0

使用 CMake 版本 3.20.1,我正在做一些我认为相对简单的事情:验证cfgpass via的值-DCMAKE_BUILD_TYPE=<cfg>是否是有效配置。

参考CMake 生成器表达式文档,这似乎是字符串所在位置的$<CONFIG:cfgs>特殊情况。我得到的 CMake 运行时错误强化了这一点,并告诉我我遗漏了一些东西。$<IN_LIST:string,list>${CMAKE_CONFIGURATION_TYPES}

我期望工作的是:

    set( CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Build Configurations" FORCE )
    
    if( NOT $<CONFIG:${CMAKE_CONFIGURATION_TYPES}> )
      # Handle_the_bad_value()
    endif()

当从命令行调用 ascmake .. -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生成器表达式的正确语法。

4

2 回答 2

1

您不能在命令中使用生成器表达式if,因为生成器表达式仅在配置过程结束时扩展,但if需要立即评估条件。

表达式$<IN_LIST:<$CONFIG>,${CMAKE_CONFIGURATION_TYPES}>在其他生成器表达式的 BOOL 上下文中有效。但它只能用于生成另一个字符串,不能用于发出错误。

如果要检查用户指定的构建类型的正确性,应考虑以下事项:

  1. 多配置生成器(如 Visual Studio)上,构建类型由--config构建阶段的选项给出。CMake会自动检查此类构建类型是否与 匹配CMAKE_CONFIGURATION_TYPES,因此无需手动检查。

  2. 单一配置生成器(如 Makefile)上,构建类型是通过CMAKE_BUILD_TYPE变量指定的。所以生成器表达式中不需要引用构建类型。

  3. 应为多配置生成器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()
于 2021-10-06T08:10:57.540 回答
0

使用 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)
于 2021-10-05T21:34:11.570 回答