《CMakeList 知识系统学习系列(二):变量的定义、作用域和使用》

160 阅读4分钟

前面我们学习了CMakeLists.txt基本构建流程。现在从基础的变量开始学习。

一、变量的类型

根据变量的作用域和生命周期类型,CMake变量分为三种主要类型

变量类型定义方式作用域生命周期典型用途
普通变量set(var value)当前作用域(函数/目录)作用域结束时销毁临时存储中间值、局部配置
缓存变量set(var value CACHE ...)全局作用域持久化到 CMakeCache.txt用户可配置选项(如安装路径)
环境变量$ENV{var}进程环境变量进程生命周期读取系统环境(如PATH)

二、变量的定义与操作

普通变量

定义和赋值

定义主要是通过set命令设置

set命令基本语法如下

set(<variable> <value>... [PARENT_SCOPE])
  • <variable>:这是要设置的变量名称。变量名通常采用大写字母,不过大小写均可,只是为了增强可读性和遵循一定的规范,一般用大写。
  • <value>...:代表要赋给变量的值。可以是单个值,也可以是多个值,多个值之间用空格分隔。
  • [PARENT_SCOPE]:这是一个可选参数。若指定了该参数,变量将会被设置在父作用域中,而非当前作用域。
SET(HELLO “Hello World”)#定义普通变量
SET(MY_LIST a b c)#定义列表变量
message(STATUS "HELLO:${HELLO}")
message(STATUS "MY_LIST:${MY_LIST}")

作用域规则

  • 在函数、宏或子目录中使用 set(),默认仅影响当前作用域。
  • 目录作用域:在 add_subdirectory() 进入子目录时,父目录的变量会拷贝到子目录作用域,但子目录的修改不会影响父目录。
输出
cmake -B build
-- HELLO:Hello World
-- MY_LIST:a;b;c

列表打印的时候打印的是一个整体。如果我们想挨个遍历。则可以用foreach

foreach(item ${MY_LIST})
    message("List item: ${item}")
endforeach()

此时的输出就是

List item: a
List item: b
List item: c

foreach语句暂时知道可以打印列表就好。后面在详细介绍。

缓存变量

定义与类型

set(<variable> <value> CACHE <type> <docstring> [FORCE])

例如

set(MY_CACHE_VARIABLE "first value" CACHE STRING "A cached variable")

STRING 表示变量的类型,后面的字符串是对该变量的描述。

message(STATUS "MY_CACHE_VARIABLE:${MY_CACHE_VARIABLE}")

输出
-- MY_CACHE_VARIABLE:first value

当使用 CACHE 关键字时,变量会被存储在 CMake 的缓存中。这样一来,用户在运行 CMake 时可以通过 -D 选项来修改这个变量的值。

cmake -DMY_CACHE_VARIABLE="new value" ..

当执行上面语句后。再cmake -B build

输出

-- MY_CACHE_VARIABLE:new value

后续MY_CACHE_VARIABLE变量如果没有通过-D改变。就一直不变。

若缓存变量已存在,再次运行 set(... CACHE ...) 不会覆盖旧值,除非使用 FORCE 。

当然如果删除了整个build文件夹。MY_CACHE_VARIABLE又会恢复成最新的那个first value值。

常见变量类型及示例

1. STRING 类型

STRING 类型用于存储任意字符串值,是最常用的类型之一。

cmake

set(MY_STRING_VARIABLE "default value" CACHE STRING "This is a string cache variable")
message("Value of MY_STRING_VARIABLE: ${MY_STRING_VARIABLE}")

在上述代码中,定义了一个名为 MY_STRING_VARIABLE 的缓存变量,初始值为 "default value",类型为 STRING,并给出了相应的描述信息。之后使用 message 命令输出该变量的值。

2. BOOL 类型

BOOL 类型用于存储布尔值,通常用于控制某些特性的开关。

set(MY_BOOL_VARIABLE ON CACHE BOOL "Enable or disable a certain feature")
if(MY_BOOL_VARIABLE)
    message("Feature is enabled.")
else()
    message("Feature is disabled.")
endif()

这里定义了一个名为 MY_BOOL_VARIABLE 的缓存变量,初始值为 ON,表示启用某个特性。通过 if 语句根据该变量的值输出不同的信息。

3. FILEPATH 类型

FILEPATH 类型用于存储文件路径,在 CMake GUI 中会提供文件选择对话框。

set(MY_FILE_VARIABLE "" CACHE FILEPATH "Select a file")
message("Selected file: ${MY_FILE_VARIABLE}")

此代码定义了一个名为 MY_FILE_VARIABLE 的缓存变量,初始值为空,类型为 FILEPATH。用户可以在 CMake GUI 中选择一个文件来设置该变量的值。

4. PATH 类型

PATH 类型用于存储目录路径,在 CMake GUI 中会提供目录选择对话框。

set(MY_PATH_VARIABLE "" CACHE PATH "Select a directory")
message("Selected directory: ${MY_PATH_VARIABLE}")

这里定义了一个名为 MY_PATH_VARIABLE 的缓存变量,初始值为空,类型为 PATH。用户可以在 CMake GUI 中选择一个目录来设置该变量的值。

作用域

缓存变量具有全局作用域,在整个 CMake 项目中都可以访问。

