现代CMake高级教程 - 第 10 章:变量与作用域

双笙子佯谬老师的【公开课】现代CMake高级教程课程笔记

第 10 章:变量与作用域

变量的传播规则

父会传给子

父模块里定义的变量,会传递给子模块。

❯ tree
.
├── CMakeLists.txt
└── m
    └── CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)

set(MYVAR ON)
add_subdirectory(mylib)

m/CMakeLists.txt

message("MYVAR: ${MYVAR}")

生成结果:

MYVAR: ON
子不传给父

但是子模块里定义的变量,不会传递给父模块。

❯ tree
.
├── CMakeLists.txt
└── m
    └── CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
add_subdirectory(mylib)
message("MYVAR: ${MYVAR}")

m/CMakeLists.txt

set(MYVAR ON)

生成结果:

MYVAR:
同名变量

如果父模块里本来就定义了同名变量,则离开子模块后仍保持父模块原来设置的值。

❯ tree
.
├── CMakeLists.txt
└── m
    └── CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)

set(MYVAR OFF)
add_subdirectory(mylib)
message("MYVAR: ${MYVAR}")

m/CMakeLists.txt

set(MYVAR ON)

生成结果:

MYVAR: OFF
子模块向父模块里传变量

可以用 set 的 PARENT_SCOPE 选项,把一个变量传递到上一层作用域(也就是父模块)。

❯ tree
.
├── CMakeLists.txt
└── m
    └── CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)

set(MYVAR OFF)
add_subdirectory(mylib)
message("MYVAR: ${MYVAR}")

m/CMakeLists.txt

set(MYVAR ON PARENT_SCOPE)

生成结果:

MYVAR: ON

如果父模块里没有定义 MYVAR 的话,也可以用缓存变量向外部传变量(不推荐)。但是这样就不光父模块可见了,父模块的父模块,到处都可见。

❯ tree
.
├── CMakeLists.txt
└── m
    └── CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)

add_subdirectory(mylib)
message("MYVAR: ${MYVAR}")

m/CMakeLists.txt

set(MYVAR ON CACHE BOOL "" FORCE)

生成结果:

MYVAR: ON

带独立作用域的模块

  • add_subdirectory 的 CMakeLists.txt
  • function (因此 PARENT_SCORE 也可以用于 function 的返回值)

环境变量

环境变量的访问方式:$ENV{xx}

${xx} 访问的是局部变量,局部变量服从刚刚所说的父子模块传播规则。而还有一种特殊的方式可以访问到系统的环境变量(environment variable):$ENV{xx}。比如 $ENV{PATH} 就是获取 PATH 这个环境变量的值。

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(hellocmake)

message("PATH is: $ENV{PATH}")

生成结果:

[cmake] PATH is: /home/ethan/.vscode-server/bin/704ed70d4fd1c6bd6342c436f1ede30d1cff4710/bin/remote-cli:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/mnt/c/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v11.6/bin:/mnt/c/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v11.6/libnvvp:/mnt/c/Program Files/Oculus/Support/oculus-runtime:/mnt/c/Program Files (x86)/VMware/VMware Workstation/bin/:/mnt/c/Windows/system32:/mnt/c/Windows:/mnt/c/Windows/System32/Wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0/:/mnt/c/Windows/System32/OpenSSH/:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA NvDLISR:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files/nodejs/:/mnt/c/Users/ethan/AppData/Local/Packages/PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0/LocalCache/local-packages/Python39/Scripts:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Program Files/Microsoft VS Code/bin:/mnt/c/Program Files/Git/cmd:/mnt/c/Users/ethan/AppData/Local/Android/Sdk/platform-tools:/mnt/c/Users/ethan/AppData/Local/Android/Sdk/tools:/mnt/c/Program Files/010 Editor:/mnt/c/Program Files/JDK14.0.2/bin:/mnt/c/Users/ethan/anaconda3:/mnt/c/Users/ethan/anaconda3/Scripts:/mnt/c/Users/ethan/anaconda3/Library/bin:/mnt/c/Program Files/Calibre2/:/mnt/c/Program Files/PuTTY/:/mnt/c/Users/ethan/AppD:/mnt/c/Program Files/NVIDIA Corporation/Nsight Compute 2022.1.0/:/mnt/c/Program Files/dotnet/:/mnt/c/Windows/system32:/mnt/c/Windows:/mnt/c/Windows/System32/Wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0/:/mnt/c/Windows/System32/OpenSSH/:/mnt/c/Program Files (x86)/Windows Kits/8.1/Windows Performance Toolkit/:/mnt/c/Program Files (x86)/ZeroTier/One/:/mnt/c/Users/ethan/AppData/Local/Android/Sdk/cmake/3.22.1/bin:/mnt/c/Program Files/BaiduPCS-Go-v3.8.7-windows-x64:/mnt/c/Program Files/rclone-v1.60.1-windows-amd64:/mnt/c/Users/ethan/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/ethan/AppData/Roaming/npm:/mnt/c/Program Files/JetBrains/IntelliJ IDEA Community Edition 2022.1.2/bin
[cmake] -- Configuring done
[cmake] -- Generating done

