I have 100 .h files in a externalFiles diretory. Around 10 .cpp files in my source includes these .h files.
So I removed all #include externalFiles/.*h directives from my .cpp files and wrote them in a pch.h header that I include via Cmake's target_precompile_headers(${PROJECT_NAME} PRIVATE pch.h).
I checked my build times using precompiled headers via Cmake vs simply including pch.h in my .cpp files. I noted build times using:
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time") and
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CMAKE_COMMAND} -E time")
Build time using precompiled headers
[1/2] Building CXX object CMakeFiles/AlgoCoding.dir/main.cpp.obj
Elapsed time: 11 s. (time), 11.413 s. (clock)
[2/2] Linking CXX executable AlgoCoding.exe
Elapsed time: 54 s. (time), 53.459 s. (clock)
Build time just including headers
[1/2] Building CXX object CMakeFiles/AlgoCoding.dir/main.cpp.obj
Elapsed time: 14 s. (time), 13.35 s. (clock)
[2/2] Linking CXX executable AlgoCoding.exe
Elapsed time: 28 s. (time), 28.109 s. (clock)
Conlusion
From these times it seems like using precompiled headers does reduce build time for the .obj creation of the .cpp file modified (main.cpp) but it increases the link time heavily.
Is this the case for everyone or am I doing something wrong here?
EDIT: 1
Experiment #2 to test Build times of precompiling headers.
I tried to include spdlog library(a header only library containing 100 .h files) into my bare-bones Cmake project (just a main.cpp logging 1 line into a file). Two methods of doing this.
target_precompile_headers(${PROJECT_NAME} PRIVATE pch.h))Build Time Results
----Method 1
[1/2] Building CXX object CMakeFiles/test.dir/main.cpp.obj
Elapsed time: 22 s. (time), 21.904 s. (clock)
[2/2] Linking CXX executable test.exe
Elapsed time: 18 s. (time), 18.311 s. (clock)
----Method 2
[1/2] Building CXX object CMakeFiles/test.dir/main.cpp.obj
Elapsed time: 18 s. (time), 18.231 s. (clock)
[2/2] Linking CXX executable test.exe
Elapsed time: 22 s. (time), 21.604 s. (clock)
Conclusion
Precompiling external headers in a barebones project still gives same total build time as just using #include directive. When using precompiled headers, the small time decrease in Building .obj file is compensated by increased time Linking CXX executable.
Is there something different I need to do to reduce build time when precompiling external .h files? Or is this the expected behaviour?
As suggested by @HolyBlackCat I tried the same compilation with clang + LLD linker. The Build times have definately improved for both normal #include of header files and precompiled headers (~100 .h files):
-------Method 1(normal #include)
[1/2] Building CXX object CMakeFiles/test.dir/main.cpp.obj
Elapsed time: 7 s. (time), 6.997 s. (clock)
[2/2] Linking CXX executable test.exe
Elapsed time: 9 s. (time), 9.493 s. (clock)
-------Method 2(precompiled headers)
[1/2] Building CXX object CMakeFiles/test.dir/main.cpp.obj
Elapsed time: 5 s. (time), 4.515 s. (clock)
[2/2] Linking CXX executable test.exe
Elapsed time: 9 s. (time), 9.076 s. (clock)
From these results, Clang+LLD performs significantly faster than gcc+LD/gold. Moreover, precompiled headers manages to reduce overall build time when used with Clang+LLD, as it reduces build time of .obj files but manages to acheive similar linking time. (See question Edit 1, for build times of gcc+default Linker)
Additionally, @Marco van de Voort mentioned to check how scaling the number of .obj/.cpp files using the precompiled headers affected the build times. So for Method 2(precomiled headers) I compiled with 3 .cpp files (Scaling 3) and 5 .cpp files (Scaling 5). Here are the results:
-----Method 2 Scaling 3 .cpp
Building all 3 CXX
Elapsed time: 7 s. (time), 6.767 s. (clock)
[4/4] Linking CXX executable test.exe
Elapsed time: 27 s. (time), 27.404 s. (clock)
-----Method 2 Scaling 5 .cpp
Building all 5 CXX object
Elapsed time: 11 s. (time), 11.416 s. (clock)
[6/6] Linking CXX executable test.exe
Elapsed time: 47 s. (time), 46.942 s. (clock)
We can see the time increase in Linking is linear ~(9 * #cpp files to link to). For Method 1 scaling gives worse results.
Although precompiled headers give better build times when used with Clang+LLD, its better to use Method 3. Find a library version(.lib/.dll) of the header only library you are trying to use. This library is statically/dynamically linked and the Build times are much faster this way.
Method 3: Using spdlog library in Cmake (installed via vcpkg):
set(CMAKE_PREFIX_PATH "<PathToVcpkg>\\installed\\x64-mingw-static") # THIS HAS TO COME BEFORE THE PROJECT LINE
project(test)
find_package(spdlog REQUIRED);
add_executable(${PROJECT_NAME} ${project-targets})
target_link_libraries(${PROJECT_NAME} PRIVATE spdlog::spdlog )
Significantly improved build times of using .lib library version (with PCH includes) compared to using header only libraries (with PCH includes):
-----Method 3 Scaling 1 .cpp
[1/2] Building CXX object CMakeFiles/test.dir/main.cpp.obj
Elapsed time: 2 s. (time), 2.073 s. (clock) [2/2] Linking CXX executable test.exe
Elapsed time: 10 s. (time), 10.294 s. (clock)
-----Method 3 Scaling 5 .cpp
[5/6] Building CXX object CMakeFiles/test.dir/main2.cpp.obj
Elapsed time: 2 s. (time), 2.244 s. (clock) [6/6] Linking CXX executable test.exe
Elapsed time: 12 s. (time), 12.024 s. (clock)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With