C++precompiled headers and modules to reduce compilation time
C++ modules are one of the hot topics of the new C++ 20 standard, but as of today, February 2022, most compilers fail to deliver the promise in a stable, cross-platform way. Nevertheless, it is possible to take some advantage of this exciting new feature and benefit from a nice reduction in compile times, and it's even better when combined with the well-known pre-compiled headers that most C++ compilers support today.
Consider this simple program and a header-only cross-platform (Win/Linux) library:
main.cpp:
#include <iostream>
#include "sysinfo.hpp"
int main(){
std::cout << "Hostname: " << getHostName() << std::endl;
std::cout << "Free RAM (MB): " << getFreeMemory() << std::endl;
}
sysinfo.hpp:
#ifndef SYSINFO_HPP
#define SYSINFO_HPP_
#include <string>
#include <unistd.h>
#ifdef _WIN32
#include <windows.h>
#endif
inline std::string getHostName();
inline size_t getFreeMemory();
inline std::string getHostName() {
#ifdef _WIN32
TCHAR infoBuf[100];
DWORD bufCharCount = 100;
GetComputerName( infoBuf, &bufCharCount );
std::string winName(infoBuf);
return winName;
#endif
#ifdef __linux__
char hostname[100];
gethostname(hostname, 100);
std::string posixName(hostname);
return posixName;
#endif
}
inline size_t getFreeMemory() {
#ifdef _WIN32
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
return status.ullAvailPhys/1024/1024;
#endif
#ifdef __linux__
long phys_page_size = sysconf( _SC_AVPHYS_PAGES );
long page_size = sysconf( _SC_PAGESIZE );
return (phys_page_size * page_size)/1024/1024;
#endif
}
#endif /* SYSINFO_HPP_ */
_
The header sysinfo.hpp is a header-only library with some conditional compilation directives in order to compile the same file on Linux and Windows and return proper values according to the platform.
To compile and run these examples I will be using GCC 11.1 on Ubuntu Server 20.04.
Test #1: classic compile using the "time" Linux command to measure the time it took.
time g++ -O3 -std=c++20 main.cpp -o test
real 0m0.338s
user 0m0.320s
sys 0m0.018s
It took 0.338s using the "-O3" high optimization level to produce fast and efficient code. Now let's compile the header and then we will compile the main program again.
g++ -O3 -std=c++20 -c sysinfo.hpp
It will generate a (big) file named sysinfo.hpp.gch on the same directory. From now on, the compiler will use this pre-compiled header instead of the plain .hpp file, let's test it:
time g++ -O3 -std=c++20 main.cpp -o test
real 0m0.165s
user 0m0.149s
sys 0m0.016s
That's about 51% less time for compiling and building the executable. Not bad.
Recommended by LinkedIn
We will use a C++ 20 module for importing <iostream> standard library, when using G++ we must pre-compile the standard headers executing this command in the same directory we are using for our program:
g++ -O3 -std=c++20 -fmodules-ts -x c++-system-header string
g++ -O3 -std=c++20 -fmodules-ts -x c++-system-header iostream
This will create a directory named gcm.cache containing pre-compiled C++ 20 modules of these headers, now we will make some changes to the source code of main.cpp in order to import the module <iostream> instead of the plain old #include.
main.cpp:
#include "sysinfo.hpp"
import <iostream>; // <--- this is the only change
Now we will compile the main program again...
time g++ -O3 -fmodules-ts -std=c++20 main.cpp -o test
real 0m0.152s
user 0m0.137s
sys 0m0.015s
That's a 55% reduction in compile-time, combining C++ 20 modules and good old pre-compiled headers, just changing the main program a bit. If a change is made to the main program code, that is the only unit that needs to be recompiled, you can somewhat extrapolate this case to a more complex scenario, some trial & error will be necessary to obtain the best results for your particular case.
Why not go the extra mile and transform sysinfo.hpp into a modern C++ 20 module? because given the current level of C++ modules implementation by GCC 11... I would probably lose my will to live! particularly when compiling on Windows.
We are going to incorporate this building-tuning technique for our MicroServer++ platform, it's a small project in terms of complexity, but no one is going to give me back the 12 seconds of my life it takes to build. #simplicityworks
If you want to install GCC 11 on your Ubuntu 20.04, please follow this recipe we prepared and tested in order to compile our MicroServer++ on Linux:
An excellent introduction to C++ 20 modules by Daniela Engert:
Fantastic