• CMake教程系列-05-选项及变量


    1.option

    此函数向项目添加一个选项,可以包含选项介绍及默认值。

    • 其原型为:
    option(<OPTION_NAME> "<help_text>" [value])
    
    • 1
    • 第一个参数为选项名称。需要注意的是,此选项不仅仅可以是boolean,也可以是string或list。
    • 第二个参数为选项介绍,为string。
    • 第三个参数为选项默认值,依据选项类型设置。

    2.CMAKE_DEPENDENT_OPTION

    进阶的。我们可以根据一些选项而额外设置其他选项值。

    • 其原型为:
    cmake_dependent_option(<OPTION_NAME> "<help_text>" <default_value> <depends> <force_value>)
    
    • 1
    • eg:
    CMAKE_DEPENDENT_OPTION(ENABLE_SAMPLE_TESTING "Enable sample test programs" ON
                           "ENABLE_SAMPLE_BUILD;NOT DISABLE_TESTING" OFF)
    
    • 1
    • 2
    • 第一个参数为选项名称。

    • 第二个参数为选项介绍。

    • 第三个参数为默认值。

    • 当第四个参数为TRUE时,开启此选项并自动设置第二个参数的值为默认值。否则,将强制设置该选项默认值为第五个参数值,使用者不能修改。

    • 在此示例中,如果 ENABLE_SAMPLE_BUILD 为 ON,且 DISABLE_TESTING 为 OFF, 则自动设置 ENABLE_SAMPLE_TESTING 为 ON,且该值可以通过cmake传入来覆盖,否则 ENABLE_SAMPLE_TESTING 会被强制设置为 OFF 且无法通过cmake传入覆盖。

    • 值得注意的是,第四个参数中可以用分号代表与的关系,也可以仅添加一个判断选项。

    3.set

    cmake作为一个弱类型语言,一个变量可代表多种类型,当我们设置一个变量并赋予初始值时,一般使用该函数。

    • 其原型有三种:
    set(<variable_name> <value>... [PARENT_SCOPE])
    
    set(<variable_name> <value>... CACHE <type> <docstring> [FORCE])
    
    set(ENV{<variable>} [<value>])
    
    • 1
    • 2
    • 3
    • 4
    • 5

    第一种:

    • 使用这种声明时,此变量作用域为从此声明起,至包含此行代码的函数结束,若没有被函数包含,则至此文件结束,向下游自动传递此变量。
    • 第一个参数是变量名称。
    • 第二个参数是设置的初始值。
    • 如果声明了 PARENT_SCOPE 关键字,则此变量向调用此函数或此文件的地方提供,且仅提供给上一层。

    第二种:

    • 这种情况下你可以认为它相当于 option :
    • 第一个参数是变量名称。
    • 第二个参数是设置的初始值。
    • CACHE 关键字代表了此变量是缓存变量。如果此变量在设置前不存在,则会将第二个值作为初始值。如果存在且没有传入 FORCE 关键字,则使用已存在的值;如果传入 FORCE 关键字,则强制设置为第二个值。
    • 第三个参数代表了该变量类型,有 BOOL, FILEPATH, PATH, STRING, INTERNAL(代表着FORCE)。

    第三种:

    • 这种情况下你可以设置一个环境变量。
    • 使用 ENV{VAR_NAME} 来设置一个名为VAR_NAME的环境变量值。

    cmake中使用每个变量,或者说获取变量的值有两种方式:

    • 使用 ${} 并在大括号中间写入变量名称,例如:
    ${SAMPLE_SOURCES}
    
    大部分情况下我们通常使用此种方式将变量转化为值来使用。
    需要注意的是,经过此种方式转化的值,会被还原为该变量类型。
    如果变量是string,则最后相当于设置了一个 "abc" ; 
    如果变量是布尔值,则相当于 ON ;
    如果是路径,则相当于 c:/windows ; 
    如果是list,则相当于传递了多个参数。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    直接使用变量名

    • 此种情况仅针对于cmake的各个函数,比如 foreach。一般情况下不建议各位使用。

    注意:如果使用以下代码,则相当于调用 unset 函数来解除此变量:

    set(VARIABLE_ONE)
    
    • 1

    4.unset

    对应的,该函数是解除一个变量声明。

    • 其原型为:
    unset(<variable> [CACHE | PARENT_SCOPE])
    
    unset(ENV{<variable>})
    
    • 1
    • 2
    • 3

    5.string

    该函数专门用于字符串处理,包含正则表达式匹配功能。

    string(operator ...)
    
    • 1

    常用的如下:

    • APPEND,追加字符串
    string(APPEND STRING_1 "world")
    
    • 1
    • PREPEND,向起始位置插入字符串
    string(PREPEND STRING_1 "hello")
    
    • 1
    • REPLACE,替换字符串内容
    string(REPLACE "hello" "world" STRING_2 ${STRING_1})
    
    • 1
    • LENGTH,获取字符串长度
    string(LENGTH STRING_1 STRING_1_LEN)
    
    • 1
    • SUBSTRING,按长度截取字符串。
    string(SUBSTRING STRING_1 0 4 STRING_2)
    
    • 1
    • TOUPPER / TOLOWER,字符串转大小写:
    string(TOUPPER STRING_1 STRING_2)
    string(TOLOWER STRING_1 STRING_1)
    
    • 1
    • 2
    • FIND,查找内容并获取内容的初始位置。
    string(FIND STRING_1 "hello" STRING_HELLO_INDEX)
    
    • 1

    正则匹配机制

    • 经常情况下我们使用下面的正则匹配机制。
    • REGEX,官方文档
    此关键字声明使用正则匹配,包含几个子关键字:
    
    MATCH 匹配一次
    MATCHALL 全部匹配
    REPLACE 匹配并替换字符串
    
    经常用的如下:
    ^ 表示开头
    $ 表示结尾
    . 一个任意字符
    * 多次匹配
    + 至少一次匹配
    ? 匹配0次或者1次
    () 提取其中内容
    [] 匹配其中任意字符
    | 匹配两侧任意一个
    \ 转义符
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • eg:
    string(REGEX REPLACE "^(.*)world$" "HELLO" STRING_1 "${STRING_1}")
    
    如果使用“()”,在第四个参数(替换成的字符串)中可使用 “\\<MATCH_INDEX>”的形式来直接表示其匹配到的内容,
    例如 \\1 。从1开始计算index。
    
    • 1
    • 2
    • 3
    • 4
    • 值得注意的是正则匹配也可以用于 if 函数 (使用 MATCHES)。

    6.list

    处理列表操作。

    list(operator <LIST_NAME> ...)
    
    几个常用的:
    APPEND追加一项:
    list(APPEND LIST_1 ${STRING_1})
    
    INSTERT插入一项:
    list(INSERT LIST_1 1 ${STRING_1})
    
    REMOVE_ITEM删除指定项:
    list(REMOVE_ITEM LIST_1 ${STRING_1})
    
    REMOVE_AT删除指定位置项:
    list(REMOVE_AT LIST_1 1 )
    
    REMOVE_DUPLICATES
    list(REMOVE_DUPLICATES LIST_1)
    
    LENGTH获取列表项数:
    list(LENGTH LIST_1 LIST_1_LEN)
    
    FILTER使用正则表达式删除匹配到或未匹配到项:
    list(FILTER LIST_1 "" INCLUDES REGEX "^hello world$")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    TRANSFORM

    • 此关键字用于将列表作为操作单元来对内部的每一条内容执行操作,所以无需遍历列表即可完成操作需求。
    子关键字有:
    APPEND / PREPEND向列表中每一项 追加或头插 字符串。
    list(TRANSFORM LIST_1 APPEND "hello " LIST_2)
    
    TOLOWER / TOUPPER将列表中每一项转为全小写或全大写。
    list(TRANSFORM LIST_1 TOUPPER)
    
    STRIP删除列表中每一项开头或结尾的空格。
    list(TRANSFORM LIST_1 STRIP)
    
    REPLACE替换列表中每一项的部分内容。
    list(TRANSFORM LIST_1 REPLACE "hello" "HELLO")
    此项可使用正则表达式。
    
    这些子关键字还可以附加以下规则以确定作用范围:
    1.AT 从哪条开始(到哪条结束)
    2.FOR 执行范围:开始-结束。
    3. REGEX 正则表达式确定范围。
    4. 例如:
    string(TRANSFORM LIST_1 REPLACE "hello" "HELLO" REGEX "^.*world$")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    7.if

    判断语句在程序中不可缺少,

    • cmake中的判断语句格式为:
    if (CONDITION_1)
        # do something
    elseif (CONDITION_2)
        # do something
    else()
        # do something
    endif()
    
    每个条件前可加 NOT 表明取反, 条件间可加 AND 或 OR 说明 关联关系。
    条件中可使用变量、字符串、数字、列表、版本号及target。以下详细说明:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    变量

    • 单独对变量判断一般为判空:
    if (VAR_1 STREQUAL "")
    ...
    endif()
    
    if (DEFINED VAR_1)
    ...
    endif()
    
    if (VAR_1)
    ...
    endif()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    字符串

    • 使用 STREUQAL 或 MATCHES 判断:
    STREUQAL
    if (STRING_1 STREQUAL "hello world")
    ...
    endif()
    
    if (NOT "${STRING_1}" STREQUAL "HELLO WORLD" AND NOT "${STRING_1}" STREQUAL "hello world")
    ...
    endif()
    这两种均可,个人建议第二种,声明了两边均为字符串。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    MATCHES

    • 激活此关键字可以使用正则表达式:
    if (STRING_1 MATCHES "^.*(world)$")
    ...
    endif()
    
    • 1
    • 2
    • 3
    • 值得说明的是,在if中间,可使用 CMAKE_MATCH_<MATCH_NUM> 来使用匹配到的内容,例如在上面的例子中, CMAKE_MATCH_1 为 world, MATCH_NUM 从1开始计算。

    数字

    • 数字这个东西在cmake中很不敏感,毕竟一般情况下也不会用数字进行运算,不过cmake仍提供了相关关键字:
    LESS
    GREATER
    EQUAL
    LESS_EQUAL
    GREATER_EQUAL
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • eg:
    if (LIST_1_COUNT LESS 5)
    ...
    endif()
    
    • 1
    • 2
    • 3

    列表

    • 使用 IN_LIST 关键字判断列表中是否存在某项:
    if ("feature_name1" IN_LIST FEATURES)
    ...
    endif()
    
    • 1
    • 2
    • 3

    版本号

    • 版本号不能使用数字判断关键字,而应当使用自己的一套关键字:
    VERSION_LESS
    VERSION_GREATER
    VERSION_EQUAL
    VERSION_LESS_EQUAL
    VERSION_GREATER_EQUAL
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • eg:
    if (CURL_VERSION VERSION_LESS 3.3.1)
    ...
    endif()
    
    • 1
    • 2
    • 3

    target

    • 使用target作为操作单元一般情况下仅仅判断它是否存在:
    if (NOT TARGET CURL::curl)
    ...
    endif()
    
    • 1
    • 2
    • 3

    8.foreach

    cmake使用 foreach 作为遍历函数名称

    • 其原型为:
    foreach(<loop_var> <operator> <items>)
      <commands>
    endforeach()
    
    • 1
    • 2
    • 3
    • 其中可以包含以下函数:
    break:声明跳出遍历。
    continue:直接遍历下一条。
    
    
    • 1
    • 2
    • 3
    • eg:
    foreach (ONE_ITEM IN LISTS LIST_1 LIST_2 LIST_3)
        if (...)
            break()
        endif()
        ...
    endforeach()
    
    foreach (ONE_ITEM IN ITEMS STRING_1)
        if (...)
            continue()
        endif()
        ...
    endforeach()
    
    foreach (ONE_ITEM RANGE 0 3)
        ...
    endforeach()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    9.while

    当然,cmake也提供while函数,不过用的甚少(场景略少)。

    while(<condition>)
      <commands>
    endwhile()
    
    • 1
    • 2
    • 3

    和 foreach 差不多用法,不过你没法在里面直接使用每一个项。所以用的很少。

    10.message

    我们的调试工作一般情况下全靠它了。

    • 其原型为:
    message([<mode>] "message text" ...)
    
    其中mode有多种,一些常用的:
    FATAL_ERROR 打印错误信息并终止整个配置流程
    WARNING 打印警告信息
    DEPRECATION 打印弃用信息
    STATUS 打印状态信息
    DEBUG 打印调试信息
    空 或 NOTICE 打印普通信息。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • eg:需要说明的是,其中可以包含获取变量值操作。
    message("hello world!")
    message(WARNING "Warning!")
    message(STATUS "Continue...")
    message(DEBUG "string 1 is: ${STRING_1}")
    message(FATAL_ERROR "Error!")
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    Navicat使用教程
    openpnp - 手工修改配置文件(元件高度,size,吸嘴)
    stm32mp157开发板ping通pc虚拟机ubuntu系统,方便nfs挂载根文件系统
    最新报错注入攻击和代码分析技术
    AXI协议(1):AMBA总线介绍,AXI概念与背景介绍,AXI协议特点与功能
    学Git先看看这一篇
    springboot + rabbitmq + redis实现秒杀
    docker(4)-容器
    git 回滚到指定版本
    windows平台下的mysql启动等基本操作
  • 原文地址:https://blog.csdn.net/u011436427/article/details/125472458