缓存变量

缓存变量的访问方式:$CACHE{xx}

此外,还可以用 $CACHE{xx} 来访问缓存里的 xx 变量。缓存变量和环境变量是不论父子模块都共用的,没有作用域一说。

cmake_minimum_required(VERSION 3.15)
project(hellocmake)

message("CMAKE_BUILD_TYPE is: $CACHE{CMAKE_BUILD_TYPE}")

生成结果:

[cmake] CMAKE_BUILD_TYPE is: Debug
[cmake] -- Configuring done
[cmake] -- Generating done

${xx} 当找不到名为 xx 的局部变量时,就会去在缓存里查找名为 xx 的缓存变量。因此这里 CMAKE_BUILD_TYPE 虽然在代码里没被 set,但是他被 -D 参数固定在缓存里了。所以 ${CMAKE_BUILD_TYPE} 自动变成 $CACHE{CMAKE_BUILD_TYPE} 从而找到变量。

cmake_minimum_required(VERSION 3.15)
project(hellocmake)

message("CMAKE_BUILD_TYPE is: ${CMAKE_BUILD_TYPE}")

生成结果:

[cmake] CMAKE_BUILD_TYPE is: Debug
[cmake] -- Configuring done
[cmake] -- Generating done

变量是否存在

if (DEFINED MYVAR) 可以判断是否存在 MYVAR 这个局部变量或缓存变量。

cmake_minimum_required(VERSION 3.15)
project(hellocmake)

if (DEFINED MYVAR)
	message("MYVAR is ${MYVAR}")
else()
	message("MYVAR is not defined")
endif()

生成结果:

MYVAR is not defined
cmake_minimum_required(VERSION 3.15)
project(hellocmake)

set(MYVAR "")
if (DEFINED MYVAR)
	message("MYVAR is ${MYVAR}")
else()
	message("MYVAR is not defined")
endif()

生成结果:

MYVAR is:

可以直接用 if (xx) 来判断是否为空字符串,因为空字符串等价于 FALSE。

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(hellocmake)

set(MYVAR "")
if (MYVAR)
	message("MYVAR is ${MYVAR}")
else()
	message("MYVAR is empty or not defined")
endif()

生成结果:

MYVAR is empty or not defined

if (DEFINED ENV{xx}) 判断某环境变量是否存在。因为 $ENV{xx} 代表环境变量,因此在 set 和 if 中也可以用 ENV{xx} 来表示环境变量。

因为 set 的第一参数和 if 的参数都是不加 $ 的,所以要设置 ${x} 就变成了 set(x …)。而设置 $ENV{x} 自然就是 set(ENV{x} ...) 咯。

同理还可以用 if (DEFINED CACHE{x}) 判断是否存在这个缓存变量,但是 set(CACHE{x} ...) 就不行。

cmake_minimum_required(VERSION 3.15)
project(hellocmake)

set(ENV{MYVAR} "hello")
if (DEFINED ENV{MYVAR})
	message("MYVAR is $ENV{MYVAR}")
else()
	message("MYVAR is empty or not defined")
endif()
MYVAR is: hello

从 bash 设置环境变量

cmake_minimum_required(VERSION 3.15)
project(hellocmake)

if (DEFINED ENV{MYVAR})
	message("MYVAR is $ENV{MYVAR}")
else()
	message("MYVAR is empty or not defined")
endif()
export MYVAR=world
❯ cmake -B build
MYVAR is world
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/h/Code/lessonCode/CMakeLession/build

你可能感兴趣的:(CMake,C,CMake,C++)