CMake中的set命令用于将普通、缓存或环境变量(normal, cache, or environment variable)设置为给定值,其格式如下:指定
- set(
... [PARENT_SCOPE]) - set(
... CACHE <type> [FORCE]) - set(ENV{
} [])
变量是CMake语言中的基本存储单元(basic unit of storage)。它们的值始终是字符串类型,尽管某些命令可能会将字符串解释为其它类型的值。set和unset命令显式设置或取消设置变量,但其它命令也具有修改变量的语义(semantics)。变量名称区分大小写,几乎可以包含任何文本,但建议使用仅有字母数字字符加上"_"和"-"组成的名称。
变量具有动态范围(dynamic scope)。每个变量"set"和"unset"在当前范围内创建一个绑定(creates a binding):
(1).Function Scope:由function命令创建的命令定义在调用时会在新的变量绑定范围内(new variable binding scope)处理记录的命令。变量"set"或"unset"绑定在此范围内,对当前函数和其中的任何嵌套调用可见,但在function返回后不可见。
(2).Directory Scope:源树(source tree)中的每个目录都有自己的变量绑定。在处理目录的CMakeLists.txt文件之前,CMake会复制当前在父目录(parent directory)中定义的所有变量绑定以初始化新目录范围。CMake脚本,当使用cmake -P时,将变量绑定在一个"directory"范围内。不在function调用内的变量"set"或"unset"绑定到当前目录范围。
(3).Persistent Cache(持久缓存):CMake存储一组单独的"cache"变量或"cache entries(缓存条目)",其值在project构建树中的多次运行中保持不变。cache entries有一个独立的绑定范围,仅由显式请求(explicit request)修改,例如set和unset命令的CACHE选项。
Variable References(变量引用):其形式为${
环境变量引用(environment variable reference)的格式为:$ENV{
缓存变量引用(cache variable reference)的格式为:$CACHE{
if命令有一个特殊的条件语法,它允许以短格式
在评估变量引用时,CMake首先在function调用堆栈(如果有)中搜索绑定,然后返回到当前目录范围内搜索绑定(如果有)。如果找到"set"绑定,则使用其值。如果找到"unset"绑定,或者没有找到绑定,CMake然后搜索缓存条目。如果找到缓存条目,则使用其值。否则,变量引用的的计算结果为空字符串。$CACHE{VAR}语法可用于直接查找缓存条目。
Environment Variables:和普通变量一样,有以下区别:
(1).Scope:环境变量在CMake过程(process)中具有全局范围。它们永远不会被缓存。
(2).References:变量引用的形式为$ENV{
(3).Initialization:CMake环境变量的初始值是调用进程(process)的初始值。可以使用set和unset命令更改值。这些命令只影响正在运行的CMake进程,而不影响整个系统环境(system environment).更改的值不会写回调用进程,后续构建或测试进程也看不到它们。
Set Normal Variable:在当前function或目录范围内设置给定的
- function(func)
- set(func_var1 "hello")
- set(func_var2 "beijing" PARENT_SCOPE)
- endfunction()
-
- set(var a b c d e) # create a list
- message("var: ${var}") # var: a;b;c;d;e
-
- set(var "a b c d e") # creates a string or a list with one item in it
- message("var: ${var}") # var: a b c d e
-
- message("func_var1: ${func_var1}") # func_var1:
- message("func_var2: ${func_var2}") # func_var2:
- func()
- message("func_var1: ${func_var1}") # func_var1:
- message("func_var2: ${func_var2}") # func_var2: beijing
-
- if(DEFINED func_var1)
- message("defined func_var1") # won't print
- endif()
- if(DEFINED func_var2)
- message("defined func_var2") # print
- endif()
-
- set(var )
- if(DEFINED var)
- message("defined var") # won't print
- endif()
Set Cache Entry:设置给定的cache
(1).BOOL:布尔值:ON/OFF
(2).FILEPATH:磁盘上文件的路径
(3).PATH:磁盘上目录的路径
(4).STRING:一行文字
(5).INTERNAL:一行文字,用于内部。它们可用于在运行之间持久存储变量。使用这种类型意味着FORCE
如果在调用之前缓存条目不存在或给出了FORCE选项,则缓存条目将设置为给定值。
如果已经存在同名的普通变量,则缓存变量的内容将无法直接访问。
cache变量信息会存入CMakeCache.txt.
- set(var "csdn addr" CACHE STRING "https://blog.csdn.net/fengbingchun")
- message("var: ${var}") # var: csdn addr
- set(var "github addr" CACHE STRING "https://github.com/fengbingchun") # 默认情况下不会覆盖现有的缓存条目
- message("var: ${var}") # var: csdn addr
-
- set(var "github addr" CACHE STRING "https://github.com/fengbingchun" FORCE) # 使用FORCE选项覆盖现有条目
- message("var: ${var}") # var: github addr
-
- # 如果已经存在同名的普通变量,则缓存变量的内容将无法直接访问
- set(var2 "hello")
- set(var2 "beijing" CACHE STRING "addr")
- message("var2: ${var2}") # var2: hello
- set(var2 "beijing" CACHE STRING "addr" FORCE)
- message("var2: ${var2}") # var2: hello
-
- unset(var2)
- set(var2 "beijing" CACHE STRING "addr" FORCE)
- message("var2: ${var2}") # var2: beijing
Set Environment Variable: 将Environment Variable设置为给定值。随后的$ENV{
如果在ENV{
- set(ENV{CMAKE_PREFIX_PATH} "github/fengbingchun")
- message("CMAKE_PREFIX_PATH: $ENV{CMAKE_PREFIX_PATH}") # CMAKE_PREFIX_PATH: github/fengbingchun
-
- set(ENV{CMAKE_PREFIX_PATH} github/fengbingchun Linux_Code_Test) # CMake Warning (dev) at test_set.cmake:59 (set):
- # Only the first value argument is used when setting an environment variable.
- # Argument 'Linux_Code_Test' and later are unused.
CMake中的unset命令用于取消设置变量、缓存变量或环境变量(variable, cache variable, or environment variable),其格式如下:
- unset(
[CACHE | PARENT_SCOPE]) - unset(ENV{
})
Unset Normal Variable or Cache Entry:从当前范围中删除一个普通变量,使其变为未定义。如果存在CACHE,则删除缓存变量而不是普通变量。注意:在评估(evaluating)${VAR}形式的变量引用时,CMake首先搜索具有该名称的普通变量。如果不存在这样的普通变量,则CMake将搜索具有该名称的缓存条目(cache entry)。因此,unsetting普通变量可以暴露以前隐藏的缓存变量。要强制${VAR}形式的变量引用返回空字符串,使用set(
如果PARENT_SCOPE存在,则该变量将从当前范围之上的范围中删除。
- set(var "hello")
- unset(var)
- if(NOT DEFINED var)
- message("no defined var") # print
- else()
- message("defined var")
- endif()
-
- func()
- message("func_var2: ${func_var2}") # func_var2: beijing
- unset(func_var2)
- if(DEFINED func_var2)
- message("defined func_var2") # won't print
- endif()
Unset Environment Variable:从当前可用的环境变量中删除
- set(ENV{CMAKE_PREFIX_PATH} "github/fengbingchun")
- message("CMAKE_PREFIX_PATH: $ENV{CMAKE_PREFIX_PATH}") # CMAKE_PREFIX_PATH: github/fengbingchun
- unset(ENV{CMAKE_PREFIX_PATH})
- message("CMAKE_PREFIX_PATH: $ENV{CMAKE_PREFIX_PATH}") # CMAKE_PREFIX_PATH:
执行上述测试代码需要3个文件:build.sh, CMakeLists.txt, test_set.cmake
build.sh内容如下:
- #! /bin/bash
-
- # supported input parameters(cmake commands)
- params=(function macro cmake_parse_arguments \
- find_library find_path find_file find_program find_package \
- cmake_policy cmake_minimum_required project include \
- string list set foreach message option if)
-
- usage()
- {
- echo "Error: $0 needs to have an input parameter"
-
- echo "supported input parameters:"
- for param in ${params[@]}; do
- echo " $0 ${param}"
- done
-
- exit -1
- }
-
- if [ $# != 1 ]; then
- usage
- fi
-
- flag=0
- for param in ${params[@]}; do
- if [ $1 == ${param} ]; then
- flag=1
- break
- fi
- done
-
- if [ ${flag} == 0 ]; then
- echo "Error: parameter \"$1\" is not supported"
- usage
- exit -1
- fi
-
- if [[ ! -d "build" ]]; then
- mkdir build
- cd build
- else
- cd build
- fi
-
- echo "==== test $1 ===="
-
- # test_set.cmake: cmake -DTEST_CMAKE_FEATURE=$1 --log-level=verbose ..
- # test_option.cmake: cmake -DTEST_CMAKE_FEATURE=$1 -DBUILD_PYTORCH=ON ..
- cmake -DTEST_CMAKE_FEATURE=$1 ..
- # It can be executed directly on the terminal, no need to execute build.sh, for example: cmake -P test_set.cmake
CMakeLists.txt内容如下:
- cmake_minimum_required(VERSION 3.22)
- project(cmake_feature_usage)
-
- message("#### current cmake version: ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
- include(test_${TEST_CMAKE_FEATURE}.cmake)
- message("==== test finish ====")
test_set.cmake:为上面的所有示例代码
可能的执行结果如下图所示:
