【Linux 环境变量相关】深入理解Linux下 CMake、Shell 与环境变量的交互(一)

简介: 【Linux 环境变量相关】深入理解Linux下 CMake、Shell 与环境变量的交互

1. 引言

在编程的世界中,我们经常会遇到各种工具和技术,它们在表面上看起来很复杂,但实际上,它们的工作原理很简单。为了更好地理解这些工具和技术,我们需要从心理学的角度来看待它们。正如卡尔·容格(Carl Jung)所说:“人们不是由他们的意识,而是由他们的潜意识所驱使。”同样,编程中的很多工具和技术也是由其背后的原理和机制所驱使的。

1.1 CMake 在现代 C++ 开发中的重要性

CMake(C++ Make)是一个开源的、跨平台的构建系统,它可以帮助开发者编写复杂的构建规则,并确保代码在不同的平台和环境中都能正确地编译和运行。但为什么我们需要 CMake 呢?

想象一下,你正在读一本名为《C++ Primer》(C++ 入门)的书,这本书详细介绍了 C++ 的基础知识和高级特性。但当你尝试在不同的操作系统或编译器上编译和运行书中的示例代码时,你可能会遇到各种问题。这时,你可能会想:“为什么编程要这么复杂?”

答案很简单:因为每个操作系统和编译器都有自己的特性和限制。正如心理学家阿布拉罕·马斯洛(Abraham Maslow)所说:“如果你只有一把锤子,你会把每个问题都看作是钉子。”同样,如果你只熟悉一个编译器或操作系统,你可能会认为所有的代码都应该按照这个编译器或操作系统的规则来写。

但是,CMake 提供了一个解决方案。它允许你编写一套构建规则,然后在不同的平台和环境中自动调整这些规则,以确保代码能够正确地编译和运行。这就像是你有了一个万能的工具箱,无论你面对什么样的问题,你都可以找到合适的工具来解决它。

1.2 环境变量的基本概念

环境变量(Environment Variables)是操作系统中用于存储各种配置信息的变量。它们通常用于存储诸如文件路径、系统设置和其他重要数据的值。

为什么我们需要环境变量呢?让我们从心理学的角度来看待这个问题。

当你在一个陌生的环境中,你可能会感到迷茫和不安。你不知道该去哪里,也不知道该做什么。但是,如果你有一个地图或指南,你就可以轻松地找到你的目的地。同样,在编程中,当代码需要访问某些外部资源(如文件或网络服务)时,它需要知道这些资源的位置。环境变量就像是这个“地图”或“指南”,它告诉代码如何找到这些资源。

例如,PATH 环境变量指定了系统在哪里查找可执行文件。当你在命令行中输入一个命令时,系统会在 PATH 环境变量中列出的目录中查找这个命令。如果没有 PATH 环境变量,你就需要为每个命令指定完整的路径,这会非常麻烦。

环境变量 描述 示例
PATH 系统查找可执行文件的目录列表 /usr/local/bin:/usr/bin:/bin
HOME 当前用户的主目录 /home/username
LANG 系统的语言和字符集设置 en_US.UTF-8

正如心理学家 B.F. 斯金纳(B.F. Skinner)所说:“行为是由其后果来控制的。”在编程中,我们的代码也是由其输入(如环境变量)来控制的。通过正确地设置和使用环境变量,我们可以确保代码的行为是可预测和可控的。

2. CMake 的工作原理

在编程的旅程中,理解工具的工作原理是至关重要的。这不仅可以帮助我们更有效地使用这些工具,还可以帮助我们避免常见的陷阱和错误。

2.1 CMake 的基本概念和工作流程

CMake(C++ Make)是一个构建工具,它可以帮助开发者编写和管理复杂的构建规则。但是,CMake 与其他构建工具有什么不同呢?

首先,我们需要理解 CMake 的核心概念:构建文件生成。与其他直接执行构建任务的工具不同,CMake 的主要任务是生成构建文件。这些构建文件然后可以被 makeninja 或其他构建工具使用,以实际编译和链接代码。

这种分离的设计思路与心理学中的分离关注点原则相吻合。这个原则告诉我们,为了更有效地处理复杂的问题,我们应该将其分解为更小、更具体的部分。CMake 通过将构建规则的定义与实际的构建过程分离,使得开发者可以更专注于编写规则,而不是关心如何执行它们。