缓存变量的优先级

  • 缓存变量会覆盖普通变量(同名时),但可以通过 FORCE 强制覆盖缓存变量:

    set(USE_GPU OFF CACHE BOOL "Override cache" FORCE)
    

3. 环境变量

环境变量的概念

环境变量是操作系统层面的一种全局变量,在不同的操作系统中都有相应的实现。例如在 Linux 和 macOS 系统中,环境变量可以通过 export 命令设置;在 Windows 系统中,可以通过系统属性或命令提示符中的 set 命令设置。这些环境变量在系统的不同进程和程序中都可以被访问和使用,CMake 也不例外。

在 CMake 中,可以使用 $ENV{<variable>} 语法来访问环境变量,其中 <variable> 是环境变量的名称

  • 设置临时设置环境变量,这种设置只在当前 CMake 运行期间有效

    set(ENV{MY_VARIABLE} "Hello, CMake!")
    
  • 读取环境变量

    message("MY_VARIABLE is: $ENV{MY_VARIABLE}")  
    
  • 修改系统环境变量

    set(ENV{LD_LIBRARY_PATH} "/opt/libs:$ENV{LD_LIBRARY_PATH}")  # 仅在当前 CMake 进程生效
    

这种设置方式只会影响当前 CMake 进程及其子进程,不会对系统的全局环境变量产生持久影响。

常见应用场景

配置依赖库路径

当项目依赖一些外部库时,这些库的安装路径可能在不同的机器上有所不同。可以通过环境变量来指定这些库的路径,从而提高项目的可移植性。例如:

# 读取环境变量指定的库路径
set(LIB_PATH $ENV{MY_LIB_PATH})
if(LIB_PATH)
    include_directories(${LIB_PATH}/include)
    link_directories(${LIB_PATH}/lib)
else()
    message(FATAL_ERROR "未设置 MY_LIB_PATH 环境变量,请设置该变量指向依赖库的安装路径。")
endif()

控制构建行为

可以通过环境变量来控制 CMake 的构建行为,比如选择不同的构建类型(Debug 或 Release)。示例如下:

# 根据环境变量选择构建类型
set(BUILD_TYPE $ENV{BUILD_TYPE})
if(NOT BUILD_TYPE)
    set(BUILD_TYPE "Release")
endif()
set(CMAKE_BUILD_TYPE ${BUILD_TYPE})
message(STATUS "当前构建类型为: ${CMAKE_BUILD_TYPE}")

注意事项

  • 可移植性:不同操作系统设置和使用环境变量的方式可能有所不同,在编写跨平台的 CMake 脚本时需要注意这一点。
  • 安全性:由于环境变量可以被用户手动修改,在使用环境变量时要确保进行必要的验证和错误处理,避免因为环境变量设置错误而导致构建失败。

三 、CMake内部变量

在 CMake 中,内部变量扮演着非常重要的角色,它们能够帮助开发者对项目的构建过程进行灵活的配置和控制。以下从常见的内部变量类型

变量名变量说明
PROJECT_NAME返回通过PROJECT指令定义的项目名称
PROJECT_SOURCE_DIRCMake源码地址,即cmake命令后指定的地址
PROJECT_BINARY_DIR运行cmake命令的目录,通常是PROJECT_SOURCE_DIR下的build目录
CMAKE_MODULE_PATH定义自己的cmake模块所在的路径
CMAKE_CURRENT_SOURCE_DIR当前处理的CMakeLists.txt所在的路径
CMAKE_CURRENT_LIST_DIR当前文件夹路径
CMAKE_CURRENT_LIST_FILE输出调用这个变量的CMakeLists.txt的完整路径
CMAKE_CURRENT_LIST_LINE输出这个变量所在的行
CMAKE_RUNTIME_OUTPUT_DIRECTORY生成可执行文件路径
CMAKE_LIBRARY_OUTPUT_DIRECTORY生成库的文件夹路径
CMAKE_BUILD_TYPE指定基于make的生成器的构建类型(Release,Debug)
CMAKE_C_FLAGS*.C文件编译选项,如 -std=c99 -O3 -march=native
CMAKE_CXX_FLAGS*.CPP文件编译选项,如 -std=c++11 -O3 -march=native
CMAKE_CURRENT_BINARY_DIRtarget编译目录
CMAKE_INCLUDE_PATH环境变量,非cmake变量
CMAKE_LIBRARY_PATH环境变量
CMAKE_STATIC_LIBRARY_PREFIX静态库前缀, Linux下默认为lib
CMAKE_STATIC_LIBRARY_SUFFIX静态库后缀,Linux下默认为.a
CMAKE_SHARED_LIBRARY_PREFIX动态库前缀,Linux下默认为lib
CMAKE_SHARED_LIBRARY_SUFFIX动态库后缀,Linux下默认为.so
BUILD_SHARED_LIBS如果为ON,则add_library默认创建共享库
CMAKE_INSTALL_PREFIX配置安装路径,默认为/usr/local
CMAKE_ABSOLUTE_DESTINATION_FILES安装文件列表时使用ABSOLUTE DESTINATION 路径
CMAKE_AUTOMOC_RELAXED_MODE在严格和宽松的automoc模式间切换
CMAKE_BACKWARDS_COMPATIBILITY构建工程所需要的CMake版本
CMAKE_COLOR_MAKEFILE开启时,使用Makefile产生器会产生彩色输出
CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS用来控制IF ELSE语句的书写方式