我试图说服 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 & call :cmErrorLevel %errorlevel% & 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"
这当然会导致编译器大声提示。
因此我需要的是以下之一:
- 告诉 cmake 生成器表达式不要将包含空格的内容扩展为带引号的字符串的一些方法。
或
- 将 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/