【CMake】环境变量

目录

一.环境变量简单介绍

1.1.示例1——设置与清除

1.2.示例2——全局唯一性和全局可见性

1.3.示例3

1.4.示例4

1.5.示例5


一.环境变量简单介绍

什么是环境变量?

我们看看官网是怎么说环境变量的:cmake-language(7) — CMake 4.1.1 Documentation

环境变量是操作系统提供给所有运行中程序(进程)的一套全局键值对。

CMake 作为一个程序,在启动时会继承它所在 shell(如命令行终端)的所有环境变量。

CMake 自己也提供了一套机制来操作这些变量。

它与 CMake 普通变量的核心区别如下:

1. 作用域 (Scope)

  • 全局性环境变量在同一个 CMake 进程内部的作用域是全局的。这意味着一旦你设置或修改了一个环境变量,你可以在同一个 CMake 运行过程中的任何地方(无论是在根目录的 CMakeLists.txt,还是在深层子目录的 CMakeLists.txt,或是在任何 .cmake 脚本文件中)访问到它。

  • 不被缓存环境变量不会被存入 CMake 的缓存(即项目根目录下的 CMakeCache.txt 文件)。缓存变量可以通过 set(... CACHE ...) 命令被缓存,从而在多次运行 cmake 时保持值不变。环境变量没有这个特性,每次重新运行 cmake 命令时,环境变量都会重新从外部系统环境中初始化。

2. 引用方式 (References)

  • 你不能像引用普通变量(${MY_VARIABLE})那样直接引用环境变量。

  • 你必须使用特殊的 $ENV{<变量名>} 语法。这里的 ENV 是一个操作符,它告诉 CMake 你要访问的是环境变量,而不是普通变量。

  • 示例: 如果你想获取系统环境变量 PATH 的值,你需要这样写:$ENV{PATH}

3. 初始化和修改 (Initialization)

  • 初始值: 当你在终端输入 cmake ... 命令时,CMake 进程启动那一刻,它所拥有的环境变量集合就是你的终端 shell 当时的环境变量集合的副本。

  • 修改的局限性: 这是最关键的一点。

    • 你可以使用 set(ENV{<变量名>} <值>) 命令来设置或修改一个环境变量。

    • 你也可以使用 unset(ENV{<变量名>}) 命令来删除一个环境变量。

    • 但是,这些修改仅仅发生在当前这个正在运行的 CMake 进程内部! 它会产生以下重要影响:

      • 不影响系统: 它绝对不会改变你操作系统的环境变量,也不会改变你终端 shell 的环境变量。

      • 不回传: 当 CMake 进程结束时,它对环境变量所做的任何修改都会随之消失,不会写回给调用它的父进程(也就是你的终端 shell)。

      • 不影响后续进程: 在 CMake 执行过程中,它可能会启动其他的子进程(例如调用 execute_process 命令,或者编译完成后进行构建和测试)。默认情况下,这些子进程启动时会继承最初从父 shell 那里获得的环境变量副本。但是启动子进程之后,如果父进程又修改了环境变量,那么子进程就看不到修改后的环境变量值(除非使用特定命令,见下一条)。

4. 相关工具 (Tools)

  • cmake -E env: 正因为直接在 CMake 脚本中修改环境变量对后续构建/测试进程无效,CMake 提供了一个命令行工具来解决这个问题。你可以在调用 CMake 时,使用 cmake -E env VAR1=value1 VAR2=value2 <command> ... 来为一个单独的命令临时创建一个修改后的环境,然后在这个新环境中运行该命令。这常用于为 build 或 test 阶段设置特定的环境。

  • cmake -E environment: 这个命令可以列出当前 CMake 进程所能看到的所有环境变量及其值。它是一个非常有用的调试工具,可以帮你确认环境变量的值是否如你所预期。

使用环境变量

我们可以去官网看看是怎么说的:set — CMake 4.1.1 Documentation

set(ENV{<变量名>} [<值>])

该命令用于将环境变量设置为指定值。此后在当前进程中通过 $ENV{<变量名>} 获取该环境变量时,将返回新设置的值。

需要注意的是,此命令仅对当前 CMake 进程有效:

  • 不会影响调用 CMake 的父进程的环境;

  • 不会改变整个系统的环境变量设置;

  • 也不会影响后续构建或测试进程的环境。

