CMake:$<CONFIG:cfg_list> 或 $<IN_LIST:str,list> 的正确语法是什么?
CMake: what is the correct syntax for $<CONFIG:cfg_list> or $<IN_LIST:str,list>?
使用 CMake 版本 3.20.1,我正在做一些我认为相对简单的事情:验证通过 -DCMAKE_BUILD_TYPE=<cfg>
传递的 cfg
的值是否是有效配置。
参考 CMake generator expressions 文档,$<CONFIG:cfgs>
似乎是 $<IN_LIST:string,list>
的特例,其中字符串为 ${CMAKE_CONFIGURATION_TYPES}
。我得到的 CMake 运行时错误强化了这一点,并告诉我我遗漏了一些东西。
我期望的工作是:
set( CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Build Configurations" FORCE )
if( NOT $<CONFIG:${CMAKE_CONFIGURATION_TYPES}> )
# Handle_the_bad_value()
endif()
当从命令行调用 cmake .. -DCMAKE_BUILD_TYPE=Debug
时,我收到以下错误:
CMake Error at CMakeLists.txt:45 (if):
if given arguments:
"NOT" "$<CONFIG:Debug" "Release>"
Unknown arguments specified
正在替换
$<CONFIG:<cfg_list>
与:
$<IN_LIST:${CMAKE_BUILD_TYPE},${CMAKE_CONFIGURATION_TYPES}>
或
$<IN_LIST:"Debug","Debug;Release">
给我以下内容:
CMake Error at CMakeLists.txt:43 (if):
if given arguments:
"NOT" "$<IN_LIST:Debug,Debug" "Release>"
Unknown arguments specified
在尝试使用 $<IN_LIST:str,list>
之前,我已经对原始语法进行了各种更改,但由于我无法使 IN_LIST
语法起作用,所以我觉得我有一些基本的东西我弄错了,我也没有从文档中理解。
后续实验,使用:
if( NOT ${CMAKE_BUILD_TYPE} IN_LIST ${CMAKE_CONFIGURATION_TYPES} )
产量:
CMake Error at CMakeLists.txt:43 (if):
if given arguments:
"NOT" "Debug" "IN_LIST" "Debug" "Release"
Unknown arguments specified
所以我尝试了暴力破解:
if( NOT ( "Debug" IN_LIST "Debug;Release" ) )
它计算但不正确,因为它在列表中没有找到“调试”,所以它在 if 语句中输入代码。最后尝试:
if( NOT ( CMAKE_BUILD_TYPE IN_LIST CMAKE_CONFIGURATION_TYPES ) )
是否按预期工作。注意:NOT
应应用于括号内的 表达式 。但它仍然无法帮助我理解 CONFIG
生成器表达式的正确语法。
使用 CMake 包括两个阶段:
- 配置阶段
cmake -S . -B _build
或cd _build && cmake ..
等
- 构建阶段
cmake --build _build
或cd _build && make
等
生成器表达式 $<suff>
在 构建项目时 展开。它们 未 在 CMake 脚本中展开。对于CMake脚本,在配置项目的时候,就是文本。
在CMake中比较,在CMake中比较。我猜:
if (CMAKE_BUILD_TYPE IN_LIST CMAKE_CONFIGURATION_TYPES)
您不能在if
命令中使用生成器表达式,因为生成器表达式仅在配置过程结束时展开,但if
条件需要立即评价。
表达式$<IN_LIST:<$CONFIG>,${CMAKE_CONFIGURATION_TYPES}>
有效
在其他生成器表达式的 BOOL 上下文中。但它只能用于生成另一个字符串,不能用于发出错误。
如果要检查用户指定的构建类型的正确性,应考虑以下事项:
在多配置 生成器(如Visual Studio)上,构建类型由--config
选项在构建阶段给出。 CMake 自动检查 此类构建类型以匹配 CMAKE_CONFIGURATION_TYPES
,因此无需手动检查。
在 单配置 生成器(如 Makefile)上,通过 CMAKE_BUILD_TYPE
变量指定构建类型。因此生成器表达式中不需要引用构建类型。
变量 CMAKE_CONFIGURATION_TYPES
应指定 仅 用于多配置生成器。为单配置生成器设置它可能会混淆一些脚本(例如 FindXXX.cmake
)。
因此,您可以通过以下方式检查构建类型(基于 中的代码)
# Use custom variable for avoid setting CMAKE_CONFIGURATION_TYPES
# for single-configuration generators.
set(MY_CONFIGURATION_TYPES "Debug;Release")
# Check whether generator is single-configuration or multi-configuration
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(isMultiConfig)
# Multi-configuration generator
# Set possible values. CMake automatically checks correctness.
set(CMAKE_CONFIGURATION_TYPES "${MY_CONFIGURATION_TYPES}" CACHE STRING "" FORCE)
else()
# Single-configuration generator
if(NOT CMAKE_BUILD_TYPE)
# If not set, set the build type to default.
message("Defaulting to release build.")
set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
else()
# Check correctness of the build type entered by user
# Note that the right operand for IN_LIST should be **variable**,
# not just a list of values
if (NOT (CMAKE_BUILD_TYPE IN_LIST MY_CONFIGURATION_TYPES))
message(FATAL_ERROR "Incorrect build type")
endif()
endif()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY HELPSTRING "Choose the type of build")
# set the suggested values for cmake-gui drop-down list
# Note, that CMake allows a user to input other values.
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${MY_CONFIGURATION_TYPES}")
endif()
使用 CMake 版本 3.20.1,我正在做一些我认为相对简单的事情:验证通过 -DCMAKE_BUILD_TYPE=<cfg>
传递的 cfg
的值是否是有效配置。
参考 CMake generator expressions 文档,$<CONFIG:cfgs>
似乎是 $<IN_LIST:string,list>
的特例,其中字符串为 ${CMAKE_CONFIGURATION_TYPES}
。我得到的 CMake 运行时错误强化了这一点,并告诉我我遗漏了一些东西。
我期望的工作是:
set( CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Build Configurations" FORCE )
if( NOT $<CONFIG:${CMAKE_CONFIGURATION_TYPES}> )
# Handle_the_bad_value()
endif()
当从命令行调用 cmake .. -DCMAKE_BUILD_TYPE=Debug
时,我收到以下错误:
CMake Error at CMakeLists.txt:45 (if):
if given arguments:
"NOT" "$<CONFIG:Debug" "Release>"
Unknown arguments specified
正在替换
$<CONFIG:<cfg_list>
与:
$<IN_LIST:${CMAKE_BUILD_TYPE},${CMAKE_CONFIGURATION_TYPES}>
或
$<IN_LIST:"Debug","Debug;Release">
给我以下内容:
CMake Error at CMakeLists.txt:43 (if):
if given arguments:
"NOT" "$<IN_LIST:Debug,Debug" "Release>"
Unknown arguments specified
在尝试使用 $<IN_LIST:str,list>
之前,我已经对原始语法进行了各种更改,但由于我无法使 IN_LIST
语法起作用,所以我觉得我有一些基本的东西我弄错了,我也没有从文档中理解。
后续实验,使用:
if( NOT ${CMAKE_BUILD_TYPE} IN_LIST ${CMAKE_CONFIGURATION_TYPES} )
产量:
CMake Error at CMakeLists.txt:43 (if):
if given arguments:
"NOT" "Debug" "IN_LIST" "Debug" "Release"
Unknown arguments specified
所以我尝试了暴力破解:
if( NOT ( "Debug" IN_LIST "Debug;Release" ) )
它计算但不正确,因为它在列表中没有找到“调试”,所以它在 if 语句中输入代码。最后尝试:
if( NOT ( CMAKE_BUILD_TYPE IN_LIST CMAKE_CONFIGURATION_TYPES ) )
是否按预期工作。注意:NOT
应应用于括号内的 表达式 。但它仍然无法帮助我理解 CONFIG
生成器表达式的正确语法。
使用 CMake 包括两个阶段:
- 配置阶段
cmake -S . -B _build
或cd _build && cmake ..
等 - 构建阶段
cmake --build _build
或cd _build && make
等
生成器表达式 $<suff>
在 构建项目时 展开。它们 未 在 CMake 脚本中展开。对于CMake脚本,在配置项目的时候,就是文本。
在CMake中比较,在CMake中比较。我猜:
if (CMAKE_BUILD_TYPE IN_LIST CMAKE_CONFIGURATION_TYPES)
您不能在if
命令中使用生成器表达式,因为生成器表达式仅在配置过程结束时展开,但if
条件需要立即评价。
表达式$<IN_LIST:<$CONFIG>,${CMAKE_CONFIGURATION_TYPES}>
有效
在其他生成器表达式的 BOOL 上下文中。但它只能用于生成另一个字符串,不能用于发出错误。
如果要检查用户指定的构建类型的正确性,应考虑以下事项:
在多配置 生成器(如Visual Studio)上,构建类型由
--config
选项在构建阶段给出。 CMake 自动检查 此类构建类型以匹配CMAKE_CONFIGURATION_TYPES
,因此无需手动检查。在 单配置 生成器(如 Makefile)上,通过
CMAKE_BUILD_TYPE
变量指定构建类型。因此生成器表达式中不需要引用构建类型。变量
CMAKE_CONFIGURATION_TYPES
应指定 仅 用于多配置生成器。为单配置生成器设置它可能会混淆一些脚本(例如FindXXX.cmake
)。
因此,您可以通过以下方式检查构建类型(基于
# Use custom variable for avoid setting CMAKE_CONFIGURATION_TYPES
# for single-configuration generators.
set(MY_CONFIGURATION_TYPES "Debug;Release")
# Check whether generator is single-configuration or multi-configuration
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(isMultiConfig)
# Multi-configuration generator
# Set possible values. CMake automatically checks correctness.
set(CMAKE_CONFIGURATION_TYPES "${MY_CONFIGURATION_TYPES}" CACHE STRING "" FORCE)
else()
# Single-configuration generator
if(NOT CMAKE_BUILD_TYPE)
# If not set, set the build type to default.
message("Defaulting to release build.")
set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
else()
# Check correctness of the build type entered by user
# Note that the right operand for IN_LIST should be **variable**,
# not just a list of values
if (NOT (CMAKE_BUILD_TYPE IN_LIST MY_CONFIGURATION_TYPES))
message(FATAL_ERROR "Incorrect build type")
endif()
endif()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY HELPSTRING "Choose the type of build")
# set the suggested values for cmake-gui drop-down list
# Note, that CMake allows a user to input other values.
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${MY_CONFIGURATION_TYPES}")
endif()