Build 如何添加特定于配置的cmake生成器表达式以添加自定义目标

Build 如何添加特定于配置的cmake生成器表达式以添加自定义目标,build,msbuild,cmake,Build,Msbuild,Cmake,我试图说服cmake添加一个自定义目标,该目标在Visual Studio上构建预编译头(注意:请不要建议我使用自定义构建步骤,我特别需要一个构建预编译头的构建target)。请注意,您不能在配置阶段简单地添加CMAKE_CXX_标志${CMAKE_BUILD_TYPE},因为这在生成的.vcxproj中不起作用,用户可以在其中更改生成配置,因此,我需要在构建阶段告诉cmake为每个可能的配置输出正确的内容,即适当配置的cmake_CXX_标志和cmake_CXX_标志_$ 除了一个我想寻求帮助

我试图说服cmake添加一个自定义目标,该目标在Visual Studio上构建预编译头(注意:请不要建议我使用自定义构建步骤,我特别需要一个构建预编译头的构建target)。请注意,您不能在配置阶段简单地添加CMAKE_CXX_标志${CMAKE_BUILD_TYPE},因为这在生成的.vcxproj中不起作用,用户可以在其中更改生成配置,因此,我需要在构建阶段告诉cmake为每个可能的配置输出正确的内容,即适当配置的cmake_CXX_标志和cmake_CXX_标志_$

除了一个我想寻求帮助的问题外,我的解决方案就快到了:

# 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()
这很有效。非常感谢齐瓦列夫

编辑2:事实证明,cmake至少对MSVC的预编译头生成提供了未经证明的支持。查看中的
add_precompiled_header()
函数,您只需将
/Yc
标志提供给对象类型库,瞧,Visual Studio生成器做了正确的事情,正确的.vcxproj XML节和所有内容。

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

# 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
#处理发布标志。
设置(FLAGS_RELEASE${CMAKE_CXX_FLAGS_RELEASE})
单独的参数(标志发布)#标志已准备好进行迭代
foreach(FLAG_RELEASE${FLAGS_RELEASE})
列表(附加标志$)
endforeach(FLAGS_RELEASE${FLAGS_RELEASE})
#其他生成类型的标志以相同的方式处理。
# ...
#现在“flags”变量可用于命令

我已经尝试了@Tsyvarev的答案,但效果很好

一般来说,您遇到的问题被认为是CMake本身的bug或特性请求。您可能希望将您的支持添加到仍然打开的CMake

我只是想添加一个简单的替代方法,在编译器选项的生成器表达式不起作用时使用:

file(
    WRITE "${CMAKE_CURRENT_BINARY_DIR}/Debug.flags" 
        "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG}"
)
file(
    WRITE "${CMAKE_CURRENT_BINARY_DIR}/Release.flags" 
        "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}"
)
file(
    WRITE "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo.flags" 
        "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}"
)
file(
    WRITE "${CMAKE_CURRENT_BINARY_DIR}/MinSizeRel.flags" 
        "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_MINSIZEREL}"
)

# Now 'flags' files may be used for COMMAND
add_custom_target(
    ${outvar}
    COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${header}.dir/${CMAKE_CFG_INTDIR}"
    COMMAND ${CMAKE_CXX_COMPILER} /c @$<CONFIG>.flags /Fp"${pchpath}" /Yc"${header}" /Tp"${CMAKE_CURRENT_SOURCE_DIR}/${headerpath}"
    COMMENT "Precompiling header ${headerpath} ..."
    SOURCES "${headerpath}"
)
文件(
写入“${CMAKE\u CURRENT\u BINARY\u DIR}/Debug.flags”
“${CMAKE_CXX_FLAGS}${CMAKE_CXX_FLAGS_DEBUG}”
)
文件(
写入“${CMAKE\u CURRENT\u BINARY\u DIR}/Release.flags”
“${CMAKE_CXX_FLAGS}${CMAKE_CXX_FLAGS_RELEASE}”
)
文件(
写入“${CMAKE\u CURRENT\u BINARY\u DIR}/RelWithDebInfo.flags”
“${CMAKE_CXX_FLAGS}${CMAKE_CXX_FLAGS_RELWITHDEBINFO}”
)
文件(
写入“${CMAKE_CURRENT_BINARY_DIR}/MinSizeRel.flags”
“${CMAKE_CXX_FLAGS}${CMAKE_CXX_FLAGS_minsizerl}”
)
#现在“标志”文件可用于命令
添加自定义目标(
${outvar}
COMMAND${CMAKE_COMMAND}-E make_目录“${CMAKE_CURRENT_BINARY_DIR}/${header}.DIR/${CMAKE_CFG_INTDIR}”
命令${CMAKE_CXX_COMPILER}/c@$.flags/Fp“${pchpath}”/Yc“${header}”/Tp“${CMAKE_CURRENT_SOURCE_DIR}/${headerpath}”
注释“预编译头${headerpath}…”
来源“${headerpath}”
)
参考资料


在列表中包含参数后,只需将
逐字添加到
添加自定义目标()
就足够了吗?我认为您不必在每个标志之前迭代并添加
$
。请参见,例如,不了解Windows,但在Linux(Makefiles)上,如果值为列表,则CMake会错误地扩展生成器表达式。一字不差,恶心。但它可能只是工作。我明天会给你回复测试结果。@NiallDouglas只是想跟进我的评论:我已经用
逐字
给出了你问题的例子,但这并没有让事情变得更好。@Florian我已经尝试过
逐字
,确实没有帮助。另外,该选项在预编译头文件路径周围的双引号前添加反斜杠,这是非常没有帮助的。另一个非常相关的cmake问题是,我不愿意使用单独的文件,因为与Linux、FreeBSD或OS X相比,Windows文件系统在创建文件方面特别慢。大规模应用,这种技术将使cmake在Windows上的速度明显减慢。不过,谢谢你的想法,它可能对其他人有用。@NiallDouglas不客气。优化CMAPK项目的周转时间是BTW.一个正在进行的矿山项目(见)。我正在慢慢地为CG+ C++库构建下一代标准的Cug工具,所以有一种“Boost 2”。这个CMAGE工具与通常的东西有点不同,它可以自动地适应任何带有增强目录布局的C++库,将来还会自动使用C++模块等。它也非常快,因为我只使用了最快的cmake编程技术来遍历嵌套的只头库的深层层次结构。我不会认为它对任何人有用,直到明年,但你可能希望明星和检查不时。
file(
    WRITE "${CMAKE_CURRENT_BINARY_DIR}/Debug.flags" 
        "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG}"
)
file(
    WRITE "${CMAKE_CURRENT_BINARY_DIR}/Release.flags" 
        "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}"
)
file(
    WRITE "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo.flags" 
        "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}"
)
file(
    WRITE "${CMAKE_CURRENT_BINARY_DIR}/MinSizeRel.flags" 
        "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_MINSIZEREL}"
)

# Now 'flags' files may be used for COMMAND
add_custom_target(
    ${outvar}
    COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${header}.dir/${CMAKE_CFG_INTDIR}"
    COMMAND ${CMAKE_CXX_COMPILER} /c @$<CONFIG>.flags /Fp"${pchpath}" /Yc"${header}" /Tp"${CMAKE_CURRENT_SOURCE_DIR}/${headerpath}"
    COMMENT "Precompiling header ${headerpath} ..."
    SOURCES "${headerpath}"
)