The C++ build pipeline

DECLARATIONS AND DEFINITIONS IN three EXAMPLES

1.

2.

3.

DEclarations

Definitions

int main()
{
  sqr(3);
}

int sqr(int x)
{
  return x * x;
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int main()
{
  sqr(3);
}
main.cpp
main.cpp
int sqr(int);

int main()
{
  sqr(3);
}

int sqr(int x)
{
  return x * x;
}

HOW TO USE MULTIPLE FILES IN C++?

MULTIPLE FILES

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}

int main()
{
  sqr(3);
  cube(2);
}
main.cpp

1.

2.

HOW TO USE MULTIPLE FILES IN C++?

MULTIPLE FILES

int sqr(int);
int cube(int);

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}

int main()
{
  sqr(3);
  cube(2);
}
main.cpp

1.

2.

HOW TO USE MULTIPLE FILES IN C++?

MULTIPLE FILES

int sqr(int);
int cube(int);

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp

2.

#include "math.h"

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp

3.

int sqr(int);
int cube(int);
math.h

HOW TO USE MULTIPLE FILES IN C++?

MULTIPLE FILES

Header Files
Source Files

(DEclarations)

(Definitions)

#include "math.h"

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp
int sqr(int);
int cube(int);
math.h

HOW TO USE MULTIPLE FILES IN C++?

MULTIPLE FILES

Header Files
Source Files

(DEclarations)

(Definitions)

math.h
io.h
utility.h
error.h
net.h
log.h
math.cpp
io.cpp
utility.cpp
error.cpp
net.cpp
log.cpp

main.cpp

THE one definition rule - the reason for headers

O

R

D

#include "math.cpp"

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp

THE one definition rule - the reason for headers

O

R

D

int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp

THE one definition rule - the reason for headers

O

R

D

#include "math.cpp"

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp
int sqr(int);
int cube(int);
math.h

THE one definition rule - the reason for headers

O

R

D

#include "math.h"

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp
int sqr(int);
int cube(int);
math.h

THE one definition rule - the reason for headers

O

R

D

int sqr(int);
int cube(int);

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int x)
{
  return x * x;
}

int cube(int x)
{
  return x * x * x;
}
math.cpp
int sqr(int);
int cube(int);
math.h
int sqr(int);
int cube(int);
shapes.h

namespaces

#include "math.h"
#include "shapes.h"

int main()
{
  sqr(3);
  cube(2);
}
main.cpp
int sqr(int);
int cube(int);
math.h
int sqr(int);
int cube(int);
shapes.h
...
math.cpp
...
shapes.cpp

namespaces

#include "math.h"
#include "shapes.h"

int main()
{
  math_sqr(3);
  shapes_cube(2);
}
main.cpp
int math_sqr(int);
int math_cube(int);
math.h
int shapes_sqr(int);
int shapes_cube(int);
shapes.h
...
math.cpp
...
shapes.cpp

namespaces

#include "math.h"
#include "shapes.h"

int main()
{
  math::sqr(3);
  shapes::cube(2);
}
main.cpp
namespace math {
  int sqr(int);
  int cube(int);
}
math.h
namespace shapes {
  int sqr(int);
  int cube(int);
}
shapes.h
...
math.cpp
...
shapes.cpp

namespaces

#include "math.h"
#include "shapes.h"

int main()
{
  math::sqr(3);
  shapes::cube(2);
}
main.cpp
namespace math {
  int sqr(int);
  int cube(int);
}
math.h
namespace shapes {
  int sqr(int);
  int cube(int);
}
shapes.h
...
math.cpp
...
shapes.cpp
namespace std {
  istream cin;
  ostream cout;
  ...
}
iostream

namespaces

#include "math.h"
#include "shapes.h"
using namespace math;

int main()
{
  sqr(3);
  shapes::cube(2);
}
main.cpp
namespace math {
  int sqr(int);
  int cube(int);
}
math.h
namespace shapes {
  int sqr(int);
  int cube(int);
}
shapes.h
...
math.cpp
...
shapes.cpp
namespace std {
  istream cin;
  ostream cout;
  ...
}
iostream

namespaces

#include "math.h"
#include "shapes.h"

int main()
{
  using namespace math;
  sqr(3);
  shapes::cube(2);
}

int func(int x)
{
  math::sqr(3);
}
main.cpp
namespace math {
  int sqr(int);
  int cube(int);
}
math.h
namespace shapes {
  int sqr(int);
  int cube(int);
}
shapes.h
...
math.cpp
...
shapes.cpp
namespace std {
  istream cin;
  ostream cout;
  ...
}
iostream

