Speeding up the Build of C and C++ Projects
Many programmers know firsthand that C and C++ program builds very long. Someone solves this problem by sword-fighting at build time, someone is going to the kitchen to "grab some coffee". This article is for those who are tired of this, and who decided it is time to do something about it. In this article, various ways of speeding up compilation time of a project are regarded, as well as treatment of a disease "fixed one header - a half of a project was rebuilt."
Before we start, let's find out/recall the main phases of the translation of C/C++ code into an executable program.
According to p. 188.8.131.52 (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf) of the draft N1548 "Programming languages — C" and p.5.2 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf) N4659 "Working Draft, Standard for Programming Language C++"(published versions of the standards can be purchased here (https://www.iso.org/standard/57853.html) and here (https://www.iso.org/standard/68564.html), 8 and 9 translation phases are defined respectively. Let's leave out the details and consider the translating process in the abstract:
- Phase I - the source file arrives at the input preprocessor. Preprocessor makes content substitution of the specified in the #include files and expands macros. It corresponds to the phases 1 - 4 of the C11 and C++17 drafts.
- Phase II - the preprocessed file arrives at the compiler and gets converted to an object file. It corresponds to the phases 5 - 7 of the C11 draft and 5 - 8 of the C++17 draft.
- Phase III - a linker links object files and provides static libraries, forming an executable program. It corresponds to the phases 8 - 9 of the C11 and C++17 drafts respectively.
The program is compound of translation units (*.c, *.cc, *.cpp, *.cxx), each is self-sufficient and can be preproccessed/compiled independently from the other. It also follows that each translation unit has no information about the other units. If the two units have to exchange any information (such as a function), this is solved by linking by name: the external entity is declared with the keyword extern, and at the phase III the linker links them. A simple example:
int64_t abs(int64_t num)
return num >= 0 ? num : -num;
extern int64_t abs(int64_t num);
To simplify the harmonization of different translation units, a header files mechanism was figured out, which is a declaration of clear interface. Subsequently, each translation unit in case of need includes the header file through the #include preprocessor directive.
Next, let's look at how you can speed up the build at different phases. In addition to the principle itself, it will also be helpful to describe how to implement this or that way in the build system. The examples will be given to the following build systems: MSBuild, Make, CMake.
Read more - https://www.viva64.com/en/b/0549/
|Vote for this post
Bring it to the Main Page