preface
Linux 发行版或官方二进制包中的 clang、lld 和 llvm(统称为 LLVM 工具链)默认不是单纯通过 Full LTO 编译得到的。
在实际的生产环境和多数主流 Linux 发行版(如 Ubuntu、Fedora、Arch Linux)的官方源中,LLVM 工具链通常使用 ThinLTO 结合 PGO (Profile-Guided Optimization,配置文件引导优化) 进行编译。 [1]
1. 为什么不使用 Full LTO?
- 内存消耗极大:LLVM/Clang 是一个极其庞大的 C++ 项目。使用 Full LTO 编译它会将所有编译单元的 Bitcode 吞入单核中进行全局链接优化。这需要高达 64GB 甚至 128GB+ 的内存,极易触发系统的 OOM (Out of Memory)。
- 无法并行化:Full LTO 的后端优化和代码生成阶段是单线程或极难高效并行化的,导致编译时间极长。 [2, 3, 4]
2. 现代 Linux 的标准编译方案
各大发行版和 Google、Apple 等大型企业在构建 LLVM 工具链时,普遍采用 3-Stage(三阶段)或 2-Stage(二阶段)的编译流水线:
- Stage 1:基础构建
- 使用系统自带的 GCC 或现有的 Clang,以常规方式(无 LTO)编译出一个基础的 Clang。
- Stage 2:PGO 采样(生成 Profile)
- 用 Stage 1 编译出的 Clang 去编译一套复杂的测试集或 LLVM 自身。
- 在编译过程中,收集编译器在运行时的行为数据(哪些代码是热点、哪些分支更常走),生成 *.profdata 性能配置文件。
- Stage 3:ThinLTO + PGO 终极黑卡
- 使用 Stage 1 编译出的 Clang 再次编译 LLVM 源码,此时在编译选项中同时开启 -flto=thin 和 -fprofile-use(引入 Stage 2 的采样数据)。
- ThinLTO 既能实现跨模块的全局优化(如内联、死代码消除),又允许各模块独立并行地进行代码生成。这不仅大幅降低了内存和时间成本,其最终产出的二进制文件性能甚至逼近或等同于 Full LTO。 [2, 5]
3. 如何验证你手头的 Clang 编译选项?
如果你想确认你当前 Linux 系统中的 clang 是如何被编译出来的,可以在终端运行以下命令:
clang -v
检查输出中是否包含 --with-linker-plugin,或者查看你所用发行版的源码包构建脚本(例如 Arch Linux 的 PKGBUILD 或 Ubuntu 的 rules 文件)。在现代构建脚本中,你会看到 CMake 参数中明确配置了:
- LLVM_ENABLE_LTO=Thin (明确指定为 Thin 模式而非 Full)
- LLVM_BUILD_LLVM_DYLIB=ON (部分发行版为减小体积会选择动态链接,此时 LTO 策略也会有所调整)
如果需要自行从源码编译高性能的 LLVM 且机器配置允许,推荐在 CMake 中使用 -DLLVM_ENABLE_LTO=Thin。 [2]
如果打算动手编译自己的 LLVM 工具链,需考虑:
-
服务器/电脑有多少 CPU 核心和内存?
-
追求的是极致的编译器性能,还是更短的编译等待时间?
可以继续查询最适合当前硬件的 CMake 编译配置参数。
[1] https://docs.python.org
[2] https://blog.csdn.net
[3] https://zhuanlan.zhihu.com
[4] https://zhuanlan.zhihu.com
[5] https://www.cnblogs.com
常用 ThinLTO 结合 PGO编译&spm=1001.2101.3001.5002&articleId=161092436&d=1&t=3&u=ba6eb7a285af480b9c2b3a2c3ec1d729)
973

被折叠的 条评论
为什么被折叠?



