使用CMake的预编译头文件
我曾经在网上看过一些关于CMake中预编译头文件的支持。 他们都显得有点全面,每个人都有自己的做法。 目前做什么是最好的方法?
有一个名为“Cotire”的第三方CMake模块 ,可以自动为基于CMake的构build系统使用预编译头文件,并支持统一构build。
我使用下面的macros来生成和使用预编译头文件:
MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar) IF(MSVC) GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE) SET(PrecompiledBinary "${CMAKE_CURRENT_BINARY_DIR}/${PrecompiledBasename}.pch") SET(Sources ${${SourcesVar}}) SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource} PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\"" OBJECT_OUTPUTS "${PrecompiledBinary}") SET_SOURCE_FILES_PROPERTIES(${Sources} PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\"" OBJECT_DEPENDS "${PrecompiledBinary}") # Add precompiled header to SourcesVar LIST(APPEND ${SourcesVar} ${PrecompiledSource}) ENDIF(MSVC) ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)
比方说,你有一个variables$ {MySources}与你所有的源文件,你想要使用的代码将是简单的
ADD_MSVC_PRECOMPILED_HEADER("precompiled.h" "precompiled.cpp" MySources) ADD_LIBRARY(MyLibrary ${MySources})
代码在非MSVC平台上仍然可以正常工作。 很简约 :)
这是一个代码片段,允许您为项目使用预编译头。 将以下内容添加到您的CMakeLists.txt中,根据需要replacemyprecompiledheaders
和myproject_SOURCE_FILES
:
if (MSVC) set_source_files_properties(myprecompiledheaders.cpp PROPERTIES COMPILE_FLAGS "/Ycmyprecompiledheaders.h" ) foreach( src_file ${myproject_SOURCE_FILES} ) set_source_files_properties( ${src_file} PROPERTIES COMPILE_FLAGS "/Yumyprecompiledheaders.h" ) endforeach( src_file ${myproject_SOURCE_FILES} ) list(APPEND myproject_SOURCE_FILES myprecompiledheaders.cpp) endif (MSVC)
我最终使用了larsmmacros的改编版本。 使用$(IntDir)为pchpath保留预编译的头文件,以便debugging和发布版本分开。
MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar) IF(MSVC) GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE) SET(PrecompiledBinary "$(IntDir)/${PrecompiledBasename}.pch") SET(Sources ${${SourcesVar}}) SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource} PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\"" OBJECT_OUTPUTS "${PrecompiledBinary}") SET_SOURCE_FILES_PROPERTIES(${Sources} PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\"" OBJECT_DEPENDS "${PrecompiledBinary}") # Add precompiled header to SourcesVar LIST(APPEND ${SourcesVar} ${PrecompiledSource}) ENDIF(MSVC) ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER) ADD_MSVC_PRECOMPILED_HEADER("stdafx.h" "stdafx.cpp" MY_SRCS) ADD_EXECUTABLE(MyApp ${MY_SRCS})
改编自Dave,但效率更高(设置目标属性,而不是每个文件):
if (MSVC) set_target_properties(abc PROPERTIES COMPILE_FLAGS "/Yustd.h") set_source_files_properties(std.cpp PROPERTIES COMPILE_FLAGS "/Ycstd.h") endif(MSVC)
恕我直言,最好的办法是为整个项目设置PCH,正如martjno所build议的,如果需要的话,还可以忽略某些来源的PCH(例如生成的来源)的能力:
# set PCH for VS project function(SET_TARGET_PRECOMPILED_HEADER Target PrecompiledHeader PrecompiledSource) if(MSVC) SET_TARGET_PROPERTIES(${Target} PROPERTIES COMPILE_FLAGS "/Yu${PrecompiledHeader}") set_source_files_properties(${PrecompiledSource} PROPERTIES COMPILE_FLAGS "/Yc${PrecompiledHeader}") endif(MSVC) endfunction(SET_TARGET_PRECOMPILED_HEADER) # ignore PCH for a specified list of files function(IGNORE_PRECOMPILED_HEADER SourcesVar) if(MSVC) set_source_files_properties(${${SourcesVar}} PROPERTIES COMPILE_FLAGS "/Y-") endif(MSVC) endfunction(IGNORE_PRECOMPILED_HEADER)
因此,如果您有一些目标MY_TARGET,并且生成的源IGNORE_PCH_SRC_LIST列表,您只需执行以下操作:
SET_TARGET_PRECOMPILED_HEADER(MY_TARGET stdafx.h stdafx.cpp) IGNORE_PRECOMPILED_HEADER(IGNORE_PCH_SRC_LIST)
这个aproach经过testing和完美的作品。
使用cmake和Visual Studio 2015的预编译头的示例
“stdafx.h”,“stdafx.cpp” – 预编译头名称。
将下面的内容放在root cmake文件中。
if (MSVC) # For precompiled header. # Set # "Precompiled Header" to "Use (/Yu)" # "Precompiled Header File" to "stdafx.h" set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Yustdafx.h /FIstdafx.h") endif()
将下面的内容放在项目cmake文件中。
“src” – 一个包含源文件的文件夹。
set_source_files_properties(src/stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h" )
如果你不想重新发明轮子,只要使用Cotire作为最好的答案build议或者更简单的一个 – cmake-precompiled-header 。 要使用它只包括模块和调用:
include( cmake-precompiled-header/PrecompiledHeader.cmake ) add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )
那么当每次在任何项目文件中更改一行代码时,在四核机器上编译需要10分钟以上的时间,这会告诉您何时为Windows添加预编译头文件。 在* nux我只会使用ccache而不用担心这一点。
我已经在我的主应用程序和一些它使用的库中实现了。 这对于这一点非常有用。 还有一件事情是需要的,你必须创buildpch源文件和头文件,并在源文件中包含所有你想要预编译的头文件。 我用MFC做了12年,但花了我几分钟时间才回忆起来。
最简洁的方法是将预编译选项添加为全局选项。 在vcxproj文件中,这将显示为<PrecompiledHeader>Use</PrecompiledHeader>
而不是为每个单独的文件执行此操作。
然后,您需要将Create
选项添加到StdAfx.cpp。 以下是我如何使用它:
MACRO(ADD_MSVC_PRECOMPILED_HEADER SourcesVar) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /YuStdAfx.h") set_source_files_properties(StdAfx.cpp PROPERTIES COMPILE_FLAGS "/YcStdAfx.h" ) list(APPEND ${${SourcesVar}} StdAfx.cpp) ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER) file(GLOB_RECURSE MYDLL_SRC "*.h" "*.cpp" "*.rc") ADD_MSVC_PRECOMPILED_HEADER(MYDLL_SRC) add_library(MyDll SHARED ${MYDLL_SRC})
这是testing和MSVC 2010的作品,将创build一个MyDll.pch文件,我不打扰什么文件名被使用,所以我没有做任何努力,指定它。
由于预编译头文件选项不适用于rc文件,我需要调整由jari提供的macros。
####################################################################### # Makro for precompiled header ####################################################################### MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar) IF(MSVC) GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE) SET(PrecompiledBinary "$(IntDir)/${PrecompiledBasename}.pch") SET(Sources ${${SourcesVar}}) # generate the precompiled header SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource} PROPERTIES COMPILE_FLAGS "/Zm500 /Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\"" OBJECT_OUTPUTS "${PrecompiledBinary}") # set the usage of this header only to the other files than rc FOREACH(fname ${Sources}) IF ( NOT ${fname} MATCHES ".*rc$" ) SET_SOURCE_FILES_PROPERTIES(${fname} PROPERTIES COMPILE_FLAGS "/Zm500 /Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\"" OBJECT_DEPENDS "${PrecompiledBinary}") ENDIF( NOT ${fname} MATCHES ".*rc$" ) ENDFOREACH(fname) # Add precompiled header to SourcesVar LIST(APPEND ${SourcesVar} ${PrecompiledSource}) ENDIF(MSVC) ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)
编辑:这个预编译头的使用减less了我的主要项目的总体构build时间从4分30秒降低到1分40秒。 这对我来说是一件非常好的事情。 在预编译头文件只有像boost / stl / Windows / mfc的头文件。
甚至不要去那里。 预编译头文件意味着只要其中一个头文件发生变化,就必须重新编译所有的东西 。 如果你有一个能够实现这一点的构build系统,那么你很幸运。 更经常的是,你的构build会失败,直到你意识到你改变了正在编译的东西,因此你需要做一个完整的重build。 你可以避免这种情况,通过预编译头文件,你绝对肯定不会改变,但是你也放弃了很大一部分的速度增益。
另一个问题是你的名字空间被许多你不知道或者关心的符号在你使用预编译头文件的地方弄脏了。