我正在努力说服cmake添加一个自定义目标,该目标在Visual Studio上构建预编译头文件(注意:请不要建议我使用自定义构建步骤,我特别需要构建目标来构建预编译头文件)。请注意,在配置阶段不能简单地添加CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE},因为在生成的.vcxproj中用户可以更改生成配置,因此我需要以某种方式告诉cmake在其构建阶段为每个可能的配置输出正确的内容,即适当配置的CMAKE_CXX_FLAGS和CMAKE_CXX_FLAGS_$<CMAKE_BUILD_TYPE>。
我已经非常接近解决这个问题了,除了一个我需要帮助解决的问题。
这个几乎可以工作,只要每个构建配置的正确标志已经扩展到其相应的命令段落中的 .vcxproj 文件中:
问题在于生成器
因此,我需要以下之一:
这很有效。非常感谢Tsyvarev! 编辑2:原来cmake支持预编译头文件生成,至少对于MSVC是如此,可以查看https://github.com/ned14/boost-lite/blob/master/cmake/BoostLitePrecompiledHeader.cmake中的
我已经非常接近解决这个问题了,除了一个我需要帮助解决的问题。
# 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的特定配置部分。
# 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是如此,可以查看https://github.com/ned14/boost-lite/blob/master/cmake/BoostLitePrecompiledHeader.cmake中的
add_precompiled_header()
函数,你只需要为OBJECT类型库提供/Yc
标志,Visual Studio生成器就会正确处理,包括正确的.vcxproj XML代码块。
add_custom_target()
中添加VERBATIM
是否就足够了呢?我认为你不必在每个标志之前迭代并添加$<$<CONFIG:Release>:...>
。例如,请参见这里。 - FlorianVERBATIM
来处理你问题的示例,但并没有改善情况。 - FlorianVERBATIM
,但它并没有起到帮助作用。此外,该选项会在预编译头文件路径周围的双引号前添加反斜杠,这非常不方便。 - Niall Douglas