C++ 在 CMake 中使用预编译的头文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/148570/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:14:56  来源:igfitidea点击:

Using pre-compiled headers with CMake

c++visual-studiogcccmakeprecompiled-headers

提问by Glutinous

I have seen a few (old) posts on the 'net about hacking together some support for pre-compiled headers in CMake. They all seem a bit all-over the place and everyone has their own way of doing it. What is the best way of doing it currently?

我在网上看到了一些(旧的)帖子,关于在 CMake 中对预编译头的一些支持进行黑客攻击。他们似乎都有点无处不在,每个人都有自己的做法。目前最好的方法是什么?

回答by sakra

There is a third party CMake module named 'Cotire'which automates the use of precompiled headers for CMake based build systems and also supports unity builds.

有一个名为“Cotire”的第三方 CMake 模块,它可以为基于 CMake 的构建系统自动使用预编译头文件,并且还支持统一构建。

回答by larsmoa

Im using the following macro to generate and use precompiled headers:

我使用以下宏来生成和使用预编译头:

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)

Lets say you have a variable ${MySources} with all your sourcefiles, the code you would want to use would be simply be

假设您有一个包含所有源文件的变量 ${MySources},您想要使用的代码就是

ADD_MSVC_PRECOMPILED_HEADER("precompiled.h" "precompiled.cpp" MySources)
ADD_LIBRARY(MyLibrary ${MySources})

The code would still function just fine on non-MSVC platforms too. Pretty neat :)

该代码在非 MSVC 平台上仍然可以正常运行。漂亮整齐 :)

回答by Dave Hillier

Here is a code snippet to allow you to use precompiled header for your project. Add the following to your CMakeLists.txt replacing myprecompiledheadersand myproject_SOURCE_FILESas appropriate:

这是一个代码片段,允许您为您的项目使用预编译头。将以下内容添加到您的 CMakeLists.txt 替换myprecompiledheadersmyproject_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)

回答by janisozaur

CMake has just gained support for PCHs, it should be available in the upcoming 3.16 release, due 2019-10-01:

CMake 刚刚获得了对 PCH 的支持,它应该会在即将于 2019 年 10 月 1 日发布的 3.16 版本中提供:

https://gitlab.kitware.com/cmake/cmake/merge_requests/3553

https://gitlab.kitware.com/cmake/cmake/merge_requests/3553

  target_precompile_headers(<target>
    <INTERFACE|PUBLIC|PRIVATE> [header1...]
    [<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])

There is ongoing discussion on supporting sharing PCHs between targets: https://gitlab.kitware.com/cmake/cmake/issues/19659

正在讨论支持在目标之间共享 PCH:https://gitlab.kitware.com/cmake/cmake/issues/19659

There is some additional context (motivation, numbers) available at https://blog.qt.io/blog/2019/08/01/precompiled-headers-and-unity-jumbo-builds-in-upcoming-cmake/

https://blog.qt.io/blog/2019/08/01/precompiled-headers-and-unity-jumbo-builds-in-upcoming-cmake/提供了一些额外的上下文(动机、数字)

回答by jari

I ended up using an adapted version of larsm macro. Using $(IntDir) for pch path keeps precompiled headers for debug and release builds separate.

我最终使用了 larsm 宏的改编版本。对 pch 路径使用 $(IntDir) 可以将用于调试和发布版本的预编译头分开。

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})

回答by martjno

Adapted from Dave, but more efficient (sets target properties, not for each file):

改编自 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)

回答by Roman Kruglov

if you don't wanna reinvent the wheel, just use either Cotire as the top answer suggests or a simpler one - cmake-precompiled-headerhere. To use it just include the module and call:

如果您不想重新发明轮子,只需使用 Cotire 作为最佳答案建议或使用更简单的一个 - cmake-precompiled-header here。要使用它,只需包含模块并调用:

include( cmake-precompiled-header/PrecompiledHeader.cmake )
add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )

回答by Maks

An example of usage precompiled header with cmake and Visual Studio 2015

使用 cmake 和 Visual Studio 2015 预编译头的示例

"stdafx.h", "stdafx.cpp" - precompiled header name.

"stdafx.h", "stdafx.cpp" - 预编译的头文件名。

Put the following below in the root cmake file.

将以下内容放在根 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()


Put the following below in the project cmake file.

将以下内容放入项目 cmake 文件中。

"src" - a folder with source files.

“src” - 包含源文件的文件夹。

set_source_files_properties(src/stdafx.cpp
    PROPERTIES
    COMPILE_FLAGS "/Ycstdafx.h"
)

回答by usr1234567

CMake 3.16 introduced support for precompiled headers. There is a new CMake command target_precompile_headerswhich does everything you need under the hood. See its documentation for further details: https://cmake.org/cmake/help/latest/command/target_precompile_headers.html

CMake 3.16 引入了对预编译头文件的支持。有一个新的 CMake 命令target_precompile_headers可以在幕后完成您需要的一切。有关更多详细信息,请参阅其文档:https: //cmake.org/cmake/help/latest/command/target_precompile_headers.html

回答by Vram Vardanian

IMHO the best way is to set PCH for whole project, as martjno suggested, combined with ability of ignoring PCH for some sources if needed (e.g. generated sources):

恕我直言,最好的方法是为整个项目设置 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)

So, if you have some target MY_TARGET, and list of generated sources IGNORE_PCH_SRC_LIST you'll simply do:

因此,如果您有一些目标 MY_TARGET 和生成的源列表 IGNORE_PCH_SRC_LIST,您只需执行以下操作:

SET_TARGET_PRECOMPILED_HEADER(MY_TARGET stdafx.h stdafx.cpp)
IGNORE_PRECOMPILED_HEADER(IGNORE_PCH_SRC_LIST)

This aproach is tested and works perfectly.

这种方法已经过测试并且运行良好。