2.1.1 CMakeLists.txt

CMake 的配置文件称为 CMakeLists.txt。这个文件包含了所有的构建规则和设置。每当你想要添加一个新的源文件、库或可执行文件,或者更改构建选项时,你都需要修改这个文件。

例如,以下是一个简单的 CMakeLists.txt 文件,它定义了一个名为 hello 的可执行文件:

cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
add_executable(hello main.cpp)

这个文件告诉 CMake,我们需要至少版本为 3.10 的 CMake,项目的名字是 HelloWorld,并且我们想要创建一个名为 hello 的可执行文件,它的源代码是 main.cpp

2.1.2 CMake 的命令行工具

一旦你编写了 CMakeLists.txt 文件,你就可以使用 CMake 的命令行工具来生成构建文件。这个过程通常包括以下步骤:

  1. 创建一个空的构建目录。
  2. 在这个目录中运行 cmake 命令,并指定 CMakeLists.txt 文件的路径。
  3. 使用 makeninja 或其他构建工具来编译和链接代码。

这种工作流程允许开发者在不同的环境和平台上使用相同的 CMakeLists.txt 文件,而不需要为每个环境或平台编写特定的构建规则。

2.2 如何在 CMakeLists.txt 中定义和使用变量

在 CMake 中,变量是存储信息的基本单位。这些信息可以是文件路径、编译选项或其他任何数据。正如心理学家乔治·米勒(George A. Miller)在其著名的论文《魔数七,加上或减去二》中所说,人类的短期记忆有限。为了处理大量的信息,我们需要将其组织成更小、更易于管理的块。在 CMake 中,变量就是这些“块”。

2.2.1 定义变量

CMakeLists.txt 文件中,你可以使用 set 命令来定义一个新的变量。例如:

set(SOURCE_FILES main.cpp util.cpp)

这个命令定义了一个名为 SOURCE_FILES 的变量,它包含了两个源文件的路径。

2.2.2 使用变量

一旦你定义了一个变量,你就可以在 CMakeLists.txt 文件中的任何地方使用它。为了使用一个变量,你需要在其名称前后加上 ${}。例如:

add_executable(my_app ${SOURCE_FILES})

这个命令告诉 CMake,我们想要创建一个名为 my_app 的可执行文件,它的源代码是 SOURCE_FILES 变量中列出的文件。

3. Shell 的交互模式与非交互模式

在编程的世界中,Shell 是一个强大的工具,它允许我们与操作系统进行交互,执行命令和管理文件。但是,你是否知道 Shell 有多种运行模式,每种模式都有其特定的用途和行为?

3.1 交互式 vs. 非交互式 Shell 的定义

当我们谈论 Shell 的交互模式和非交互模式时,我们实际上是在谈论 Shell 如何与用户进行交互。

3.1.1 交互式 Shell

交互式 Shell 是指当你直接在终端或控制台中输入命令时使用的 Shell。在这种模式下,Shell 会显示一个提示符,等待你输入命令。当你输入命令并按下 Enter 键后,Shell 会执行该命令并显示结果。

这种直接的、实时的交互方式与心理学中的即时反馈原理相吻合。即时反馈可以增强学习和记忆,因为它允许我们立即看到我们的行为的结果。同样,当我们在交互式 Shell 中输入命令时,我们可以立即看到命令的输出,这有助于我们理解和记忆这些命令。

3.1.2 非交互式 Shell

非交互式 Shell 是指 Shell 脚本或其他程序调用 Shell 时使用的 Shell。在这种模式下,Shell 不会显示提示符,也不会等待用户输入。相反,它会按照脚本或程序中的指令执行命令,并返回结果。

这种模式与心理学中的条件反射原理相似。条件反射是一种学习过程,其中一个刺激(如铃声)与另一个刺激(如食物)反复配对,直到第一个刺激本身就能引起与第二个刺激相关的反应(如流口水)。同样,在非交互式 Shell 中,命令是预先定义的,它们会在特定的条件下自动执行,而不需要用户的干预。

