build - 如何将配置特定的 cmake 生成器表达式添加到 add_custom_target

标签 build msbuild cmake

我试图说服 cmake 添加一个自定义目标,该目标在 Visual Studio 上构建一个预编译 header (注意:请不要建议我改用自定义构建步骤,我特别需要一个构建目标 它构建了一个预编译头文件)。请注意,您不能在配置阶段简单地添加 CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE},因为这在生成的 .vcxproj 中不起作用,用户可以在其中更改构建配置,因此我需要以某种方式告诉 cmake 在其构建阶段输出正确的东西对于每个可能的配置,即适当配置的 CMAKE_CXX_FLAGS 和 CMAKE_CXX_FLAGS_$

除了一个我正在寻求帮助的问题:

# Adds a custom target which generates a precompiled header
function(add_precompiled_header outvar headerpath)
  get_filename_component(header "${headerpath}" NAME)
  set(pchpath ${CMAKE_CURRENT_BINARY_DIR}/${header}.dir/${CMAKE_CFG_INTDIR}/${header}.pch)
  set(flags ${CMAKE_CXX_FLAGS})
  separate_arguments(flags)
  set(flags ${flags}
    $<$<CONFIG:Debug>:${CMAKE_CXX_FLAGS_DEBUG}>
    $<$<CONFIG:Release>:${CMAKE_CXX_FLAGS_RELEASE}>
    $<$<CONFIG:RelWithDebInfo>:${CMAKE_CXX_FLAGS_RELWITHDEBINFO}>
    $<$<CONFIG:MinSizeRel>:${CMAKE_CXX_FLAGS_MINSIZEREL}>
  )
  if(MSVC)
    add_custom_target(${outvar}
      COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${header}.dir/${CMAKE_CFG_INTDIR}"
      COMMAND ${CMAKE_CXX_COMPILER} /c ${flags} /Fp"${pchpath}" /Yc"${header}" /Tp"${CMAKE_CURRENT_SOURCE_DIR}/${headerpath}"
      COMMENT "Precompiling header ${headerpath} ..."
      SOURCES "${headerpath}"
    )
  endif()
endfunction()

这几乎可以在每个构建配置的正确标志已扩展到 .vcxproj 文件中它们各自的命令节的情况下工作:

<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">setlocal
  "G:\Program Files\CMake\bin\cmake.exe" -E make_directory G:/boost.afio/cmake/afio.hpp.dir/$(Configuration)
  if %errorlevel% neq 0 goto :cmEnd
  "G:\Program Files\Microsoft Visual Studio 14.0\VC\bin\cl.exe" /c /DWIN32 /D_WINDOWS /W3 /GR /EHsc  "/MD /O2 /Ob2 /D NDEBUG"   /Fp"G:/boost.afio/cmake/afio.hpp.dir/$(Configuration)/afio.hpp.pch" /Yc"afio.hpp" /Tp"G:/boost.afio/include/boost/afio/afio.hpp"
  if %errorlevel% neq 0 goto :cmEnd
:cmEnd
  endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
:cmErrorLevel
  exit /b %1
:cmDone
  if %errorlevel% neq 0 goto :VCEnd
</Command>

问题是生成器 $<$<CONFIG:Release>:${CMAKE_CXX_FLAGS_RELEASE}>由于包含空格扩展为带引号的字符串 "/MD /O2 /Ob2 /D NDEBUG"这当然会导致编译器大声提示。

因此我需要的是以下之一:

  1. 告诉 cmake 生成器表达式不要将包含空格的内容扩展为带引号的字符串的一些方法。

  1. 将 CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE} 扩展到 add_custom_target 的每个配置特定部分的其他一些方法。

非常感谢。

编辑:根据下面 Tsyvarev 的回答,我想到了这个:

# Add generator expressions to appendvar expanding at build time any remaining parameters
# if the build configuration is config
function(expand_at_build_if_config config appendvar)
  set(ret ${${appendvar}})
  set(items ${ARGV})
  list(REMOVE_AT items 0 1)
  separate_arguments(items)
  foreach(item ${items})
    list(APPEND ret $<$<CONFIG:${config}>:${item}>)
  endforeach()
  set(${appendvar} ${ret} PARENT_SCOPE)
endfunction()

这很好用。非常感谢 Tsyvarev!

编辑 2:事实证明 cmake 至少对 MSVC 具有对预编译 header 生成的未记录支持。看看add_precompiled_header()https://github.com/ned14/boost-lite/blob/master/cmake/BoostLitePrecompiledHeader.cmake 中发挥作用,您需要做的就是提供 /Yc标记为 OBJECT 类型库,瞧,Visual Studio 生成器做正确的事情,更正 .vcxproj XML 节和所有内容。

最佳答案

用空格分割FLAGS,并为每个标志附加相应的生成器表达式:

# Process Release flags.
set(FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
separate_arguments(FLAGS_RELEASE) # Flags are ready for iterate

foreach(FLAG_RELEASE ${FLAGS_RELEASE})
    list(APPEND flags $<$<CONFIG:Release>:${FLAG_RELEASE}>)
endforeach(FLAGS_RELEASE ${FLAGS_RELEASE})
# Flags for other build types are processed in the same way.
# ...

# Now 'flags' variable may be used for COMMAND

关于build - 如何将配置特定的 cmake 生成器表达式添加到 add_custom_target,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38245049/

相关文章:

c++ - 如何在 visual studio 的所有 cpp 文件中自动包含标题?

Cmake 构建类型(RELEASE、DEBUG 等)编译器标志

c - 自动重建依赖关系(makefiles)

c++ - 如何使 eclipse cdt(c++) 一键构建&运行?

java - 寻找 Java 项目的层次结构标准

maven - 如何在程序集 JAR 中添加本地依赖项

c# - 在全局级别抑制 StyleCop 警告

msbuild - 如何解决sonarqube中的代码行限制问题?

linux - 如何从 CMake 工具链文件设置 LD_LIBRARY_PATH?

c - 字符串化 CMake 预处理器 token