如果 ENV{<变量名>} 后未提供参数,或 <值> 为空字符串,则该命令将清除该环境变量当前已存在的值。

若在 <值> 后提供了额外参数,这些参数将被忽略。同时,如果检测到有多余参数存在,CMake 会发出作者警告(author warning)。

1.1.示例1——设置与清除

📂 项目目录结构

env_demo/
└── CMakeLists.txt

🔹 env_demo/CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(EnvVarDemo)# 1. 设置环境变量
set(ENV{MY_ENV_VAR} "hello world")
message("设置后: $ENV{MY_ENV_VAR}")# 2. 清除方式一:赋空字符串
set(ENV{MY_ENV_VAR} "")
message("清除方式一后: '$ENV{MY_ENV_VAR}'")# 3. 再次设置
set(ENV{MY_ENV_VAR} "hello again")
message("再次设置后: $ENV{MY_ENV_VAR}")# 4. 清除方式二:不给值
set(ENV{MY_ENV_VAR})
message("清除方式二后: '$ENV{MY_ENV_VAR}'")

其实我们可以通过下面这个命令来一键搭建出这个目录结构和文件

mkdir -p env_demo && \
cat > env_demo/CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.15)
project(EnvVarDemo)# 1. 设置环境变量
set(ENV{MY_ENV_VAR} "hello world")
message("设置后: $ENV{MY_ENV_VAR}")# 2. 清除方式一:赋空字符串
set(ENV{MY_ENV_VAR} "")
message("清除方式一后: '$ENV{MY_ENV_VAR}'")# 3. 再次设置
set(ENV{MY_ENV_VAR} "hello again")
message("再次设置后: $ENV{MY_ENV_VAR}")# 4. 清除方式二:不给值
set(ENV{MY_ENV_VAR})
message("清除方式二后: '$ENV{MY_ENV_VAR}'")
EOF

接下来我们就来搭建我们的项目

rm -rf build && mkdir build && cd build && cmake ..

两种清理方式都是没有问题的!!

1.2.示例2——全局唯一性和全局可见性

项目结构

demo/
├── CMakeLists.txt              # 顶层
├── subdir/
│   ├── CMakeLists.txt          # 子目录
│   └── subsubdir/
│       ├── CMakeLists.txt      # 子子目录
│       └── helper.cmake        # 脚本

顶层 CMakeLists.txt

cmake_minimum_required(VERSION 3.18)
project(GlobalEnvDemo)# 在顶层设置环境变量
set(ENV{MY_VAR} "HelloFromTop")
message(STATUS "顶层看到的 MY_VAR: '$ENV{MY_VAR}'")# 进入子目录
add_subdirectory(subdir)# 在所有子目录之后再打印一次,看看是否被修改过
message(STATUS "顶层最后看到的 MY_VAR: '$ENV{MY_VAR}'")

子目录 subdir/CMakeLists.txt

# 子目录也能访问
message(STATUS "子目录看到的 MY_VAR: '$ENV{MY_VAR}'")# 进入子子目录
add_subdirectory(subsubdir)

子子目录 subdir/subsubdir/CMakeLists.txt

# 子子目录访问环境变量
message(STATUS "子子目录看到的 MY_VAR: '$ENV{MY_VAR}'")# 在子子目录里修改环境变量
set(ENV{MY_VAR} "ModifiedInSubSubDir")
message(STATUS "子子目录修改后的 MY_VAR: '$ENV{MY_VAR}'")# 引入 helper 脚本
include(helper.cmake)

脚本 subdir/subsubdir/helper.cmake

# helper.cmake 也能看到修改过的值
message(STATUS "helper.cmake 看到的 MY_VAR: '$ENV{MY_VAR}'")

我们可以运行下面这个bash语句来一键搭建出这个目录结构和文件