The C++ build pipeline

What is

?

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}
$ ./a.out
Hello World!
$

Compiler

Linker

Assembler

Preprocessor

The C++ build pipeline

What is

?

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}
$ ./a.out
Hello World!
$

Compiler

Linker

Assembler

Preprocessor

Source
Files
Preprocessed
Code
Object

Files

Static

Libraries

Executable

File

Dynamic

Libraries

Library

Header

Files

Header
Files

HOW IS A C++ program STRUCTURED?

Source Files
Header Files

Internal

Compile-time

Runtime

Resource Files
Textures, Audio
Config Files
...
Static Libraries
Dynamic Libraries
Library Header Files

EXternal

Compile-time

Runtime

Resource Files
Textures, Audio
...

The C++ build pipeline

What is

?

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}
$ ./a.out
Hello World!
$

Compiler

Linker

Assembler

Preprocessor

Preprocessor

#ifndef HEADER_GUARD
#define HEADER_GUARD

#include <type_traits>
#include "myheader.h"

#define PI 3.1415926
#define ERROR_MSG "Exception access violation"

#define ADD(ARG1, ARG2) ((ARG1) + (ARG2))

#define STRINGIFY(ARG1) #ARG1
#define CONCAT(ARG1, ARG2) ARG1 ## ARG2
#define FWD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)

#ifdef __APPLE__
  #include "apple_specific.h"
#elif __linux__
  #include "linux_specific.h"
#elif _WIN32
  #include "windows_specific.h"
#else
  #error Unsupported platform
#endif

#line 42

#endif // HEADER_GUARD
  • Header guards
  • Includes
  • Constants
  • Compile-time computation
  • Source code transformation
  • Cross-platform compatibility
    • Platform detection
    • Conditional compilation
    • Reporting compilation errors
  • Code generation support

Preprocessor

#include <iostream>
#define SQR(x) x * x

int main()
{
  std::cout << SQR(2);
}

Preprocessor

#include <iostream>
#define SQR(x) x * x

int main()
{
  std::cout << 2 * 2;
}

Preprocessor

#include <iostream>
#define SQR(x) x * x

int main()
{
  std::cout << SQR(2 + 3);
}

Preprocessor

#include <iostream>
#define SQR(x) x * x

int main()
{
  std::cout << 2 + 3 * 2 + 3;
}

Preprocessor

#include <iostream>
#define SQR(x) x * x

int main()
{
  std::cout << 2 + 3 * 2 + 3;
  //std::cout << (2 + 3) * (2 + 3);
}

Preprocessor

#include <iostream>
#define SQR(x) ((x) * (x))

int main()
{
  std::cout << SQR(2 + 3);
}

Preprocessor

#include <iostream>
#define SQR(x) ((x) * (x))

int main()
{
  std::cout << ((2 + 3) * (2 + 3));
}

Preprocessor

#include <iostream>
#define SQR(x) ((x) * (x))

int main()
{
  int x = 3;
  std::cout << SQR(++x);
}

Preprocessor

#include <iostream>
#define SQR(x) ((x) * (x))

int main()
{
  int x = 3;
  std::cout << ((++x) * (++x));
}

Preprocessor

#include <iostream>
#define SQR(x) ((x) * (x))

int main()
{
  int x = 3;
  std::cout << ((++x) * (++x));
  //std::cout << 20;
}

Preprocessor

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}
#ifndef _GLIBCXX_IOSTREAM
#define _GLIBCXX_IOSTREAM 1

#pragma GCC system_header

#include <bits/c++config.h>
#include <ostream>
#include <istream>

namespace std
{
  extern istream cin;
  extern ostream cout;
  extern ostream cerr;
  extern ostream clog;

#ifdef _GLIBCXX_USE_WCHAR_T
  extern wistream wcin;
  extern wostream wcout;
  extern wostream wcerr;
  extern wostream wclog;
#endif

  static ios_base::Init __ioinit;
  
} // namespace std

#endif /* _GLIBCXX_IOSTREAM */

Preprocessor

#ifndef _GLIBCXX_IOSTREAM
#define _GLIBCXX_IOSTREAM 1

#pragma GCC system_header

#include <bits/c++config.h>
#include <ostream>
#include <istream>

namespace std
{
  extern istream cin;
  extern ostream cout;
  extern ostream cerr;
  extern ostream clog;

#ifdef _GLIBCXX_USE_WCHAR_T
  extern wistream wcin;
  extern wostream wcout;
  extern wostream wcerr;
  extern wostream wclog;
#endif

