content/blog/2018-11-28-cpp-compiler.org
130 lines · 5323 bytes
1#+date: <2018-11-28 Wed 00:00:00>
2#+title: C++ Compilation Process: Stepwise Transformation from Source to Executable
3#+description: Systematic presentation of the C++ compilation phases including preprocessing, compilation, assembly, and linking, with technical insights into each stage’s function.
4#+slug: cpp-compiler
5#+filetags: :cpp:compilation:programming:
6
7* A Brief Introduction
8
9[[https://en.wikipedia.org/wiki/C%2B%2B][C++]] is a general-purpose programming language with object-oriented, generic, and
10functional features in addition to facilities for low-level memory manipulation.
11
12The source code, shown in the snippet below, must be compiled before it can be
13executed. There are many steps and intricacies to the compilation process, and
14this post was a personal exercise to learn and remember as much information as I
15can.
16
17#+begin_src cpp
18#include <iostream>
19
20int main()
21{
22 std::cout << "Hello, world!\n";
23}
24#+end_src
25
26** Compilation Process
27
28*** An Overview
29
30Compiling C++ projects is a frustrating task most days. Seemingly nonexistent
31errors keeping your program from successfully compiling can be annoying
32(especially since you know you wrote it perfectly the first time, right?).
33
34I'm learning more and more about C++ these days and decided to write this
35concept down so that I can cement it even further in my own head. However, C++
36is not the only compiled language. Check out [[https://en.wikipedia.org/wiki/Compiled_language][the Wikipedia entry for compiled
37languages]] for more examples of compiled languages.
38
39I'll start with a wonderful, graphical way to conceptualize the C++ compiler.
40View [[https://web.archive.org/web/20190419035048/http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/compile.html][The C++ Compilation Process]] by Kurt MacMahon, an NIU professor, to see the
41graphic and an explanation. The goal of the compilation process is to take the
42C++ code and produce a shared library, dynamic library, or an executable file.
43
44** Compilation Phases
45
46Let's break down the compilation process. There are four major steps to
47compiling C++ code.
48
49*** Step 1
50
51The first step is to expand the source code file to meet all dependencies. The
52C++ preprocessor includes the code from all the header files, such as =#include
53<iostream>=. Now, what does that mean? The previous example includes the
54=iostream= header. This tells the computer that you want to use the =iostream=
55standard library, which contains classes and functions written in the core
56language. This specific header allows you to manipulate input/output streams.
57After all this, you'll end up which a temporary file that contains the expanded
58source code.
59
60In the example of the C++ code above, the =iostream= class would be included in
61the expanded code.
62
63*** Step 2
64
65After the code is expanded, the compiler comes into play. The compiler takes the
66C++ code and converts this code into the assembly language, understood by the
67platform. You can see this in action if you head over to the [[https://godbolt.org][GodBolt Compiler
68Explorer]], which shows C++ being converted into assembly dynamically.
69
70For example, the =Hello, world!= code snippet above compiles into the following
71assembly code:
72
73#+begin_src asm
74.LC0:
75 .string "Hello, world!\n"
76main:
77 push rbp
78 mov rbp, rsp
79 mov esi, OFFSET FLAT:.LC0
80 mov edi, OFFSET FLAT:_ZSt4cout
81 call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
82 mov eax, 0
83 pop rbp
84 ret
85__static_initialization_and_destruction_0(int, int):
86 push rbp
87 mov rbp, rsp
88 sub rsp, 16
89 mov DWORD PTR [rbp-4], edi
90 mov DWORD PTR [rbp-8], esi
91 cmp DWORD PTR [rbp-4], 1
92 jne .L5
93 cmp DWORD PTR [rbp-8], 65535
94 jne .L5
95 mov edi, OFFSET FLAT:_ZStL8__ioinit
96 call std::ios_base::Init::Init() [complete object constructor]
97 mov edx, OFFSET FLAT:__dso_handle
98 mov esi, OFFSET FLAT:_ZStL8__ioinit
99 mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
100 call __cxa_atexit
101.L5:
102 nop
103 leave
104 ret
105_GLOBAL__sub_I_main:
106 push rbp
107 mov rbp, rsp
108 mov esi, 65535
109 mov edi, 1
110 call __static_initialization_and_destruction_0(int, int)
111 pop rbp
112 ret
113#+end_src
114
115*** Step 3
116
117Third, the assembly code generated by the compiler is assembled into the object
118code for the platform. Essentially, this is when the compiler takes the assembly
119code and assembles it into machine code in a binary format. After researching
120this online, I figured out that a lot of compilers will allow you to stop
121compilation at this step. This would be useful for compiling each source code
122file separately. This saves time later if a single file changes; only that file
123needs to be recompiled.
124
125*** Step 4
126
127Finally, the object code file generated by the assembler is linked together with
128the object code files for any library functions used to produce a shared
129library, dynamic library, or an executable file. It replaces all references to
130undefined symbols with the correct addresses.