CMake:$< CONFIG:cfg_list>或$〈IN_LIST:str,list>的正确语法是什么?

k7fdbhmy  于 2023-01-30  发布在  其他
关注(0)|答案(2)|浏览(229)

使用CMake 3.20.1版,我正在做一些我认为相对简单的事情:检验cfg通过-DCMAKE_BUILD_TYPE=<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" ) )

它会进行计算,但计算结果不正确,因为它在列表中找不到"Debug",所以它会在if语句中输入代码。

if( NOT ( CMAKE_BUILD_TYPE IN_LIST CMAKE_CONFIGURATION_TYPES ) )

***是否按预期工作。注意:NOT应该应用于括号内的 * expression *,但它仍然不能帮助我理解CONFIG生成器表达式的正确语法。

hs1ihplo

hs1ihplo1#

不能在if命令中使用 * 生成器表达式 *,因为生成器表达式仅在配置过程结束时展开,但需要立即计算if条件。
表达式$<IN_LIST:<$CONFIG>,${CMAKE_CONFIGURATION_TYPES}>在其他生成器表达式的BOOL上下文中有效。但它只能用于生成另一个字符串,不能用于发出错误。
如果要检查用户指定的生成类型的正确性,则应考虑以下事项:
1.在多配置生成器(如Visual Studio)上,构建类型由构建阶段的--config选项给定。CMake自动检查此类构建类型是否与CMAKE_CONFIGURATION_TYPES匹配,因此无需手动检查。
1.在single-configiration生成器(如Makefile)上,构建类型通过CMAKE_BUILD_TYPE变量指定。因此生成器表达式中不需要引用构建类型。
1.变量CMAKE_CONFIGURATION_TYPES指定给多配置生成器。为单配置生成器设置该变量可能会混淆某些脚本(例如FindXXX.cmake)。
因此,您可以通过以下方式检查构建类型(基于that answer中的代码)

# 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()
ma8fv8wu

ma8fv8wu2#

使用CMake包括两个阶段:

  • 配置阶段cmake -S . -B _buildcd _build && cmake ..
  • 构建阶段cmake --build _buildcd _build && make

生成器表达式$<suff>在 * 构建项目时 * 被展开。它们在CMake脚本中 * 不 * 被展开。对于CMake脚本,在配置项目时,它只是文本。
要在CMake中比较,就在CMake中比较。我猜:

if (CMAKE_BUILD_TYPE IN_LIST CMAKE_CONFIGURATION_TYPES)

相关问题