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

Posted

技术标签:

【中文标题】CMake:$<CONFIG:cfg_list> 或 $<IN_LIST:str,list> 的正确语法是啥?【英文标题】:CMake: what is the correct syntax for $<CONFIG:cfg_list> or $<IN_LIST:str,list>?CMake:$<CONFIG:cfg_list> 或 $<IN_LIST:str,list> 的正确语法是什么? 【发布时间】:2021-11-26 03:20:37 【问题描述】:

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

参考CMake generator expressions 文档,$&lt;CONFIG:cfgs&gt; 似乎是$&lt;IN_LIST:string,list&gt; 的特殊情况,其中字符串为$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

在尝试 $&lt;IN_LIST:str,list&gt; 之前,我已经对原始语法进行了各种更改,但是由于我无法使 IN_LIST 语法正常工作,我觉得有一些基本的东西我错了m 也未能从文档中掌握。


随后的实验,使用:

    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 应该应用于括号内的 表达式。但它仍然不能帮助我理解 CONFIG 生成器表达式的正确语法。

【问题讨论】:

【参考方案1】:

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

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

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

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

    single-configiration 生成器(如 Makefile)上,构建类型是通过 CMAKE_BUILD_TYPE 变量指定的。所以生成器表达式中不需要引用构建类型。

    变量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()

【讨论】:

我昨天发现一个帖子暗示了你所说的,但你已经解释得更好了。所以正确的答案是“你不能从这里到达那里”。不是我想听到的,但我知道停止转动我的***。谢谢!【参考方案2】:

使用 CMake 包括两个阶段:

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

生成器表达式$&lt;suff&gt; 在构建项目时扩展。它们在 CMake 脚本中扩展。对于 CMake 脚本,在配置项目时,它只是文本。

要在 CMake 中进行比较,请在 CMake 中进行比较。我猜:

if (CMAKE_BUILD_TYPE IN_LIST CMAKE_CONFIGURATION_TYPES)

【讨论】:

我了解这两个步骤,但现在我只是在第一步上挂断了电话。 CMAKE_BUILD_TYPE 是一个 CMake 隐式变量,用户可以在命令行中显式指定它,或者他们可以使用默认值运行(这是一个空字符串,所以如果你的 CMake 脚本关心,你需要指定一个默认值) . IIRC,CMAKE_CONFIGURATION_TYPES 也是一个隐式 CMake 变量。 Och CMAKE_CONFIGURATION_TYPES 是吗?我不知道;)对不起。

以上是关于CMake:$<CONFIG:cfg_list> 或 $<IN_LIST:str,list> 的正确语法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

CMake基础教程(30)在cmake里执行命令execute_process

CMake基础教程(20)认识cmake命令

CMake中cmake_minimum_required的使用

CMake + ccache:RULE_LAUNCH_COMPILE 或 CMAKE_<LANG>_COMPILER_LAUNCHER

CMake 错误无法运行 MSBuild 命令

CMake中cmake_host_system_information的使用