CMake 从入门到崩溃2 - 基础语法之CMake变量

CMake 从入门到崩溃2 - 基础语法之CMake变量

CMake 中变量名大小写敏感,且可以由任何字符组成

🔑 最佳实践
仅在当前作用域中使用的本地变量用简短的小写命名,在多个作用域中使用的变量用详细的大写命名

变量评估

CMake 中变量都是“字符串化”的,用 ${} 包裹一个变量会用变量的值来替换它,CMake 将这个解引用的过程称作变量评估(variable evaluation)

变量评估将发生在接受该表达式做参数的命令执行之前,因此如果对列表解引用,那么可能产生多个命令参数

变量解引用可以被嵌套使用,比如

set(var_name var1)
set(${var_name} foo) # same as "set(var1 foo)"
set(${${var_name}}_var bar) # same as "set(foo_var bar)"

解引用一个未设置的变量将结果为空,因此可以这样使用

if(APPLE)
  set(extra_sources Apple.cpp MacOS.cpp)
endif()
add_executable(HelloWorld HelloWorld.cpp ${extra_sources})

在 APPLE 以外的平台下执行这段命令将导致 ${extra_sources} 的结果为空,不会将额外参数传递给 add_executable

if语句和变量评估

条件判断中,如果条件是 1ONYESTRUEY 或非零数字则执行该分支

if ("VAR")
  message(TRUE)
else()
  message(FALSE)
endif()

if ("y")
  message(TRUE)
else()
  message(FALSE)
endif()

上面两段代码的输出是 FALSETRUE

条件判断语句会对我们给出的条件做自动评估,但放到引号中的符号会被当做字符串看待,不会执行自动评估

set(var1 OFF)
set(var2 "var1")

if(${var2})
    message("hello 1")
endif()

if(var2)
    message("hello 2")
endif()

输出为 hello 2

变量类型

缓存下来或通过命令行指定的变量可以有一个相关联的类型,这个类型被 CMake 的 GUI 工具用于显示正确的输入框

变量的类型通常不会影响变量评估,但如果命令行中指定的变量类型为 PATHFILEPATH,且变量的值为相对路径,那么 CMake 会当它相对于当前工作目录,并将它转换为绝对路径

列表

在 CMake 中列表是分号隔开的字符串,因此不应该在列表元素中使用分号,创建列表的例子

# Creates a list with members a, b, c, and d
set(my_list a b c d)
set(my_list "a;b;c;d")

# Creates a string "a b c d"
set(my_string "a b c d")

列表操作

可以用 list 命令对列表做读取、查找、修改和排序操作

  • 对于表示元素下标的参数,可以使用 -1 取最后一个元素,以此类推

列表的列表

因为列表的元素不能包含分号,因此如果要创建列表的列表,你必须创建一系列变量以引用子列表,比如

set(list_of_lists a b c)
set(a 1 2 3)
set(b 4 5 6)
set(c 7 8 9)

遍历列表的列表,打印每个值

foreach(list_name IN LISTS list_of_lists)
  foreach(value IN LISTS ${list_name})
    message(${value})
  endforeach()
endforeach()

先解引用出出子列表的名字,再解引用出子列表元素;这个模式在 CMake 中被广泛使用

  • 最常见的例子是 CMake 指定编译器选项时,会使用到
    • CMAKE_${LANGUAGE}_FLAGS
    • CMAKE_${LANGUAGE}_FLAGS_${CMAKE_BUILD_TYPE}

环境变量

  • 读取环境变量 VAR
    • $ENV{VAR}
  • 判断环境变量是否被定义
    • if(DEFINED ENV{<name>})
    • DEFINED 也可以用来检查任意变量是否被定义

🔑 CMake 不会跟踪环境变量的变化,因此不要在你的代码中使用可能被改变的环境变量

设置环境变量

set(ENV{<variable>} [<value>])

只影响当前 CMake 进程,不影响调用 CMake 的进程、整体的系统环境,以及后续的构建和测试进程的环境

如果没有给出 value 参数或 value 参数为空字符串,那么该命令会清除掉现有环境变量的值

Cache 变量

set(MY_FUCKING_CACHE_VAR HELLO_HELLO 
	CACHE STRING a_fucking_cache_variable)

将导致CMakeCache.txt中产生:

//a_fucking_cache_variable
MY_FUCKING_CACHE_VAR:STRING=HELLO_HELLO

注意,如果 MY_FUCKING_CACHE_VAR 已经存在于 CACHE 中了,那么 set 操作不会产生任何效果,除非你指定 FORCE 选项,但这往往意味着你 CMake 项目的设计有问题

🔑 最佳实践
由于 Cache 变量的全局性,你应该在变量名的前面加上项目名前缀以避免冲突

运行 CMake 时,如果传递 -D 选项,CMake 会用它创建或修改 Cache 变量

  • 比如执行 cmake .. -DMY_FUCKING_CACHE_VAR=RUN 后,再打开 CMakeCache.txt ,就会发现变量的值变为了 RUN
  • 一般在 CMake 文件中通过 set(...CACHE) 设置某个选项的默认值,让用户用 -D 传进来他们的自定义值
    • 由于 -D 写入 Cache 变量先于我们的 CMake 文件解析,因此不加 FORCE 的 set 命令不会再去修改 -D 写入的 Cache 内容
  • 如果有很多变量都要通过 -D 来设置,可以将它们放到一个单独的文件里,并用-C 选项加载

Cache 变量和普通变量的交互

  • ${VAR} 做变量评估时,CMake 会优先去寻找叫这个名字的普通变量,找不到才会去找 Cache 变量
  • 显式地指定读取 Cache 变量:$CACHE{VAR}
  • 设置 Cache 变量时,如果当前作用域下有同名普通变量,则该普通变量会被移除
    • 这个移除普通变量的行为在 CMake3.21 里被标记为废弃(CMP0126)

Option

option 命令可以用来创建一个布尔值 Cache 项,供用户选择是 ON 还是 OFF

option(<variable> "<help_text>" [value])
posted @ 2022-02-27 00:38  路过的摸鱼侠  阅读(586)  评论(0编辑  收藏  举报