环境搭建与配置
pycharm篇
markdown as root
idea篇
clion篇
构建
cmake -S src -B build $CMAKE_OPTIONS
编译
cmake --build
配置deployment,cmake(cmake配置编译目录,引用环境变量,cmake环境变量引用$CMAKE_OPTIONS)
ccache配置
ccache弄一个gcc和g++的软链,放在PATH最前面,再放真实需要fallback的gcc和g++
CMAKE_C_COMPILER、CMAKE_CXX_COMPILER通过外部传,比内部设置优先级高(这样也可以规避定义project隐藏两个变量的问题)
mold、ar、ranlib可以通过update-alternatives更新
构建篇
编译分三个阶段
构建 编译 生成产物 这三个可以映射到三个不同的目录
cmake -S src -B build $CMAKE_OPTIONS
cmake --build
加速构建
ar ranlib可以用llvm
ld可以用mold,建议手编
ccache,建议手编
关键文档
https://github.com/ccache/ccache/blob/master/doc/INSTALL.md
https://github.com/ccache/ccache/wiki/CMake
安装(假设ccache安装在/usr/local/bin)
-
/usr/local/bin新增gcc和g++的软链,指向ccache
-
调整path优先级,ccache放最前,目标gcc紧随其后
export PATH=/usr/local/bin:/usr/local/gcc~/bin:$PATH
-
设置CC,CXX分别为ccache gcc, ccache g++
-
cmake传递-D CMAKE_C_COMPILER_LAUNCHER=ccache -D CMAKE_CXX_COMPILER_LAUNCHER=ccache
CMAKE_C_COMPILER
CMAKE_CXX_COMPILER
CMAKE_C_COMPILER传递规则?
CMAKE_C_COMPILER
的传递规则CMAKE_C_COMPILER
是 CMake 中用于指定 C 编译器的变量。它控制 CMake 生成的构建系统中使用的 C 编译器。其传递和使用规则如下:
1. 如何设置
CMAKE_C_COMPILER
1.1 在命令行中传递
可以通过命令行参数显式传递
CMAKE_C_COMPILER
变量:cmake -DCMAKE_C_COMPILER=/path/to/compiler ..
- 设置后,CMake 会使用指定的编译器(如
gcc
、clang
、icc
等)。 - 该设置会保存到
CMakeCache.txt
中,后续运行时会复用。
1.2 通过环境变量传递
可以通过设置环境变量
CC
来影响CMAKE_C_COMPILER
的值:export CC=/path/to/compiler cmake ..
- 如果
CMAKE_C_COMPILER
没有显式设置,CMake 会优先尝试使用环境变量CC
指定的编译器。
1.3 在
CMakeLists.txt
中显式设置可以直接在
CMakeLists.txt
文件中设置:set(CMAKE_C_COMPILER /path/to/compiler)
- 注意:在首次运行 CMake 配置阶段后,
CMAKE_C_COMPILER
的值会被锁定到CMakeCache.txt
,后续更改不会生效,除非删除CMakeCache.txt
或使用cmake -U
来清除该缓存变量。
1.4 使用工具链文件
可以通过工具链文件指定编译器:
# toolchain.cmake set(CMAKE_C_COMPILER /path/to/compiler)
然后在运行 CMake 时指定工具链文件:
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..
2.
CMAKE_C_COMPILER
的传递优先级CMake 选择 C 编译器时的优先级如下:
- 命令行传递的
-DCMAKE_C_COMPILER
选项:最高优先级,直接指定编译器路径。 - 工具链文件中的
CMAKE_C_COMPILER
设置:如果指定了工具链文件,CMake 会优先使用该文件中声明的编译器。 - 环境变量
CC
:如果没有显式指定CMAKE_C_COMPILER
,CMake 会检查CC
环境变量。 - 系统默认编译器:如果上述方法都没有设置,CMake 会尝试从系统路径中找到默认的 C 编译器,例如
/usr/bin/cc
。
3.
CMAKE_C_COMPILER
在缓存中的行为3.1 缓存机制
-
CMAKE_C_COMPILER
的值会被写入
CMakeCache.txt
文件。一旦设置并生成缓存,后续运行 CMake 时不会自动更改,除非:
-
删除
CMakeCache.txt
文件。 -
使用
cmake -U
删除缓存变量:
cmake -U CMAKE_C_COMPILER ..
-
3.2 修改编译器的注意事项
如果需要更换编译器,必须清理缓存。否则,CMake 会继续使用缓存中保存的编译器,导致编译器切换失败。
rm -rf CMakeCache.txt cmake -DCMAKE_C_COMPILER=/path/to/new/compiler ..
4. 使用多个编译器的场景
4.1 交叉编译
对于交叉编译,通常需要使用工具链文件显式指定编译器和目标平台:
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..
工具链文件示例:
set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_C_COMPILER /path/to/arm-linux-gnueabihf-gcc)
4.2 不同编译器切换
可以在命令行中通过不同的编译器切换:
cmake -DCMAKE_C_COMPILER=/usr/bin/gcc .. cmake -DCMAKE_C_COMPILER=/usr/bin/clang ..
每次切换时,需要清理缓存。
5. 传递到子项目
5.1 子项目的继承规则
在 CMake 中,
CMAKE_C_COMPILER
是全局变量,子项目会继承主项目的编译器设置:add_subdirectory(subproject)
- 子项目会自动使用主项目中指定的
CMAKE_C_COMPILER
。
5.2 为子项目单独设置编译器
如果需要为子项目指定不同的编译器,可以通过
set()
在子项目的CMakeLists.txt
中覆盖:set(CMAKE_C_COMPILER /path/to/other/compiler)
- 注意:这可能会导致 CMake 报错,因为编译器的改变通常需要重新配置整个项目。
6. 常见问题及解决办法
6.1 编译器未找到
如果指定的编译器路径错误,CMake 会报类似以下错误:
CMake Error: CMake was unable to find a working compiler
解决办法:
- 确保编译器路径正确,并且编译器可执行文件有执行权限。
- 使用完整路径指定编译器,不要依赖系统
PATH
。
6.2 修改编译器无效
问题:
- 修改
CMAKE_C_COMPILER
后发现 CMake 仍然使用旧的编译器。
原因: - CMake 已缓存了
CMAKE_C_COMPILER
的值。
解决办法: - 删除缓存文件 (
CMakeCache.txt
) 或使用-U
清除缓存变量。
7. 总结
- 优先级规则:
-DCMAKE_C_COMPILER
> 工具链文件 > 环境变量CC
> 系统默认编译器。 - 缓存行为:
CMAKE_C_COMPILER
会被缓存到CMakeCache.txt
,需要清理缓存才能更改编译器。 - 子项目行为: 子项目继承主项目的编译器设置,除非显式覆盖。
- 多编译器管理: 使用工具链文件或在命令行指定编译器路径可以更方便地切换编译器。
通过正确设置
CMAKE_C_COMPILER
,可以灵活地配置和切换 CMake 项目的编译器。CMAKE_C_COMPILER
是否可以被篡改?CMAKE_C_COMPILER
是否可以被篡改?CMAKE_C_COMPILER
是 CMake 中的一个关键变量,用于指定 C 编译器。一般情况下,一旦 CMake 配置阶段完成并生成了CMakeCache.txt
文件,CMAKE_C_COMPILER
就会被锁定,不能被修改(防止篡改)。如果尝试在后续阶段篡改或更改它,CMake 通常会报错。以下是详细分析:
1. CMake 的编译器锁定机制
1.1 配置阶段锁定
-
在首次运行
cmake
时(配置阶段),
CMAKE_C_COMPILER
的值会被记录到
CMakeCache.txt
文件中:
CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc
-
此后,
CMAKE_C_COMPILER
的值是锁定的,除非删除缓存文件或显式清除变量。
1.2 修改或篡改
CMAKE_C_COMPILER
的结果-
如果尝试在已有缓存的项目中重新指定
CMAKE_C_COMPILER
,CMake 会报错,例如:
cmake -DCMAKE_C_COMPILER=/usr/bin/clang ..
错误信息:
CMake Error: The C compiler "/usr/bin/gcc" is not the same as the compiler "/usr/bin/clang" used in the previous run. Please remove the CMakeCache.txt file and CMakeFiles directory and try again.
- 原因:CMake 不允许在已有缓存的情况下更改编译器,因为这可能会导致构建不一致。
1.3 删除缓存后重新配置
-
如果确实需要更改编译器,必须清理缓存文件,然后重新运行
cmake
:
rm -rf CMakeCache.txt CMakeFiles cmake -DCMAKE_C_COMPILER=/usr/bin/clang ..
2.
CMAKE_C_COMPILER
的保护机制CMake 会通过以下方式保护
CMAKE_C_COMPILER
不被随意修改:2.1 缓存机制
CMAKE_C_COMPILER
的值会被缓存到CMakeCache.txt
文件中,后续运行时会直接使用缓存值,而不会重新解析命令行参数或环境变量。
2.2 检查一致性
- 如果尝试在已有配置中更改
CMAKE_C_COMPILER
,CMake 会检查新值和缓存中记录的值是否一致。若不一致,会终止运行并提示清理缓存。
2.3 工具链文件的强制限制
- 如果使用了工具链文件(通过
-DCMAKE_TOOLCHAIN_FILE
指定),CMAKE_C_COMPILER
的值会受到工具链文件的约束,不能在其他地方更改。
3. 如何绕过保护机制?
虽然 CMake 对
CMAKE_C_COMPILER
有保护机制,但仍然有一些方法可以绕过或修改它:3.1 清理缓存文件
-
删除
CMakeCache.txt
和
CMakeFiles
目录后,可以重新指定
CMAKE_C_COMPILER
:
rm -rf CMakeCache.txt CMakeFiles cmake -DCMAKE_C_COMPILER=/path/to/new/compiler ..
3.2 修改
CMakeCache.txt
文件-
手动编辑
CMakeCache.txt
文件,找到类似以下的行:
CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc
修改为新的编译器路径:
CMAKE_C_COMPILER:FILEPATH=/usr/bin/clang
然后重新运行
cmake
。
注意
:直接修改缓存文件可能导致不一致问题,需谨慎操作。
3.3 强制覆盖变量
-
即使变量被缓存,也可以在命令行中显式取消缓存限制:
cmake -U CMAKE_C_COMPILER -DCMAKE_C_COMPILER=/path/to/new/compiler ..
这里的
-U
参数会清理缓存中指定的变量。
3.4 使用外部脚本篡改
- 如果有人试图通过外部脚本(如 Python、Bash)修改配置,可以直接操作
CMakeCache.txt
或工具链文件来篡改CMAKE_C_COMPILER
。
4. 如何防止篡改?
如果担心
CMAKE_C_COMPILER
被意外或恶意篡改,可以采取以下措施:4.1 使用工具链文件
-
使用工具链文件显式定义
CMAKE_C_COMPILER
,并确保工具链文件权限不可修改:
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..
工具链文件示例:
set(CMAKE_C_COMPILER /usr/bin/gcc CACHE FILEPATH "" FORCE)
FORCE
参数:确保即使有缓存,CMAKE_C_COMPILER
也会被强制设置为指定的值。
4.2 使用只读缓存
-
将
CMakeCache.txt
设置为只读,防止用户或脚本修改:
chmod 444 CMakeCache.txt
4.3 检查一致性
-
在
CMakeLists.txt
中添加检查逻辑,确保
CMAKE_C_COMPILER
的值符合预期:
if (NOT CMAKE_C_COMPILER MATCHES "/usr/bin/gcc")message(FATAL_ERROR "CMAKE_C_COMPILER has been modified!") endif()
4.4 使用环境隔离
- 在构建环境中使用容器(如 Docker),确保编译器和 CMake 的配置不可被外部修改。
5. 总结
- 默认情况下,
CMAKE_C_COMPILER
是受 CMake 的缓存机制保护的,不能随意篡改。 - 如果需要更改编译器,必须清理缓存或正确地传递新的编译器路径。
- 防止篡改的方法:
- 使用工具链文件,并通过
FORCE
参数锁定变量。 - 检查
CMAKE_C_COMPILER
的一致性。 - 设置缓存文件只读或隔离构建环境。
- 使用工具链文件,并通过
通过这些机制,可以有效地防止
CMAKE_C_COMPILER
被意外或恶意修改。 - 设置后,CMake 会使用指定的编译器(如
ccache不生效?
排查
ccache -s -vexport CCACHE_LOGFILE=/path/to/ccache.log
与缓存命中机制有关,基于时间/hash,如果目录中大量文件都会存在patch,基于时间大概率是不靠谱的,可以基于hash做进一步优化。
export CCACHE_NOINODE=1
cmake只有add_subdirectories会触发构建,其他都不会
通过这个线索,即可知道触发构建的顺序
代码查看篇
bear ccls compiledatabase
idea篇
vscode篇
ccls
装一个llvm,然后直接编,参考今夕佬
禁用cppintelllisnse
ccls制定compile_database目录配置
pycharm篇
pythonpath
pdb++
抓单进程
ccache fallbcak
gcc查找顺序
4. 总结:检查未命中缓存的关键词
- 日志关键词:
No direct cache hit
No preprocessed cache hit
Compiler mismatch
Source file changed
Header file changed
Cache miss
Unsupported compiler option
- 统计信息:
使用ccache -s
检查cache miss
、called for link
等未命中情况。 - 常见问题及解决方法:
- 确保编译器和编译选项一致。
- 避免源文件和头文件的多次生成或修改。
- 使用
CCACHE_CPP2=yes
减少预处理器输出的差异。 - 增大缓存大小,避免缓存不足。
"No direct cache hit"
表示缓存未被直接命中,ccache 没有找到符合条件的缓存编译结果。
"No preprocessed cache hit"
表示即使在预处理文件的基础上,也未找到缓存命中。
"Compiler mismatch"
表示编译器版本或路径发生了变化,导致缓存未命中。
"Unsupported compiler option"
表示使用了一些 ccache 无法支持的编译器选项(如 -frecord-gcc-switches
),导致缓存无效。
"Source file changed"
表示源文件内容发生了变化,因此缓存未命中。
"Header file changed"
表示包含的头文件发生了变化,导致缓存未命中。
"Preprocessor changed"
表示预处理器的输出发生了变化(例如宏定义、环境变量变化)。
"Cache miss"
通常直接表示某次编译未命中缓存。
1. ccache
的常用环境变量
ccache
提供了一系列环境变量,用于控制其行为、配置缓存路径和大小、调试日志等功能。以下是常用的 ccache
环境变量:
缓存控制
-
CCACHE_DIR
-
指定
ccache
缓存目录。 -
默认值:
~/.ccache
-
示例:
export CCACHE_DIR=/tmp/my_ccache
-
-
CCACHE_MAXSIZE
-
设置缓存的最大大小。
-
默认值:5 GiB
-
示例:
export CCACHE_MAXSIZE=10G
-
-
CCACHE_COMPRESS
-
是否启用缓存文件的压缩。
-
默认值:
true
-
示例:
export CCACHE_COMPRESS=false
-
-
CCACHE_READONLY
-
将缓存目录设置为只读模式(防止写入)。
-
默认值:未启用
-
示例:
export CCACHE_READONLY=1
-
性能优化
-
CCACHE_NOINODE
-
禁用 inode 缓存的使用(基于 inode 的缓存检查)。
-
默认值:未启用
-
示例:
export CCACHE_NOINODE=1
-
-
CCACHE_BASEDIR
-
指定构建目录的基准路径,归一化路径以提高缓存命中率(适用于路径变化频繁的场景)。
-
示例:
export CCACHE_BASEDIR=/path/to/project
-
-
CCACHE_HARDLINK
-
启用硬链接以减少缓存文件的复制。
-
默认值:未启用
-
示例:
export CCACHE_HARDLINK=1
-
调试与日志
-
CCACHE_LOGFILE
-
指定调试日志文件路径。
-
默认值:无日志输出
-
示例:
export CCACHE_LOGFILE=/path/to/ccache.log
-
-
CCACHE_DEBUG
-
启用调试模式,输出更多详细信息(仅调试时使用)。
-
默认值:未启用
-
示例:
export CCACHE_DEBUG=1
-
-
CCACHE_STATS
-
启用统计信息,显示缓存命中率和使用情况。
-
默认值:未启用
-
示例:
export CCACHE_STATS=1
-
其他
-
CCACHE_DISABLE
-
禁用
ccache
,所有编译请求直接传递给底层编译器。 -
默认值:未启用
-
示例:
export CCACHE_DISABLE=1
-
-
CCACHE_RECACHE
-
强制重新生成缓存项,即使缓存已存在。
-
默认值:未启用
-
示例:
export CCACHE_RECACHE=1
-
2. Python 的常用环境变量
除了 PYTHONPATH
,Python 还支持许多环境变量,用于控制 Python 的运行时行为、模块路径、调试信息、内存管理等。
路径与模块加载
-
PYTHONPATH
-
指定 Python 的模块搜索路径。
-
示例:
export PYTHONPATH=/path/to/modules
-
-
PYTHONHOME
-
指定 Python 的安装目录,用于覆盖默认的安装路径。
-
示例:
export PYTHONHOME=/usr/local/python
-
-
PYTHONUSERBASE
-
指定用户级安装路径(
pip install --user
的默认路径)。 -
示例:
export PYTHONUSERBASE=/home/user/.local
-
执行与调试
-
PYTHONDEBUG
-
启用调试模式,显示更多运行时调试信息。
-
默认值:未启用
-
示例:
export PYTHONDEBUG=1
-
-
PYTHONDONTWRITEBYTECODE
-
禁止生成
.pyc
文件。 -
默认值:未启用
-
示例:
export PYTHONDONTWRITEBYTECODE=1
-
-
PYTHONUNBUFFERED
-
禁用标准输入、输出和错误流的缓冲区(常用于调试和日志记录)。
-
默认值:未启用
-
示例:
export PYTHONUNBUFFERED=1
-
内存与性能
-
PYTHONMALLOC
-
控制 Python 的内存分配器。
-
值:
debug
:启用调试分配器,检查内存泄漏。malloc
:使用系统的malloc
。pymalloc
:使用 Python 的内置内存分配器(默认)。
-
示例:
export PYTHONMALLOC=debug
-
-
PYTHONHASHSEED
-
控制哈希随机化的种子(用于安全性和一致性)。
-
示例:
export PYTHONHASHSEED=42
-
优化与版本控制
-
PYTHONOPTIMIZE
-
启用优化模式(
-O
或-OO
相当于设置此变量)。 -
值:
1
:移除断言语句。2
:移除断言语句和文档字符串。
-
示例:
export PYTHONOPTIMIZE=2
-
-
PYTHONWARNINGS
-
控制警告的显示方式(等效于
-W
)。 -
示例:
export PYTHONWARNINGS=default
-
-
PYTHONSTARTUP
-
指定 Python 交互模式启动时执行的脚本路径。
-
示例:
export PYTHONSTARTUP=~/.pythonrc
-
虚拟环境
-
VIRTUAL_ENV
-
指定当前激活的虚拟环境路径(通常由虚拟环境工具自动设置)。
-
示例:
export VIRTUAL_ENV=/path/to/virtualenv
-
-
PIP_REQUIRE_VIRTUALENV
-
强制
pip
只能在虚拟环境中运行。 -
示例:
export PIP_REQUIRE_VIRTUALENV=true
-
3. 参考总结
ccache
常用环境变量
- 缓存控制:
CCACHE_DIR
、CCACHE_MAXSIZE
、CCACHE_COMPRESS
- 性能优化:
CCACHE_NOINODE
、CCACHE_BASEDIR
- 调试日志:
CCACHE_LOGFILE
、CCACHE_DEBUG
Python 常用环境变量
- 路径管理:
PYTHONPATH
、PYTHONHOME
- 调试与优化:
PYTHONDEBUG
、PYTHONMALLOC
- 虚拟环境:
VIRTUAL_ENV
根据你的使用场景,可以设置这些变量来优化开发和运行环境。如果还有其他问题,欢迎继续提问! 😊
Python 除了 PYTHONPATH
之外,还有许多环境变量可以影响其行为。这些变量通常用于控制 Python 的运行时设置、模块查找路径、优化选项以及交互式解释器的行为。
以下是 Python 支持的一些重要默认环境变量:
1. 与模块路径相关的环境变量
1.1 PYTHONPATH
-
作用:用于指定 Python 的模块搜索路径(类似于
sys.path
)。 -
用法:
-
将目录路径添加到
PYTHONPATH
,Python 会在这些目录中查找模块。 -
示例:
export PYTHONPATH=/my/custom/modules python myscript.py
-
1.2 PYTHONHOME
-
作用:设置 Python 的主目录,影响标准库和脚本的查找路径。
-
用法:
-
如果没有设置,默认值取决于 Python 的安装路径。
-
示例:
export PYTHONHOME=/usr/local/python
-
-
注意:
PYTHONHOME
通常与PYTHONPATH
配合使用,但不建议随意设置,因为它可能导致环境不一致。
1.3 PYTHONSTARTUP
-
作用:指定一个启动脚本文件,在启动交互式 Python 解释器时自动运行。
-
用法:
-
通常用于加载常用模块或定义一些全局变量。
-
示例:
export PYTHONSTARTUP=~/.pythonrc
在
~/.pythonrc
文件中:
import os print("Welcome to Python!")
-
1.4 PYTHONDEBUG
-
作用:启用调试模式,影响某些模块的行为(如
importlib
和sys
)。 -
用法:
-
设置为任意值(如
1
)以启用调试模式。 -
示例:
export PYTHONDEBUG=1 python myscript.py
-
1.5 PYTHONPATH_OVERRIDE
(Python 3.11 引入)
-
作用:覆盖默认的
PYTHONPATH
,优先于PYTHONPATH
。 -
用法:
-
示例:
export PYTHONPATH_OVERRIDE=/my/override/path
-
2. 与字节码和缓存相关的环境变量
2.1 PYTHONDONTWRITEBYTECODE
-
作用:禁止 Python 写入
.pyc
文件(字节码文件)。 -
用法:
-
设置为任意值(如
1
)以禁用.pyc
文件生成。 -
示例:
export PYTHONDONTWRITEBYTECODE=1 python myscript.py
-
-
用于:防止污染源代码目录(例如在容器环境中)或调试。
2.2 PYTHONPYCACHEPREFIX
-
作用:指定
__pycache__
目录的位置。 -
用法:
-
如果未设置,
.pyc
文件默认存储在脚本所在目录的__pycache__
文件夹中。 -
示例:
export PYTHONPYCACHEPREFIX=/my/custom/cache
-
3. 与优化和性能相关的环境变量
3.1 PYTHONOPTIMIZE
-
作用:启用优化模式,相当于运行 Python 时添加
-O
或-OO
参数。 -
用法:
-
设置为
1
:启用一级优化(移除断言语句)。 -
设置为
2
:启用二级优化(移除断言和__doc__
字符串)。 -
示例:
export PYTHONOPTIMIZE=1 python myscript.py
-
3.2 PYTHONWARNINGS
-
作用:控制警告的显示方式,相当于运行 Python 时添加
-W
参数。 -
用法:
-
示例:
export PYTHONWARNINGS="ignore::DeprecationWarning" python myscript.py
-
常见值:
default
:显示默认警告。ignore
:忽略警告。error
:将警告转换为错误。
-
3.3 PYTHONHASHSEED
-
作用:设置字符串和字节对象的哈希种子。
-
用法:
-
设置为随机值(
random
)或固定种子(整数值)。 -
示例:
export PYTHONHASHSEED=42 python myscript.py
-
用于:解决哈希冲突或调试哈希依赖的代码。
-
4. 与交互式解释器相关的环境变量
4.1 PYTHONINSPECT
-
作用:在脚本执行结束后进入交互式模式。
-
用法:
-
设置为任意值(如
1
)以启用交互模式。 -
示例:
export PYTHONINSPECT=1 python myscript.py
-
4.2 PYTHONIOENCODING
-
作用:设置标准输入、输出和错误流的编码格式。
-
用法:
-
格式:
encoding[:errors]
,其中errors
是错误处理模式。 -
示例:
export PYTHONIOENCODING=utf-8 python myscript.py
-
4.3 PYTHONUNBUFFERED
-
作用:使标准输入、输出和错误流变为非缓冲模式。
-
用法:
-
设置为任意值(如
1
)以禁用缓冲。 -
示例:
export PYTHONUNBUFFERED=1 python myscript.py
-
-
用于:将输出立即写入(例如在日志或实时输出场景中)。
5. 与虚拟环境相关的环境变量
5.1 VIRTUAL_ENV
-
作用:指向当前激活的 Python 虚拟环境目录。
-
用法:
-
自动设置为虚拟环境的路径,当虚拟环境激活时。
-
示例:
echo $VIRTUAL_ENV /path/to/venv
-
5.2 PYTHONUSERBASE
-
作用:指定用户级别的 Python 包目录(默认是
~/.local
)。 -
用法:
-
示例:
export PYTHONUSERBASE=/my/custom/userbase python -m pip install --user somepackage
-
5.3 PIP_REQUIRE_VIRTUALENV
-
作用:强制要求在虚拟环境中使用
pip
。 -
用法:
-
设置为任意值(如
1
)以启用虚拟环境限制。 -
示例:
export PIP_REQUIRE_VIRTUALENV=1
-
6. 其他环境变量
6.1 PYTHONNOUSERSITE
-
作用:禁用用户级别的
site-packages
目录。 -
用法:
-
设置为任意值(如
1
)以禁用用户级目录。 -
示例:
export PYTHONNOUSERSITE=1
-
6.2 PYTHONBREAKPOINT
-
作用:定义调试器的入口点,替代默认的
pdb.set_trace()
。 -
用法:
-
示例:
export PYTHONBREAKPOINT=ipdb.set_trace python myscript.py
-
6.3 PYTHONFAULTHANDLER
-
作用:启用 Python 的错误处理程序(输出崩溃堆栈跟踪)。
-
用法:
-
设置为任意值(如
1
)以启用。 -
示例:
export PYTHONFAULTHANDLER=1 python myscript.py
-
总结
Python 环境变量可以极大地影响 Python 的运行行为。常见的环境变量包括:
- 模块路径相关:
PYTHONPATH
,PYTHONHOME
- 性能优化相关:
PYTHONOPTIMIZE
,PYTHONDONTWRITEBYTECODE
- 交互模式相关:
PYTHONSTARTUP
,PYTHONINSPECT
- 虚拟环境相关:
VIRTUAL_ENV
,PYTHONUSERBASE
这些变量可以通过 export
命令设置,也可以在脚本运行时动态修改。如果有特定需求,可以根据场景调整环境变量的值。
add_subdirectory过程中 子目录的set(CMAKE_CXX_COMPILER g++)
set(CMAKE_C_COMPILER gcc)
都消失了 为什么
在 add_subdirectory
的过程中,子目录中的 set(CMAKE_CXX_COMPILER g++)
和 set(CMAKE_C_COMPILER gcc)
都消失,通常是因为 CMake 的编译器设置机制导致的。CMake 对编译器的设置有严格的规则,以下是详细原因和解决方法:
原因分析
1. CMake 编译器的设置规则
-
CMAKE_C_COMPILER
和CMAKE_CXX_COMPILER
是全局变量:- 一旦 CMake 完成了编译器的检测,
CMAKE_C_COMPILER
和CMAKE_CXX_COMPILER
就被锁定,无法在项目的子目录中通过set()
直接修改。 - 这些变量只能在 CMake 配置初始阶段(通常是顶层
CMakeLists.txt
或通过cmake
命令行参数)配置。
- 一旦 CMake 完成了编译器的检测,
-
CMake 的编译器设置机制:
-
在 CMake 的第一次运行时,CMake 会检测和设置编译器。
-
如果你尝试在子目录中重新设置编译器,例如:
set(CMAKE_C_COMPILER gcc) set(CMAKE_CXX_COMPILER g++)
这些设置会被忽略或无效,因为编译器已经在顶层配置中锁定。
-
2. 为什么编译器变量会“消失”?
- 子目录中不能重新设置编译器:
- 在
add_subdirectory
的子目录中,set(CMAKE_C_COMPILER ...)
和set(CMAKE_CXX_COMPILER ...)
尝试更改全局变量,但 CMake 已经完成了编译器初始化,因此这些变量被视为无效设置。 - 编译器检测只在 配置阶段 执行一次,子目录中无法重新触发这个过程。
- 在
- CMake 缓存机制:
CMAKE_C_COMPILER
和CMAKE_CXX_COMPILER
会被存储在CMakeCache.txt
中。- 如果子目录试图修改这些变量,CMake 会优先使用缓存中的值,而不是子目录中的新设置。
- 最终,子目录中的设置“消失”,并继续使用原有的编译器。
3. 子目录独立编译器设置的限制
CMake 的设计决定了编译器设置是 全局性的,无法对某些子目录设置不同的编译器(除非使用特殊的方法,如外部项目构建)。
解决方法
方法 1:在顶层配置编译器
如果需要全局设置编译器,应该在顶层 CMakeLists.txt
中设置编译器,而不是在子目录中。例如:
set(CMAKE_C_COMPILER gcc)
set(CMAKE_CXX_COMPILER g++)
或者直接在运行 CMake 时指定:
cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ ..
方法 2:清理缓存并重新配置
如果你曾经运行过 CMake,它可能已经缓存了错误的编译器设置,可以通过清理缓存来重新配置:
rm -rf CMakeFiles CMakeCache.txt
cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ ..
方法 3:为子目录使用外部项目
如果确实需要为某个子目录使用独立的编译器,可以使用 ExternalProject_Add
,让子目录成为一个独立的外部项目。例如:
include(ExternalProject)ExternalProject_Add(MySubProjectSOURCE_DIR ${CMAKE_SOURCE_DIR}/subdirCMAKE_ARGS -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
)
这会为子目录配置独立的编译器。
方法 4:子目录中使用自定义目标
如果你只需要在子目录中使用特定的编译器来完成某些任务(而不是影响整个项目),可以使用 add_custom_target
或 add_custom_command
来调用特定的编译器。例如:
add_custom_target(MyCustomBuildCOMMAND g++ -o my_program my_program.cppWORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
方法 5:避免在子目录中设置编译器
如果不需要为子目录单独设置编译器,避免在子目录中重复操作。编译器的设置应始终在顶层配置,子目录继承即可。
总结
-
核心原因:CMake 的编译器设置是全局的,一旦设置完成,子目录中无法重新修改。
-
最佳实践
:
- 在顶层设置编译器。
- 或者通过
ExternalProject_Add
为子目录配置独立的编译器。
-
建议:尽量避免在子目录中直接调用
set(CMAKE_C_COMPILER)
和set(CMAKE_CXX_COMPILER)
,这些操作通常是无效的。
如果你需要更具体的解决方案,可以详细描述你的项目需求,我可以进一步优化建议! 😊
1.3 为什么子目录还能重新设置编译器?
- 子目录中重新设置编译器的行为可能生效,但仅限于:
- 子目录中调用了新的
project()
命令。 - 子目录是完全独立的配置环境(例如,使用
ExternalProject
或手动调用 CMake)。
- 子目录中调用了新的
这种行为是因为 project()
的调用会重新初始化一些与项目相关的变量,如 CMAKE_C_COMPILER
和 CMAKE_CXX_COMPILER
。但这通常会导致构建系统的不一致。
4. 总结
- 编译器变量的全局性:
CMAKE_C_COMPILER
和CMAKE_CXX_COMPILER
是全局变量,默认在add_subdirectory
中继承主目录的值。- 一旦在顶层目录中通过 CMake 配置阶段设置并缓存,编译器变量不能在子目录中直接更改。
- 为什么会消失?
- 子目录继承了主目录的配置,但这些变量可能被锁定在缓存中,新的设置无效。
- 子目录重新设置编译器的行为:
- 如果子目录调用了
project()
,编译器变量会重新初始化。 - 如果通过
ExternalProject
,子目录可以完全独立配置编译器。
- 如果子目录调用了
- 最佳实践:
- 在主目录中统一设置编译器,以保证构建一致性。
- 如果需要为子项目设置不同的编译器,使用工具链文件或
ExternalProject
来隔离配置。