mkdir -p demo/subdir/subsubdir && \
cat > demo/CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.18)
project(GlobalEnvDemo)# 在顶层设置环境变量
set(ENV{MY_VAR} "HelloFromTop")
message(STATUS "顶层看到的 MY_VAR: '$ENV{MY_VAR}'")# 进入子目录
add_subdirectory(subdir)# 在所有子目录之后再打印一次,看看是否被修改过
message(STATUS "顶层最后看到的 MY_VAR: '$ENV{MY_VAR}'")
EOFcat > demo/subdir/CMakeLists.txt <<'EOF'
# 子目录也能访问
message(STATUS "子目录看到的 MY_VAR: '$ENV{MY_VAR}'")# 进入子子目录
add_subdirectory(subsubdir)
EOFcat > demo/subdir/subsubdir/CMakeLists.txt <<'EOF'
# 子子目录访问环境变量
message(STATUS "子子目录看到的 MY_VAR: '$ENV{MY_VAR}'")# 在子子目录里修改环境变量
set(ENV{MY_VAR} "ModifiedInSubSubDir")
message(STATUS "子子目录修改后的 MY_VAR: '$ENV{MY_VAR}'")# 引入 helper 脚本
include(helper.cmake)
EOFcat > demo/subdir/subsubdir/helper.cmake <<'EOF'
# helper.cmake 也能看到修改过的值
message(STATUS "helper.cmake 看到的 MY_VAR: '$ENV{MY_VAR}'")
EOF

现在我们就来构建我们的项目

rm -rf build && mkdir build && cd build && cmake ..


✅ 这就展示了:

  1. 环境变量在同一个 CMake 进程里是 全局可见的

  2. 子子目录修改了环境变量之后,顶层 CMakeLists.txt 后续部分也能看到修改后的值

1.3.示例3

初始值: 当你在终端输入 cmake ... 命令时,CMake 进程启动那一刻,它所拥有的环境变量集合就是你的终端 shell 当时的环境变量集合的副本。

案例1

在你的 终端 里先设置一个环境变量,例如

export MY_VAR=HelloFromShell

写一个简单的 CMakeLists.txt

cmake_minimum_required(VERSION 3.18)
project(InitEnvDemo)# 打印 CMake 启动时继承的环境变量
message(STATUS "CMake 看到的 MY_VAR: '$ENV{MY_VAR}'")

运行:

mkdir build && cd build && cmake ..

运行结果

结论

CMake 启动时,确实拿到了 终端 shell 的环境变量副本

  • 如果你在终端里没设置 MY_VAR,那 CMake 里就是空。

  • 如果你在运行 cmake .. 之后再修改 shell 的 MY_VAR,CMake 进程是看不到的(因为它只在启动时复制了一份)。

我们来看看

export MY_VAR=Hello

再次启动看看

这说明 CMake 每次启动时都是从当前 shell 环境复制一份副本。


1.4.示例4

我给你写一个最小例子,演示 CMake 内部修改环境变量不会影响系统或终端 shell

打开终端,先设置一个环境变量:

export MY_VAR=OriginalValue

写一个简单的 CMakeLists.txt

cmake_minimum_required(VERSION 3.18)
project(NoSystemImpactDemo)# 打印启动时 shell 的环境变量
message(STATUS "CMake 启动时看到的 MY_VAR: '$ENV{MY_VAR}'")# 修改 CMake 内部环境变量
set(ENV{MY_VAR} "ModifiedInCMake")
message(STATUS "CMake 内部修改后的 MY_VAR: '$ENV{MY_VAR}'")

运行 CMake:

rm -rf build && mkdir build && cd build && cmake ..

CMake 内部修改了环境变量set(ENV{MY_VAR} ...)),只对 CMake 进程和它启动的子进程有效

系统环境或父 shell 完全不受影响,CMake 退出后修改的值消失。

1.5.示例5

我们都说子进程会继承父进程的环境变量,我们来看看是不是这么一回事。

📂 项目目录结构

env_demo/
└── CMakeLists.txt

🔹 env_demo/CMakeLists.txt

cmake_minimum_required(VERSION 3.18)
project(MultiChildEnvDemo)# Step 1: CMake 启动时的环境变量
message(STATUS "CMake 启动时看到的 MY_VAR: '$ENV{MY_VAR}'")# Step 2: 修改环境变量
set(ENV{MY_VAR} "FirstValue")
message(STATUS "CMake 修改后的 MY_VAR: '$ENV{MY_VAR}'")# Step 3: 启动第一个子进程
execute_process(COMMAND printenv MY_VAROUTPUT_VARIABLE OUT1OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "第一个子进程看到的 MY_VAR: '${OUT1}'")# Step 4: 再修改环境变量
set(ENV{MY_VAR} "SecondValue")
message(STATUS "CMake 再次修改 MY_VAR: '$ENV{MY_VAR}'")# Step 5: 启动第二个子进程
execute_process(COMMAND printenv MY_VAROUTPUT_VARIABLE OUT2OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "第二个子进程看到的 MY_VAR: '${OUT2}'")

 运行 CMake:

rm -rf build && mkdir build && cd build && cmake ..

  • 第一次修改"FirstValue"

    • 第一个子进程 继承了 "FirstValue"

  • 第二次修改"SecondValue"

    • 第二个子进程 继承了 "SecondValue"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96428.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mysql杂志(十四)——Mysql逻辑架构

Mysql逻辑架构 这个图相信大家并不陌生&#xff0c;这个就是mysql的逻辑结构图下面是主包让AI生成的翻译后的逻辑结构图&#xff1a; 我们先来看看各个部分的作用是什么 第一层&#xff1a;客户端连接层 (Client Layer) 这一层负责处理所有客户端连接到服务器的请求。责任就…

Git 版本回退与撤销修改

作为版本控制管理器&#xff0c;Git应当具备版本回退等一系列功能——它的应用场景也很常见&#xff0c;当你在工作区开发时&#xff0c;忽然发现&#xff1a;怎么我这版本写的代码还不如上一版本好&#xff1f;这时&#xff0c;版本回退功能就派上用场了。一.版本回退1.概览首…

学习日记-JS+DOM-day54-9.12

1.javascript基本说明知识点核心内容重点JavaScript基础控制HTML内容与属性&#xff0c;实现动态行为&#xff08;如开灯/关灯效果&#xff09;src属性路径修正&#xff08;./与../的区别&#xff09;前端三要素HTML&#xff08;内容&#xff09;、CSS&#xff08;样式&#xf…

使用tree命令导出文件夹/文件的目录树( Windows 和 macOS)

你可以在终端&#xff08;命令提示符&#xff09;中使用 tree 命令来清晰直观地查看和导出文件夹的目录结构。下面我会详细告诉你如何在 Windows 和 macOS 上使用它。 &#x1f5a5;️ tree 命令基本用法 tree 命令的核心作用是以树状图的形式展示指定路径下的目录和文件结构。…

GrapeCity Documents V8.0 Update2 重磅发布:性能飞跃、AI 赋能与文档处理全流程升级

作为葡萄城旗下服务端文档组件库&#xff0c;GrapeCity Documents&#xff08;简称"GcDocs"&#xff09;凭借跨平台、高兼容的优势&#xff0c;已成为 众多开发者构建文档生成、编辑、转换与管理系统的首选。 近日&#xff0c;GcDocs 迎来 V8.0 Update2 版本更新&am…

水质在线监测系统御控物联网解决方案

一、行业背景与需求痛点水质安全是饮用水供应、工业生产、生态保护的核心要素。随着《水污染防治行动计划》的深入实施&#xff0c;传统水质监测方式面临三大挑战&#xff1a;时效性不足&#xff1a;人工采样-实验室分析周期长达24-72小时&#xff0c;难以实时捕捉污染事件&…

【完整源码+数据集+部署教程】仓库物品分类检测图像分割系统源码和数据集:改进yolo11-convnextv2

背景意义 研究背景与意义 随着现代物流和仓储管理的快速发展&#xff0c;物品分类与检测技术在提高仓库运营效率、降低人工成本方面发挥着越来越重要的作用。传统的物品管理方式往往依赖人工识别和分类&#xff0c;效率低下且容易出错。为了解决这一问题&#xff0c;基于计算机…

浏览器稳定性提升之路:线上崩溃率优化中的 Return 与 CHECK 之争

一、前言在大型 C 工程&#xff08;例如 Chrome 浏览器内核&#xff09;中&#xff0c;开发者经常会遇到这样的选择&#xff1a; 到底应该在关键点使用 CHECK 直接崩溃&#xff0c;还是使用 return、LOG 记录错误然后继续执行&#xff1f;这看似只是一个代码风格问题&#xff0…

【数据结构与算法Trip第3站】双指针

我们来详细讲解一下算法中非常常用且重要的技巧——双指针法。 这是一个概念清晰但应用极其广泛的技术&#xff0c;掌握它能帮助你高效解决许多问题。 一、什么是双指针法&#xff1f; 核心思想&#xff1a;顾名思义&#xff0c;就是在遍历对象&#xff08;通常是数组或链表&am…

