我在网上看到了一些有关在CMake中合并预编译头文件的方法的旧帖子。它们看起来都比较混乱,每个人都有自己的做法。目前最好的方法是什么?
我在网上看到了一些有关在CMake中合并预编译头文件的方法的旧帖子。它们看起来都比较混乱,每个人都有自己的做法。目前最好的方法是什么?
有一个名为'Cotire'的第三方CMake模块,它可以自动化使用预编译头文件来构建基于CMake的系统,并且还支持统一构建。
CMake现已支持PCH(预编译头文件),从2019年10月发布的3.16版本开始可用:
https://gitlab.kitware.com/cmake/cmake/merge_requests/3553
target_precompile_headers(<target>
<INTERFACE|PUBLIC|PRIVATE> [header1...]
[<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
通过REUSE_FROM
关键字(例如此处)支持在目标之间共享PCH。
有一些附加的背景信息(动机、数字)可在https://blog.qt.io/blog/2019/08/01/precompiled-headers-and-unity-jumbo-builds-in-upcoming-cmake/中找到。
target_precompile_headers(MyTarget PUBLIC "$<$<COMPILE_LANGUAGE:OBJC,OBJCXX>:${CMAKE_CURRENT_LIST_DIR}/src/MyPrefixHeader.pch>")
- 如果您的头文件不支持 C/C++,或者只需添加支持(通过在任何 #import
中包含 #ifdef __OBJC__
检查)。 - Top-MasterCannot specify precompile headers for target "xxx," which is not built by this project
。很可能是由于CMakeLists.txt被包含在其他地方。也许有人有一个在多项目环境下使用它的例子? - Joerg S我正在使用以下宏来生成和使用预编译头文件:
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平台上,该代码仍会正常运行。相当不错 :)
list( APPEND ... )
移到了关闭的 endif()
外面。在这里查看完整代码:http://pastebin.com/84dm5rXZ - void.pointer/Yu
和/FI
参数,它们应该是${PrecompiledHeader}
而不是${PrecompiledBinary}
。 - Mourad以下是一段代码片段,可以让你为你的项目使用预编译头文件。
将以下内容添加到你的CMakeLists.txt文件中,根据需要替换myprecompiledheaders
和myproject_SOURCE_FILES
:
add_library(myprecompiledheaders OBJECT myheader1.h myheader2.h)
set_source_files_properties(${myproject_SOURCE_FILES} PROPERTIES COMPILE_FLAGS "/Yu"myheader1.h"")
target_compile_options(myprecompiledheaders PRIVATE /Yc"myheader1.h")
target_link_libraries(myproject PUBLIC myprecompiledheaders)
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)
set(CMAKE_AUTOMOC ON)
时无法获取自动生成文件的列表。 - Dmitry Sazonovmyprecompiledheader.cpp
首先被编译吗?从这段代码片段来看,它似乎会最后被编译,所以这可能是导致延迟的原因。myprecompiledheader.h
仅包含我的代码使用的最常见的STL头文件。 - Grim Fandango我最终使用了经过改编的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)
abc
是什么? - Sandburginclude( cmake-precompiled-header/PrecompiledHeader.cmake )
add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )
"stdafx.h"、"stdafx.cpp" - 预编译头文件名称。
将以下内容放在根目录的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()
set_source_files_properties(src/stdafx.cpp
PROPERTIES
COMPILE_FLAGS "/Ycstdafx.h"
)
我认为最好的方法是为整个项目设置PCH,就像martjno建议的那样,再加上忽略某些源文件的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)
SET_TARGET_PRECOMPILED_HEADER(MY_TARGET stdafx.h stdafx.cpp)
IGNORE_PRECOMPILED_HEADER(IGNORE_PCH_SRC_LIST)
最简单的方法是将预编译选项作为全局选项添加。在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})
这经过测试适用于MSVC 2010,并将创建一个MyDll.pch文件,我不关心使用的文件名是什么,因此我没有指定任何努力。