  static ios_base::Init __ioinit;
  
} // namespace std

#endif /* _GLIBCXX_IOSTREAM */

int main()
{
  std::cout << "Hello World!\n";
}
#ifndef _GLIBCXX_IOSTREAM
#define _GLIBCXX_IOSTREAM 1

#pragma GCC system_header

#include <bits/c++config.h>
#include <ostream>
#include <istream>

namespace std
{
  extern istream cin;
  extern ostream cout;
  extern ostream cerr;
  extern ostream clog;

#ifdef _GLIBCXX_USE_WCHAR_T
  extern wistream wcin;
  extern wostream wcout;
  extern wostream wcerr;
  extern wostream wclog;
#endif

  static ios_base::Init __ioinit;
  
} // namespace std

#endif /* _GLIBCXX_IOSTREAM */

Compiler

Preprocessor

...

int main()
{
  std::cout << "Hello World!\n";
}

Compiler

The C++ build pipeline

What is

?

...

int main()
{
  std::cout << "Hello World!\n";
}
$ ./a.out
Hello World!
$

Compiler

Linker

Assembler

Preprocessor

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}

Compiler

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}

Compiler

main:                                   # @main
        push    rax
        mov     edi, offset _ZSt4cout
        mov     esi, offset .L.str
        mov     edx, 13
        call    _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        xor     eax, eax
        pop     rcx
        ret
_GLOBAL__sub_I_example.cpp:             # @_GLOBAL__sub_I_example.cpp
        push    rax
        mov     edi, offset _ZStL8__ioinit
        call    _ZNSt8ios_base4InitC1Ev
        mov     edi, offset _ZNSt8ios_base4InitD1Ev
        mov     esi, offset _ZStL8__ioinit
        mov     edx, offset __dso_handle
        pop     rax
        jmp     __cxa_atexit                    # TAILCALL
.L.str:
        .asciz  "Hello World!\n"
#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}

Compiler

$ ./a.out
Hello World!
$
#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}

Compiler

$ ./a.out
Hello World!
$

=

=

01010111011010101010101010101010101010100100101110100000010101010101000001111101010110101010101010100001011111001010111011010101010101010101010101010100100101110100001010110101010101010100001011111001010111011010101010101010101010101010100100101110100001011010100001011111010100111000011100101110101001000011011001010111110010011101010111101001000101011110101101010101010101101010101010110111110100011110100101110000101100101011100101001110
#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}

Compiler

01010111011010101010101010101010101010100100101110100000010101010101000001111101010110101010101010100001011111001010111011010101010101010101010101010100100101110100001010110101010101010100001011111001010111011010101010101010101010101010100100101110100001011010100001011111010100111000011100101110101001000011011001010111110010011101010111101001000101011110101101010101010101101010101010110111110100011110100101110000101100101011100101001110
$ ./a.out
Hello World!
$

Compiler

01010111011010101010101010101010101010100100101110100000010101010101000001111101010110101010101010100001011111001010111011010101010101010101010101010100100101110100001010110101010101010100001011111001010111011010101010101010101010101010100100101110100001011010100001011111010100111000011100101110101001000011011001010111110010011101010111101001000101011110101101010101010101101010101010110111110100011110100101110000101100101011100101001110
ff 25 da 2f 00 00
68 01 00 00 00
e9 df 00 00 00
ff 25 d2 2f 00 00
...
main:                                   # @main
        push    rax
        mov     edi, offset _ZSt4cout
        mov     esi, offset .L.str
        mov     edx, 13
        call    _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        xor     eax, eax
        pop     rcx
        ret
_GLOBAL__sub_I_example.cpp:             # @_GLOBAL__sub_I_example.cpp
        push    rax
        mov     edi, offset _ZStL8__ioinit
        call    _ZNSt8ios_base4InitC1Ev
        mov     edi, offset _ZNSt8ios_base4InitD1Ev
        mov     esi, offset _ZStL8__ioinit
        mov     edx, offset __dso_handle
        pop     rax
        jmp     __cxa_atexit                    # TAILCALL
.L.str:
        .asciz  "Hello World!\n"
$ ./a.out
Hello World!
$

Compiler