时序数据库选型指南:基于大数据视角的IoTDB应用优势分析详解!

目录 一、时序数据库选型的基本原则 1.1 数据特征与需求分析 1.1.1 数据规模与写入负载 1.1.2 查询需求 1.1.3 数据保留与归档策略 1.1.4 系统扩展性与高可用性 1.2 技术架构与系统性能评估 1.2.1 写入性能 1.2.2 查询性能 1.2.3 数据压缩能力 1.2.4 高可用性与灾备…

缓存三大劫攻防战:穿透、击穿、雪崩的Java实战防御体系(三)

第三部分&#xff1a;缓存雪崩——大量key失效引发的“系统性崩溃” 缓存雪崩的本质是“大量缓存key在同一时间失效&#xff0c;或缓存集群整体故障”&#xff0c;导致请求全量穿透至DB&#xff0c;引发“系统性崩溃”。 案例4&#xff1a;电商首页的“批量过期”灾难 故障现场…

解决docker配置了镜像源但还会拉取官方镜像源的问题

&#x1f3d3;我们有时候虽然配置了Docker国内镜像源&#xff0c;但是还是会绕过去请求官方镜像源&#xff08;docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded&#xff09;&#xff0c;现在我们就来解决一…

R语言水文、水环境模型优化:从最速上升法、岭分析到贝叶斯优化与异方差处理,涵盖采样设计、代理模型与快速率定等

在水利工程、环境治理、生态保护、机械设计与航天航空等现代工业与科学领域&#xff0c;数学模型已成为不可或缺的核心分析、预测与决策工具。然而&#xff0c;随着系统复杂性的日益增长&#xff0c;模型构建的精确性、参数率定的效率以及不确定性量化的重要性被提到了前所未有…

关于数据采集与处理心得(一)

目前所实践的经验告知我&#xff01;1. 别企图妄想一个脚本解决所有问题要学会对问题分解&#xff0c;编写多个脚本一步步将问题解决&#xff0c;如果每一个步骤都为了下一个阶段的成果打地基&#xff0c;也是非常OK的。同时要尽可能将每一个编写的脚本都尽到最大的利用率2. 编…

IvorySQL 适配 LoongArch® 龙架构

IvorySQL 社区很高兴向您宣布&#xff0c;IvorySQL 已成功适配LoongArch 龙架构&#xff0c;为国产数据库与国产芯片的深度融合迈出了坚实一步。这一里程碑标志着 IvorySQL 在推动国产化生态建设、赋能信创产业方面取得了重大突破&#xff0c;为用户提供更高效、稳定、安全的数…

数据库分库分表是考虑ShardingSphere 还是Mycat?

http://www.mycat.org.cn/ https://shardingsphere.apache.org/ 这是一个非常核心且优秀的问题。在选择 ShardingSphere 和 Mycat 之间&#xff0c;对于游戏这种高性能、高复杂度的场景&#xff0c;目前行业内的主流选择和发展趋势毫无疑问是 ShardingSphere。 我会为你详细对…

mysql分库分表数据量核查问题

场景&#xff1a; 使用分库分表的业务有时分库数量几百甚至上千&#xff0c;当主管需要查询每个库中的数据&#xff0c;掌握数据分布情况。要你查看哪些库中的表数量大于某个量级的给找出来 &#xff0c;你会怎么做。 例子 &#xff1a; mysql库数量&#xff1a;db_xx_devicein…

python之socket网络编程

引言 在互联网时代&#xff0c;网络编程已经成为开发人员必备的技能之一。无论是Web开发、实时通信还是分布式计算&#xff0c;都离不开网络编程的支持。Python提供的socket模块为我们提供了简洁而强大的接口&#xff0c;可以轻松实现客户端和服务器之间的通信。 Socket编程是网…

WPF Telerik.Windows.Controls.Data.PropertyGrid 自定义属性编辑器

1.AI帮忙定义新用户控件 2.在属性上添加TelerikEditorAttribute特性 private ObservableCollection<string> _axisOrder;[Display(Description "点位", GroupName "通用", Name "轴&顺序", Order 1)][DataMember][TelerikEditorAt…

【超详细】别再看零散的教程了!一篇搞定Gitee从注册、配置到代码上传与管理(内含避坑指南最佳实践)

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 &#x1f349;学习方向&#xff1a;C/C方向学习者…