title: Precompiled Header File Handling by Different Compilers tags: [xmake, lua, precompiled headers, c++ compilation acceleration, optimization compilation, cross-platform] date: 2017-07-31 author: Ruki
Recently, in order to implement precompiled header file support for xmake, I studied the mechanisms and differences of how major mainstream compilers handle precompiled headers.
Most c/c++ compilers now support precompiled headers, such as: gcc, clang, msvc, etc., to optimize c++ code compilation speed. After all, if c++ header files contain template definitions, compilation speed is very slow. If most common header files can be placed in a header.h and precompiled before other source code compilation, subsequent code can reuse this part of the precompiled header, which can greatly reduce frequent redundant header file compilation.
However, different compilers have different levels of support and handling methods for it, and it's not very universal. It took a lot of effort to encapsulate it into a unified interface and usage method in xmake.
Precompiled headers are very common in msvc projects. You often see files like stdafx.cpp, stdafx.h, which are used for this purpose. The msvc compiler generates the precompiled header file stdafx.pch by compiling stdafx.cpp.
The command line to create a precompiled header is as follows:
$ cl.exe -c -Yc -Fpstdafx.pch -Fostdafx.obj stdafx.cpp
Among them, -Yc means creating the precompiled header stdafx.pch, -Fp is used to specify the output file path of *.pch, and -Fo is used to specify the object file generated by compiling stdafx.cpp.
How do other source files use this stdafx.pch? By passing stdafx.h to -Yu to tell the compiler to compile the current code, ignore #include "stdafx.h", and directly use the already compiled stdafx.pch file.
$ cl.exe -c -Yustdafx.h -Fpstdafx.pch -Fotest.obj test.cpp
Finally, when linking, you need to link both: stdafx.obj and test.obj. This is also different from gcc and clang compilers.
$ link.exe -out:test test.obj stdafx.obj
Note: You must also link stdafx.obj. Although stdafx.cpp is only used to generate stdafx.pch, the object file is also needed.
Another difference from gcc and clang is that msvc's -Yu specifies that stdafx.h must be the header file name in #include "stdafx.h", not the file path.
I personally feel that clang's precompiled header file support is the most friendly and simplest.
Compared to msvc, it doesn't need stdafx.cpp, only a header file stdafx.h can generate a pch file.
Compared to gcc, it can flexibly control the pch file path, which is more flexible.
Compile header file to generate pch file:
$ clang -c -o stdafx.pch stdafx.h
Use precompiled header file:
$ clang -c -include stdafx.h -include-pch stdafx.pch -o test.o test.cpp
Among them, -include stdafx.h is used to ignore #include "stdafx.h" when compiling test.cpp, and use the precompiled stdafx.pch through -include-pch.
And the stdafx.h and stdafx.pch specified here can not only be files in the includedir search path, but also specify full path file names, which is very flexible, for example:
$ clang -c -include inc/stdafx.h -include-pch out/stdafx.pch -o test.o test.cpp
gcc's precompiled header handling is basically similar to clang's. The only difference is: it doesn't support the -include-pch parameter, so it cannot specify the stdafx.pch file path to use.
It has its own search rules:
stdafx.h.pch file in the directory where stdafx.h is locatedstdafx.h.pch in the -I header file search pathCompile header file to generate pch file:
$ gcc -c -o stdafx.pch stdafx.h
Use precompiled header file:
$ gcc -c -include stdafx.h -o test.o test.cpp
In order for the above code to compile normally, stdafx.h.pch must be placed in the same directory as stdafx.h, so that compilation can find it. I haven't found a method to specify the output directory yet.
For gcc and clang, compiling *.h header files by default is used as c precompiled headers, which is different from c++ pch and cannot be used by c++ code. If you want to generate c++ usable pch files, you must tell the compiler how to compile stdafx.h.
This can be solved through the -x c++-header parameter:
$ gcc -c -x c++-header -o stdafx.pch stdafx.h
Of course, it can also be solved by modifying the suffix:
$ gcc -c -o stdafx.pch stdafx.hpp
xmake supports accelerating c/c++ program compilation through precompiled header files. Currently supported compilers are: gcc, clang and msvc.
The usage for c precompiled header files is as follows:
target("test")
set_pcheader("header.h")
If it's precompilation of c++ header files, change to:
target("test")
set_pcxxheader("header.h")
For more usage instructions, see: target.set_pcheader