常用 ThinLTO 结合 PGO编译)
prefaceLinux 发行版或官方二进制包中的 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 2PGO 采样生成 Profile用 Stage 1 编译出的 Clang 去编译一套复杂的测试集或 LLVM 自身。在编译过程中收集编译器在运行时的行为数据哪些代码是热点、哪些分支更常走生成 *.profdata 性能配置文件。Stage 3ThinLTO PGO 终极黑卡使用 Stage 1 编译出的 Clang 再次编译 LLVM 源码此时在编译选项中同时开启 -fltothin 和 -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_LTOThin 明确指定为 Thin 模式而非 FullLLVM_BUILD_LLVM_DYLIBON 部分发行版为减小体积会选择动态链接此时 LTO 策略也会有所调整如果需要自行从源码编译高性能的 LLVM 且机器配置允许推荐在 CMake 中使用 -DLLVM_ENABLE_LTOThin。 [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