Using Precompiled Headers to Speed Up Linux Project Building

This tutorial shows how to use precompiled headers to speed up building of heavy Linux projects. We will create a simple project using the Boost library, will demonstrate how parsing large C++ headers slows down the build, and will then used precompiled headers to speed it up. The techniques shown here will also work for embedded (e.g. STM32) and MinGW-based projects.

  1. Start Visual Studio and open the VisualGDB Linux Project Wizard:
  2. Enter the name and location of the project you would like to create:
  3. Select “Create a new project -> Application -> MSBuild”. Precompiled headers are supported out-of-the-box for MSBuild projects and can be manually enabled for CMake-based projects:
  4. Select the Linux machine you would like to target and choose whether you want to build the project directly, or use a cross-compiler. Both options support precompiled headers:
  5. Press “Finish” to create the project. Once a basic project is created, we will update it to use the Boost library that will considerably slow down the build due to very heavy C++ header files. In order to install Boost on the target, open the SSH console for it:
  6. Then run “sudo apt-get install libboost-dev” or “sudo yum install libboost-dev” depending on the package manager you are using:
  7. If you are using a cross-compiler, you would need to synchronize the sysroot directory to make sure the cross-toolchain can find the boost headers and libraries:
  8. Boost gets installed into the regular library locations, so the default sysroot synchronization options will work:
  9. Replace the contents of the main source file with the boost asynchronous TCP server example. Then add “pthread” and “<version>” to the Additional Library Names in VS Project Properties. Note that Boost uses versioned library names, so just adding “boost_system” to Additional Library Names would not work. Instead, the full library name including the “lib” prefix and the version should be used, prefixed by a colon:
  10. Try building the project and ensure it succeeds. To simulate a larger project with multiple source files using the same headers, add another source file via Solution Explorer:
  11. Copy the #include<> directives from the main source file to the newly added file and do not add any code after them:
    #include <boost/asio.hpp>
    #include <cstdlib>
    #include <iostream>
    #include <memory>
    #include <utility>
  12. Now we will measure the exact time it takes to build the project. Open VS Project Properties -> Configuration Properties -> Local Build and set Generate a .bat file to Yes:
  13. Build the project. VisualGDB will generate a batch file with all the build commands. Add “echo %time%” between the GCC invocations to measure the exact time it takes to run gcc:
  14. Run the batch file and note the times it took for both sources to build: In this example, the original TCP server example took 7 seconds to build, while an empty source file with just the #include<> directives took another 5 seconds. If the project was larger, every source file using these header files would take at least 5 seconds to build.
  15. Precompiled headers speed up the building of large projects by first precompiling a set of commonly used header files, and then simply loading it for each compiled file. Create a new file called pch.h and copy the #include<> directives from either of the source files into it:
  16. Update both source files to include the pch.h file that, in turn, includes the actual headers:
  17. Go to VS Project Properties -> C/C++ -> Precompiled Headers and set the Precompiled Header option to “Use“. Also set the precompiled file name to pch.h:
  18. Add another source file called pch.cpp, include pch.h from it and set “Precompiled Header” to “Create” just for that file: This ensures that VisualGDB will first precompile pch.h file into a .gch file, and will then load when building the regular source files, instead of actually parsing pch.h over and over. Similarly to the regular Win32 projects, the pch.cpp file is needed because MSBuild does not build the header files directly.
  19. Build the project and open the updated batch file. Note how it now contains a line for precompiling pch.h. Add “echo %time” between the compiler invocations:
  20. The updated timing shows how precompiling the header file added extra 7.2 seconds at the beginning of the build, however the subsequent compilations of the regular source files were sped up more than 2x:The overall speedup will be greater for projects with more source files.
  21. Precompiling the headers also speed up partial rebuilds. Modifying the contents of the main source file (but not the headers included from pch.h) will not require rebuilding the precompiled header file. In this example, it translates to 3.5 seconds + linking time instead of 7.5 seconds + linking time:

If different source files in your project use different sets of header files, consider moving the most common headers into the pch.h file. Even if some of these headers are not required by every source file, precompilation may still make the overall build faster. Also because most headers contain a #pragma once directive, or an #ifdef-based header guard, you can keep the original #include<> directives in the source files and duplicate them in pch.h. As long as pch.h is included before the rest of the headers, precompilation will work as expected and redundant #include<> statements will have no effect.