最近为了给xmake实现预编译头文件的支持,研究了下各大主流编译器处理预编译头的机制以及之间的一些差别。c++
如今的大部分c/c++编译器都是支持预编译头的,例如:gcc,clang,msvc等,用于优化c++代码的编译速度,毕竟c++的头文件若是包含了模板定义的话,编译速度是很慢的,
若是可以吧大部分通用的头文件放置在一个header.h
中,在其余源码编译以前预先对其进行编译,以后的代码都能重用这部分预编译头,就能够极大程度上减小频繁的头文件冗余编译。bash
可是不一样编译器对它的支持力度和处理方式,仍是有很大差别的,并非很是通用,在xmake中封装成统一的接口和使用方式,仍是费了很大的功夫才搞定。优化
预编译头在msvc的项目中很常见,常常会看到相似stdafx.cpp
, stdafx.h
的文件,就是用于此目的,而msvc编译器是经过编译stdafx.cpp
来生成预编译头文件stdafx.pch
的。lua
建立预编译头的命令行以下:插件
$ cl.exe -c -Yc -Fpstdafx.pch -Fostdafx.obj stdafx.cpp
其中,-Yc
就是建立预编译头stdafx.pch
的意思,经过-Fp
来指定*.pch
的输出文件路径,用-Fo
指定编译stdafx.cpp
生成对象文件。命令行
其余源码是如何使用这个stdafx.pch
的呢,经过将stdafx.h
传入-Yu
来告诉编译器,编译当前代码,忽略#include "stdafx.h"
,直接使用已经编译好的stdafx.pch
文件。code
$ cl.exe -c -Yustdafx.h -Fpstdafx.pch -Fotest.obj test.cpp
最后连接的时候,须要把:stdafx.obj
, test.obj
都链接上才行,这个也是和gcc, clang编译器不一样的地方。对象
$ link.exe -out:test test.obj stdafx.obj
注:必定要吧stdafx.obj
也连接上哦,虽然stdafx.cpp
仅用于生成stdafx.pch
,可是对象文件也是须要。接口
还有个跟gcc, clang有区别的地方是,msvc的-Yu
指定stdafx.h
必须是#include "stdafx.h"
中的头文件名字,不是文件路径哦。get
我的感受clang的预编译头文件支持方式最为友好,也最为简单。
相比于msvc,不须要stdafx.cpp
,只须要一个头文件stdafx.h
就能够生成pch文件。
相比于gcc,能够灵活控制pch文件的路径,更加灵活。
编译头文件生成pch文件:
$ clang -c -o stdafx.pch stdafx.h
使用预编译头文件:
$ clang -c -include stdafx.h -include-pch stdafx.pch -o test.o test.cpp
其中-include stdafx.h
用于忽略编译test.cpp
中的#include "stdafx.h"
,经过-include-pch
使用预先编译好的stdafx.pch
。
而且这里指定的stdafx.h
和stdafx.pch
不只能够是在includedir搜索路径下的文件,也能够指定全路径文件名,很是灵活,例如:
$ clang -c -include inc/stdafx.h -include-pch out/stdafx.pch -o test.o test.cpp
gcc的预编译头处理方式基本上跟clang的相似,惟一的区别就是:它不支持-include-pch
参数,所以不能因此指定使用的stdafx.pch
文件路径。
它有本身的搜索规则:
stdafx.h
所在目录中,查找stdafx.h.pch
文件是否存在-I
的头文件搜索路径找查找stdafx.h.pch
编译头文件生成pch文件:
$ gcc -c -o stdafx.pch stdafx.h
使用预编译头文件:
$ gcc -c -include stdafx.h -o test.o test.cpp
为了让上述代码正常编译,stdafx.h.pch
必须放置在stdafx.h
的相同目录下,这样编译才能找到,目前我尚未找到能够因此指定输出目录的方法。
gcc、clang对于*.h
的头文件编译,默认是做为c预编译头来使用的,这跟c++的pch是不同的,没法给c++的代码使用,若是要生成c++可用的pch文件,必需要告诉编译器,如何去编译stdafx.h
。
这个能够经过-x c++-header
参数来解决:
$ gcc -c -x c++-header -o stdafx.pch stdafx.h
固然也能够经过修改后缀名来解决:
$ gcc -c -o stdafx.pch stdafx.hpp
xmake支持经过预编译头文件去加速c/c++
程序编译,目前支持的编译器有:gcc, clang和msvc。
使用方式以下:
target("test") set_precompiled_header("header.h")
一般状况下,设置c头文件的预编译,这须要加上这个配置便可,若是是对c++头文件的预编译,改为:
target("test") set_precompiled_header("header.hpp")
其中的参数指定的是须要预编译的头文件路径,相对于当前xmake.lua
所在的目录。
若是只是调用xmake命令行进行直接编译,那么上面的设置足够了,而且已经对各个编译器进行支持,可是有些状况下,上面的设置还不能知足需求:
xmake project
工程插件生成vs工程文件,那么还缺乏一个相似stdafx.cpp
的文件(上面的设置在msvc编译的时候会自动生成一个临时的,可是对IDE工程不友好)。header.h
想做为c++的预编译头文件就不支持了,除非改为header.hpp
(默认会当作c头文件进行预编译)。所以为了更加地通用跨平台,能够在工程里面建立一个相似vc中stdafx.cpp
的源文件:header.cpp
。
target("test") set_precompiled_header("header.h", "header.cpp")
header.cpp
的内容以下:
#include "header.h"
上面的设置,就能够很好地处理各类状况下的预编译处理,追加的header.cpp
也告诉了xmake:header.h
是做为c++来预编译的。
相对于经典的vc工程中的stdafx.cpp
和stdafx.h
,也能完美支持:
target("test") set_precompiled_header("stdafx.h", "stdafx.cpp")
更多使用说明见:target.set_precompiled_header