CMake中$<CONFIG>生成器表达式跨平台求值结果不一致
CMake中$在Linux下为空的问题分析与解决
问题现象
编写如下CMake自定义命令:
add_custom_command(TARGET MyTarget POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Hello! $<CONFIG>")
执行构建命令:
cmake --build . --config Debug --target MyTarget --verbose
不同平台输出差异明显:
- Windows(CMake 3.24.1,Visual Studio生成器)输出:
"C:\Program Files\CMake\bin\cmake.exe" -E echo "Hello! Debug" - Linux(CMake 3.22.1,Makefile生成器)输出:
/usr/bin/cmake -E echo Hello!
可见Linux环境下$<CONFIG>被解析为空字符串。
实际业务场景中,如下目录配置语句在Windows正常工作,但Linux完全失效:
set(installDirectory "${artifactsDirectory}/$<LOWER_CASE:$<CONFIG>>")
补充测试CMake文档中的条件配置示例:
add_custom_command(TARGET ${name} POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "$<$<CONFIG:Debug>:DEBUG_MODE>")
- Windows输出:
"C:\Program Files\CMake\bin\cmake.exe" -E echo DEBUG_MODE - Linux输出:
/usr/bin/cmake -E echo(仅输出空内容)
原因分析
这并非CMake的bug,而是多配置生成器与单配置生成器的核心行为差异导致:
- Windows常用的Visual Studio属于多配置生成器,支持在构建阶段通过
--config参数动态指定配置类型,$<CONFIG>会在构建阶段实时解析为指定的配置值。 - Linux默认的Makefile生成器属于单配置生成器,配置类型必须在CMake初始化配置阶段(执行
cmake ..时)通过CMAKE_BUILD_TYPE变量指定,构建阶段传入的--config参数会被直接忽略。若配置阶段未显式设置CMAKE_BUILD_TYPE,其默认值为空,最终导致$<CONFIG>也解析为空。
解决方案
1. 单配置生成器显式指定构建类型
在CMake配置阶段通过-DCMAKE_BUILD_TYPE明确指定配置类型,再执行构建:
# 初始化配置时指定Debug类型 cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug # 构建阶段无需再传递--config参数 cmake --build build --target MyTarget --verbose
此时$<CONFIG>会被正确解析为Debug。
2. 兼容单/多配置生成器的通用写法
使用$<IF>表达式兼容两种生成器场景:优先判断$<CONFIG>是否为空(单配置场景特征),为空则使用CMAKE_BUILD_TYPE的值,否则使用$<CONFIG>:
add_custom_command(TARGET MyTarget POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Hello! $<IF:$<CONFIG:>,${CMAKE_BUILD_TYPE},$<CONFIG>>" )
3. 目录复制场景的修正
针对按配置复制输出到不同目录的需求,调整installDirectory的定义,同时兼容两种生成器:
# 兼容单/多配置的目录路径写法 set(installDirectory "${artifactsDirectory}/$<LOWER_CASE:$<IF:$<CONFIG:>,${CMAKE_BUILD_TYPE},$<CONFIG>>>")
或者提前将CMAKE_BUILD_TYPE转为小写,避免重复调用LOWER_CASE:
string(TOLOWER "${CMAKE_BUILD_TYPE}" build_type_lower) set(installDirectory "${artifactsDirectory}/$<IF:$<CONFIG:>,${build_type_lower},$<LOWER_CASE:$<CONFIG>>>")
内容的提问来源于stack exchange,提问作者Mircea Ispas
相关产品推荐
相关产品推荐

