cmc/cleberg.net

My personal web garden & blog.

clone: git clone https://gitbay.org/cmc/cleberg.net.git

main: content/blog/2018-11-28-cpp-compiler.org · raw

  1#+date:        [2018-11-28 Wed 00:00:00]
  2#+title:       The C++ Compiler
  3#+description: A brief trip into the C++ compilation process.
  4#+slug:        cpp-compiler
  5#+filetags:    :linux:
  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
 12A developer must compile source code, such as the example shown in the snippet
 13below, before they can execute the compiled program. There are numerous steps
 14and intricacies to the compilation process, and this post was a personal
 15exercise to learn and remember as much information as I can.
 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, a Northern Illinois
 41University (NIU) professor, to see the graphic and an explanation. The goal of
 42the compilation process is to take the C++ code and produce a shared library,
 43dynamic library, or an executable file.
 44
 45** Compilation Phases
 46
 47Let's break down the compilation process. There are four major steps to
 48compiling C++ code.
 49
 50*** Step 1
 51
 52The first step is to expand the source code file to meet all dependencies. The
 53C++ preprocessor includes the code from all the header files, such as =#include
 54<iostream>=. Now, what does that mean? The previous example includes the
 55=iostream= header. This tells the computer that you want to use the =iostream=
 56standard library, which contains classes and functions written in the core
 57language. This specific header allows you to manipulate input/output streams.
 58After all this, you'll end up with a temporary file that contains the expanded
 59source code.
 60
 61In the example of the C++ code above, the =iostream= class would be included in
 62the expanded code.
 63
 64*** Step 2
 65
 66After the compiler expands the code, the compiler comes into play. The compiler
 67takes the C++ code and converts this code into the assembly language, understood
 68by the platform. You can see this in action if you head over to the [[https://godbolt.org][GodBolt
 69Compiler Explorer]], which shows the compiler converting C++ into assembly
 70dynamically.
 71
 72For example, the =Hello, world!= code snippet above compiles into the following
 73assembly code:
 74
 75#+begin_src asm
 76.LC0:
 77        .string "Hello, world!\n"
 78main:
 79        push    rbp
 80        mov     rbp, rsp
 81        mov     esi, OFFSET FLAT:.LC0
 82        mov     edi, OFFSET FLAT:_ZSt4cout
 83        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*)
 84        mov     eax, 0
 85        pop     rbp
 86        ret
 87__static_initialization_and_destruction_0(int, int):
 88        push    rbp
 89        mov     rbp, rsp
 90        sub     rsp, 16
 91        mov     DWORD PTR [rbp-4], edi
 92        mov     DWORD PTR [rbp-8], esi
 93        cmp     DWORD PTR [rbp-4], 1
 94        jne     .L5
 95        cmp     DWORD PTR [rbp-8], 65535
 96        jne     .L5
 97        mov     edi, OFFSET FLAT:_ZStL8__ioinit
 98        call    std::ios_base::Init::Init() [complete object constructor]
 99        mov     edx, OFFSET FLAT:__dso_handle
100        mov     esi, OFFSET FLAT:_ZStL8__ioinit
101        mov     edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
102        call    __cxa_atexit
103.L5:
104        nop
105        leave
106        ret
107_GLOBAL__sub_I_main:
108        push    rbp
109        mov     rbp, rsp
110        mov     esi, 65535
111        mov     edi, 1
112        call    __static_initialization_and_destruction_0(int, int)
113        pop     rbp
114        ret
115#+end_src
116
117*** Step 3
118
119Third, the compiler assembles the assembly code into the object code for the
120platform. Essentially, this is when the compiler takes the assembly code and
121assembles it into machine code in a binary format. After researching this
122online, I figured out that a lot of compilers will allow you to stop compilation
123at this step. This would be useful for compiling each source code file
124separately. This saves time later if a single file changes, since the developer
125will only need to re-compile a single file.
126
127*** Step 4
128
129Finally, the compiler links the object code file generated by the assembler
130together with the object code files for any library functions used to produce a
131shared library, dynamic library, or an executable file. It replaces all
132references to undefined symbols with the correct addresses.