2014年12月14日星期日

GCC LTO 连接时优化的几点注意

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

注:在 Linux 下使用 LLVM/Clang 的全程序优化遇到困难的时候可以试试 http://nochair.net/posts/2011/07-01-whole-program-llvm-bitcode.html
Linux 下,Clang 需要使用 Gold 连接器。配置好之后 -flto 就可以使用。