Reducing Build Times in C++ Projects
One of the most frequent criticisms of the C++ language is the difficulty generated by the long compilation and link times. All of that contributes to the perceived duration of complete builds for that language.
Sadly, few people understand that build times are not just a factor of the complexity of the language or the individual tools, but also of the code organization. While C++ provides the means to reducing compilation time when necessary, project choose to adopt practices that makes it hard to achieve any speedup in compilation and linking times.
Avoiding Header Dependencies
One of the main problems affecting the speed of C++ compilation is the unnecessary inclusion of header files. C++ libraries are certainly a big culprit for these problems, because they employ the widespread tactic of including even the kitchen sink through a single header file. This is done in the name of simplicity, and it definitely makes life easier when working in small projects, but it has a negative effect on build times for large scale products.
For example, consider the infamous “windows.h” header in the Windows environment. With a single line, this include file makes a compiler request that results in processing tens of thousand lines of declarations. Many other libraries follow this misguided idea of making life “easier” with the use of an all-encompassing header file.
In a well designed library, header inclusion should be done only when needed. For example, if you are using only classes A and B, your list of include files should be limited to <a.h> and <b.h> only.
Another important tip: avoid including headers inside other other header files, unless strictly necessary. For example, if you only use pointers and references to a type, there is no need to include the header in the class declaration. It is enough to present a forward declaration of the class or struct.
Recursive header inclusion is insidious because it will affect everyone building against that header file. This generates unnecessary work for the compiler and even for the linker in the next build phase, because of the way template instantiation works.
Avoid Templates When Possible
Another common problem in modern C++ code is the overuse of templates. Templates are a great technology and has been used by C++ designers to provide features that are not natively available in the language itself. For example, C++ templates allowed library designers to create useful containers such as vectors and map, in a way that would be difficult or impossible using other techniques.
It has been found, however, that templates have a number of problems. These problems are nowadays widely recognized as affecting code modularity in programs of all sizes. First, templates provide their own compile-time language, which may slow down compilation significantly. Second, templates generate terrible error messages due to the way they were designed. Third, templates make it hard to provide separate compilation, since the compiler needs to have direct access to the definition of a template in order to generate code. Fourth, templates have the potential to unnecessarily increase the size of executables, due to the need to generate separate instantiations for each type. Fifth, generalized use of templates increases link time, because the linker has to remove copies of identical templates generated during compilation.
As we see, despite the advantages of using template libraries, there is also a lot of downsides that need to be carefully balanced. My personal view is that it is great to use the STL and other elements of the standard C++ library that use templates. After all, they are there for an important reason. They are also great for low level code that needs to run as quickly as possible.
On the other hand, most application code should be organized around classes and other object oriented concepts that do not depend on the use of templates. While templates have the potential to create very fast code, they can be difficult to reuse and extend. Object oriented code, however, may be just a little slower but it was designed with extensibility in mind. Therefore, application level constructs are much easier to handle when expressed with classes instead of templates. Additionally, there is a extensive body of knowledge about software design using object oriented concepts that is much more mature then the current techniques used for template-based software.
In summary, consider C++ templates as a technology that has advantages and pitfalls in the same way as other concepts in the language, such as pointers. Don’t use them everywhere.