在CMake中使用预编译的头文件
我在网上看到一些(旧的)帖子,内容涉及一起破解CMake中对预编译标头的一些支持。他们似乎遍地都是,每个人都有自己的做事方式。目前最好的方法是什么?
解决方案
甚至不要去那里。预编译的头文件意味着,只要其中一个头文件发生更改,就必须重新构建所有内容。如果我们拥有能够实现这一目标的构建系统,那么我们将很幸运。通常,构建会失败,直到我们意识到自己更改了预编译的内容,因此我们需要进行全面的重建。我们可以通过预编译绝对肯定不会改变的标头来避免这种情况,但同时我们也会放弃很大一部分速度增益。
另一个问题是,在许多使用预编译标头的地方,命名空间会被我们不知道或者不关心的各种符号污染。
这是一个代码段,可让我们为项目使用预编译的标头。
将以下内容添加到CMakeLists.txt中,酌情替换为myprecompiledheaders和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)
好了,每当我们在任何项目文件中更改一行时,在四核计算机上进行构建都需要10分钟以上的时间,它就会告诉我们添加Windows预编译头文件的时间。在* nux上,我只使用ccache而不用担心。
我已经在我的主应用程序及其使用的一些库中实现了。到目前为止,它的工作原理非常好。还需要做的一件事是,我们必须创建pch源文件和头文件,并且在源文件中包括要预编译的所有头文件。我在MFC上做了12年,但是花了我几分钟的时间来回忆。
我正在使用以下宏来生成和使用预编译的标头:
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)
假设我们在所有源文件中都有一个变量$ {MySources},那么我们想要使用的代码就是
ADD_MSVC_PRECOMPILED_HEADER("precompiled.h" "precompiled.cpp" MySources) ADD_LIBRARY(MyLibrary ${MySources})
该代码在非MSVC平台上仍然可以正常运行。挺整洁的 :)
我最终使用了适应版本的larsm宏。将$(IntDir)用于pch路径可将调试和发布版本的预编译头分开。
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)