3.2 初始化文件的加载顺序(如 ~/.bashrc vs. ~/.bash_profile

当 Shell 启动时,它会加载一些初始化文件,这些文件包含了设置环境变量、定义函数和别名等的命令。但是,不同的 Shell 模式会加载不同的初始化文件。

3.2.1 交互式 Shell 的初始化文件

当你启动一个交互式登录 Shell(例如,当你首次登录系统时)时,Shell 会加载 ~/.bash_profile~/.profile 文件(取决于你的系统和 Shell 版本)。这些文件通常用于设置全局环境变量和启动程序。

当你启动一个交互式非登录 Shell(例如,打开一个新的终端窗口)时,Shell 会加载 ~/.bashrc 文件。这个文件通常用于定义函数、别名和其他只适用于当前 Shell 会话的设置。

3.2.2 非交互式 Shell 的初始化文件

当 Shell 以非交互模式运行(例如,执行 Shell 脚本)时,它不会加载任何初始化文件。这是因为在这种模式下,Shell 通常只执行脚本中的命令,而不需要任何额外的设置。

然而,你可以使用 BASH_ENV 环境变量来指定一个文件,Shell 会在非交互模式下加载这个文件。这可以用于设置脚本所需的特定环境变量或函数。

4. 环境变量的继承机制

环境变量(Environment Variables)是操作系统中用于存储配置信息的全局变量,它们为运行在计算机上的进程提供了关于计算机环境的信息。在 C/C++ 和嵌入式开发中,我们经常需要配置和使用这些变量来满足不同的开发和运行需求。

4.1 如何在 Shell 中设置和使用环境变量

在 Unix-like 系统中,我们通常使用 Shell 来设置和使用环境变量。例如,我们可以使用 export 命令来设置一个新的环境变量:

export MY_VARIABLE=value

当我们想要查看一个环境变量的值时,我们可以使用 echo 命令:

echo $MY_VARIABLE

这种方式的设置是暂时的,当你关闭 Shell 时,这些变量就会消失。为了使环境变量永久生效,我们通常会将它们添加到 ~/.bashrc~/.bash_profile 文件中。

“人们经常因为害怕改变而错过捕捉幸福的机会。” —— Leo Buscaglia

这句话提醒我们,环境变量的改变可能会影响到我们的程序行为,所以我们应该时刻注意它们的设置和使用。

4.2 子进程如何继承父进程的环境变量

当一个进程启动一个新的子进程时,子进程会继承父进程的环境变量。这是一个非常自然的过程,就像我们从父母那里继承了某些特征一样。

例如,当我们在一个 Shell 中设置了一个环境变量,然后从这个 Shell 启动一个新的程序,这个程序就可以访问我们设置的环境变量。

#include <iostream>
#include <cstdlib> // for getenv
int main() {
    const char* value = getenv("MY_VARIABLE");
    if (value) {
        std::cout << "MY_VARIABLE: " << value << std::endl;
    } else {
        std::cout << "MY_VARIABLE is not set." << std::endl;
    }
    return 0;
}

在这个 C++ 示例中,我们使用 getenv 函数来获取环境变量的值。这个函数是 C 标准库中的一个函数,它允许我们在程序中访问环境变量。

方法 描述 示例
export 设置环境变量 export MY_VARIABLE=value
echo 查看环境变量的值 echo $MY_VARIABLE
getenv 在 C/C++ 中获取环境变量的值 getenv("MY_VARIABLE")

“我们不能改变现实,但我们可以改变我们对现实的看法。” —— Wayne Dyer

这句话告诉我们,尽管环境变量的值可能是固定的,但我们可以通过不同的方法和工具来查看和解释它们。

4.2.1 环境变量的覆盖

当子进程启动时,它会继承父进程的环境变量。但是,子进程可以修改它自己的环境变量,而不影响父进程。这就像我们可以选择遵循或忽略从父母那里学到的教训一样。

例如,我们可以在子进程中使用 export 命令来修改或设置新的环境变量,而这些变量的值不会影响到父进程。

5. CMake 中的 execute_process 命令

在 C++ 开发中,我们经常需要调用外部命令或脚本来完成某些任务,例如生成代码、检查依赖关系或执行测试。CMake 提供了一个非常强大的命令 execute_process,允许我们在配置阶段执行外部进程。

5.1 execute_process 的基本用法

execute_process 命令允许我们在 CMakeLists.txt 文件中执行外部命令。它的基本语法如下:

execute_process(
  COMMAND cmd [arg1 [arg2 ...]]
  [WORKING_DIRECTORY dir]
  [RESULT_VARIABLE var]
  [OUTPUT_VARIABLE var]
  [ERROR_VARIABLE var]
  [INPUT_FILE file]
  [OUTPUT_FILE file]
  [ERROR_FILE file]
  [TIMEOUT seconds]
  [ENVIRONMENT var=value...]
)
  • COMMAND:要执行的命令及其参数。
  • WORKING_DIRECTORY:命令的工作目录。
  • RESULT_VARIABLE:用于存储命令返回值的变量。
  • OUTPUT_VARIABLE:用于存储命令的标准输出的变量。
  • ERROR_VARIABLE:用于存储命令的标准错误的变量。

例如,我们可以使用以下命令来获取 Git 仓库的当前分支:

execute_process(
  COMMAND git rev-parse --abbrev-ref HEAD
  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  OUTPUT_VARIABLE GIT_BRANCH
  OUTPUT_STRIP_TRAILING_WHITESPACE
)
message("当前分支: ${GIT_BRANCH}")

这个命令会在项目的源代码目录中执行 git rev-parse --abbrev-ref HEAD,并将结果存储在 GIT_BRANCH 变量中。

5.2 如何使用 ENVIRONMENT 选项

当我们需要在特定的环境下执行命令时,可以使用 ENVIRONMENT 选项来设置或修改环境变量。例如,我们可能需要在特定的 PATH 下执行某个命令:

execute_process(
  COMMAND some_command
  ENVIRONMENT "PATH=/path/to/special/bin:${PATH}"
)

这样,some_command 就会在一个包含 /path/to/special/binPATH 环境变量中执行。


【Linux 环境变量相关】深入理解Linux下 CMake、Shell 与环境变量的交互(二)https://developer.aliyun.com/article/1467705

目录
相关文章
|
2月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
1月前
|
Web App开发 网络协议 Linux
linux命令总结(centos):shell常用命令汇总,平时用不到,用到就懵逼忘了,于是专门写了这篇论文,【便持续更新】
这篇文章是关于Linux命令的总结,涵盖了从基础操作到网络配置等多个方面的命令及其使用方法。
61 1
linux命令总结(centos):shell常用命令汇总,平时用不到,用到就懵逼忘了,于是专门写了这篇论文,【便持续更新】
|
16天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
1月前
|
存储 Linux 编译器
cmake的单目录和多目录的使用(Linux和Windows)
本文介绍了在Windows和Linux平台上使用CMake构建单目录和多目录项目的步骤,包括如何配置CMakeLists.txt文件以及如何生成和使用可执行文件、库文件。
19 2
|
2月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
2月前
|
人工智能 监控 Shell
常用的 55 个 Linux Shell 脚本(包括基础案例、文件操作、实用工具、图形化、sed、gawk)
这篇文章提供了55个常用的Linux Shell脚本实例,涵盖基础案例、文件操作、实用工具、图形化界面及sed、gawk的使用。
386 2
|
1月前
|
存储 Shell Linux
【Linux】shell基础,shell脚本
Shell脚本是Linux系统管理和自动化任务的重要工具,掌握其基础及进阶用法能显著提升工作效率。从简单的命令序列到复杂的逻辑控制和功能封装,Shell脚本展现了强大的灵活性和实用性。不断实践和探索,将使您更加熟练地运用Shell脚本解决各种实际问题
23 0
|
1月前
|
Linux
CMake在linux上的使用
这篇文章介绍了在Linux系统上使用CMake的基本步骤,包括安装CMake、创建和编辑CMakeLists.txt文件、生成构建文件以及编译和安装项目的命令。
45 0
|
2月前
|
Shell Linux 开发工具
linux shell 脚本调试技巧
【9月更文挑战第3天】在Linux中调试shell脚本可采用多种技巧:使用`-x`选项显示每行命令及变量扩展情况;通过`read`或`trap`设置断点;利用`echo`检查变量值,`set`显示所有变量;检查退出状态码 `$?` 进行错误处理;使用`bashdb`等调试工具实现更复杂调试功能。
|
3月前
|
Linux TensorFlow 算法框架/工具
在Linux上安装其他版本的cmake 或 升级cmake
在Linux上安装其他版本的cmake 或 升级cmake
89 2