01010111011010101010101010101010101010100100101110100000010101010101000001111101010110101010101010100001011111001010111011010101010101010101010101010100100101110100001010110101010101010100001011111001010111011010101010101010101010101010100100101110100001011010100001011111010100111000011100101110101001000011011001010111110010011101010111101001000101011110101101010101010101101010101010110111110100011110100101110000101100101011100101001110
ff 25 da 2f 00 00
68 01 00 00 00
e9 df 00 00 00
ff 25 d2 2f 00 00
...
main:                                   # @main
        push    rax
        mov     edi, offset _ZSt4cout
        mov     esi, offset .L.str
        mov     edx, 13
        call    _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        xor     eax, eax
        pop     rcx
        ret
_GLOBAL__sub_I_example.cpp:             # @_GLOBAL__sub_I_example.cpp
        push    rax
        mov     edi, offset _ZStL8__ioinit
        call    _ZNSt8ios_base4InitC1Ev
        mov     edi, offset _ZNSt8ios_base4InitD1Ev
        mov     esi, offset _ZStL8__ioinit
        mov     edx, offset __dso_handle
        pop     rax
        jmp     __cxa_atexit                    # TAILCALL
.L.str:
        .asciz  "Hello World!\n"
#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}

Assembler

$ ./a.out
Hello World!
$

Compiler

01010111011010101010101010101010101010100100101110100000010101010101000001111101010110101010101010100001011111001010111011010101010101010101010101010100100101110100001010110101010101010100001011111001010111011010101010101010101010101010100100101110100001011010100001011111010100111000011100101110101001000011011001010111110010011101010111101001000101011110101101010101010101101010101010110111110100011110100101110000101100101011100101001110
ff 25 da 2f 00 00
68 01 00 00 00
e9 df 00 00 00
ff 25 d2 2f 00 00
...
main:                                   # @main
        push    rax
        mov     edi, offset _ZSt4cout
        mov     esi, offset .L.str
        mov     edx, 13
        call    _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        xor     eax, eax
        pop     rcx
        ret
_GLOBAL__sub_I_example.cpp:             # @_GLOBAL__sub_I_example.cpp
        push    rax
        mov     edi, offset _ZStL8__ioinit
        call    _ZNSt8ios_base4InitC1Ev
        mov     edi, offset _ZNSt8ios_base4InitD1Ev
        mov     esi, offset _ZStL8__ioinit
        mov     edx, offset __dso_handle
        pop     rax
        jmp     __cxa_atexit                    # TAILCALL
.L.str:
        .asciz  "Hello World!\n"
#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}

Assembler

Linker

Compiler

01010111011010101010101010101010101010100100101110100000010101010101000001111101010110101010101010100001011111001010111011010101010101010101010101010100100101110100001010110101010101010100001011111001010111011010101010101010101010101010100100101110100001011010100001011111010100111000011100101110101001000011011001010111110010011101010111101001000101011110101101010101010101101010101010110111110100011110100101110000101100101011100101001110
ff 25 da 2f 00 00
68 01 00 00 00
e9 df 00 00 00
ff 25 d2 2f 00 00
...
main:                                   # @main
        push    rax
        mov     edi, offset _ZSt4cout
        mov     esi, offset .L.str
        mov     edx, 13
        call    _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        xor     eax, eax
        pop     rcx
        ret
_GLOBAL__sub_I_example.cpp:             # @_GLOBAL__sub_I_example.cpp
        push    rax
        mov     edi, offset _ZStL8__ioinit
        call    _ZNSt8ios_base4InitC1Ev
        mov     edi, offset _ZNSt8ios_base4InitD1Ev
        mov     esi, offset _ZStL8__ioinit
        mov     edx, offset __dso_handle
        pop     rax
        jmp     __cxa_atexit                    # TAILCALL
.L.str:
        .asciz  "Hello World!\n"
#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}

Assembler

Linker

The C++ build pipeline

What is

?

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}
$ ./a.out
Hello World!
$

Compiler

Linker

Assembler

Preprocessor

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}
 

Linker

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}
$ ./a.out
Hello World!
$

Linker

The C++ build pipeline

#include <iostream>

int main()
{
  std::cout << "Hello World!\n";
}
$ ./a.out
Hello World!
$

Compiler

Linker

Assembler

Preprocessor

Source
Files
Preprocessed
Code
Object

Files

Static

Libraries

Executable

File

Dynamic

Libraries

Library

Header

Files

Header
Files

The C++ Build Pipeline

By Jan Bielak

The C++ Build Pipeline

A presentation about the C++ build pipeline. It is presented here: https://www.youtube.com/watch?v=Ev8DrjtBtNg .

  • 546