GCC 4.7 开始支持 Link Time Optimization (LTO),即连接时优化,可以使跨不同源文件的函数之间的关系得到进一步的优化。
它的做法是先把源代码编译成 GIMPLE 中间码,再在连接的时候生成真正的机器码。
在 Linux 上编译本机程序时一直正常工作,但是在使用 MingW-w64 工具链的时候,发现有时连接静态库会报错提示找不到符号。
在 Google 和 StackOverflow 一段时间之后,发现需要注意以下几点:
- 把 ar、nm、ranlib 换成 gcc-ar、gcc-nm、gcc-ranlib。因为原生的 ar、nm、ranlib 无法处理含有 GIMPLE 中间码的目标文件。
- 使用 gcc -fuse-linker-plugin 参数。它开启连接器插件功能,GCC 可以在连接时做更多的优化。
- 如果各种方法都不行,使用 gcc -ffat-lto-objects。这会让 GCC 生成一个“胖的(fat)”目标文件,它同时含有非 LTO 的机器码和 GIMPLE 中间码。工具链中如果有不支持 LTO 的程序如(ar),会使用非 LTO 的机器码副本。
总结一下,编译的时候加上以下的 CFLAGS:
gcc -flto -fuse-linker-plugin
如果 Makefile 是别人写好的,可以使用我的 LTOWrapper 来注入 -flto 参数。
Linux 下,Clang 需要使用 Gold 连接器。配置好之后 -flto 就可以使用。