lto必须编译和链接阶段均启用-flto,否则完全不生效;cmake中推荐用set(cmake_interprocedural_optimization on)自动注入,静态库需用gcc-ar归档以保留.gnu.lto_*段。

编译和链接两个阶段都得加 -flto
只在编译时加 -flto,链接时不加,LTO 就完全不生效——链接器看到的还是普通目标文件,根本读不到 GIMPLE 中间表示。常见错误现象是 ld: error: lto1: not found,或者静默退化为普通链接,体积和性能毫无变化。
必须同步做两件事:
- 每个
.cpp编译:用g++ -flto -O2 -c foo.cpp -o foo.o - 最终链接:用
g++ -flto -O2 foo.o bar.o -o app(-flto不能漏)
CMake 中正确启用 INTERPROCEDURAL_OPTIMIZATION
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) 是最简方式,它会自动在 compile 和 link 阶段插入 -flto,但前提是编译器支持。别直接硬写 target_compile_options(... -flto) + target_link_options(... -flto),容易漏掉某一项或配错 scope。
更稳妥的做法是先检测支持性:
- 在
CMakeLists.txt开头加include(CheckIPOSupported) - 调用
check_ipo_supported(RESULT lto_enabled) - 仅当
lto_enabled为真时,再对 target 设置set_property(TARGET YourTarget PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
静态库打包必须用 gcc-ar,不是系统 ar
用普通 ar rc libfoo.a foo.o 打包带 LTO 的 .o,会把 .gnu.lto_* 段丢掉,导致后续链接时 LTO 失效。验证方法:readelf -x .gnu.lto_.symtab libfoo.a 返回空,就说明归档里没存 LTO 数据。
正确做法:
- 替换 CMake 的归档工具:
set(CMAKE_AR "/usr/bin/gcc-ar")、set(CMAKE_RANLIB "/usr/bin/gcc-ranlib") - 或者绕过静态库:把所有
.o直接传给最终链接命令,不经过.a中转
-flto=4 和 -flto=thin 不是随便换的
-flto 默认等价于 -flto=1,只做基础跨 TU 优化;-flto=4 启用多线程、全局常量传播、虚函数去虚拟化,但内存占用高、链接慢,CI 或嵌入式环境容易 OOM。
Clang 用户优先考虑 -flto=thin:
- 内存友好,适合大型项目
- 需要搭配
lld链接器(clang -flto=thin ... -fuse-ld=lld) - 老系统默认
ld.bfd不支持 ThinLTO,会静默回退
LTO 生效后,nm 看不到符号、gdb 行号错位是正常现象——中间表示重优化了代码布局,不是 bug,但调试体验确实会变差。











