使用GCC的链接时优化与静态链接库

35

我正在尝试使用GCC(6.1.1)的-flto标志进行链接时优化。

虽然我的代码可以正常工作,但它无法与我同时构建和链接到项目中的静态库一起链接(该项目为Engine,库是glsl-optimizer,仅供参考)。

以下是输出内容:

...
/usr/bin/ranlib: ir_expression_flattening.cpp.o: plugin needed to handle lto object
/usr/bin/ranlib: opt_function_inlining.cpp.o: plugin needed to handle lto object
/usr/bin/ranlib: opt_copy_propagation_elements.cpp.o: plugin needed to handle lto object
...

然后,当然,我遇到了一些函数的“未定义引用”问题。

我做了一些研究,并发现这可能是由于ar导致的,我应该尝试使用gcc-ar,但我不确定如何操作。

此外,我正在使用不支持lto(除了在一些平台上使用英特尔编译器,据我所读...)的CMake。尽管如此,我尝试使用:

set_property(TARGET glsl_optimizer PROPERTY INTERPROCEDURAL_OPTIMIZATION True)

这并没有起作用。

此外,我尝试了GCC的-fuse-linker-plugin标志,但不起作用。

我想我将不得不以传统的方式手动直接使用gcc-ar来完成,或者可能还有其他方法?


你试过在CMakeCache.txt中或通过CMake的GUI(在高级选项下)将CMAKE_AR缓存变量中的ar替换为gcc-ar吗?GCC对于INTERPROCEDURAL_OPTIMIZATION不起作用是CMake的GitLab页面上的一个已知问题 - Florian
@Florian:我刚试过,仅设置 CMAKE_AR 不能解决问题。您还需要 CMAKE_CXX_ARCHIVE_CREATECMAKE_CXX_ARCHIVE_FINISH(参见 @Mike Kinghan 的答案)。 - CpCd0y
这个快速修复方法对我非常有效! - Gumby The Green
2个回答

30

这里是一个包含 MCVE 的 CMake 项目,用于重现该问题:

$ ls -R hellow
hellow:
CMakeLists.txt  hello.c  libhello.c

$ cat hellow/CMakeLists.txt 
cmake_minimum_required (VERSION 2.6)
project (hellow)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
#SET(CMAKE_AR  "gcc-ar")
#SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
#SET(CMAKE_C_ARCHIVE_FINISH   true)
add_library(hello STATIC libhello.c) 
add_executable(hellow hello.c)
target_link_libraries(hellow hello)
add_dependencies(hellow hello)


$ cat hellow/hello.c 
extern void hello(void);

int main(void)
{
    hello();
    return 0;
}

$ cat hellow/libhello.c 
#include <stdio.h>

void hello(void)
{
    puts("Hello");
}

配置良好:

$ mkdir build_hellow
$ cd build_hellow/
$ cmake ../hellow
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/imk/dev/so/build_hellow

按照问题描述,构建失败:

$ make
Scanning dependencies of target hello
[ 25%] Building C object CMakeFiles/hello.dir/libhello.c.o
[ 50%] Linking C static library libhello.a
/usr/bin/ar: CMakeFiles/hello.dir/libhello.c.o: plugin needed to handle lto object
/usr/bin/ranlib: libhello.c.o: plugin needed to handle lto object
[ 50%] Built target hello
Scanning dependencies of target hellow
[ 75%] Building C object CMakeFiles/hellow.dir/hello.c.o
[100%] Linking C executable hellow
/tmp/ccV0lG36.ltrans0.ltrans.o: In function `main':
<artificial>:(.text+0x5): undefined reference to `hello'
collect2: error: ld returned 1 exit status
CMakeFiles/hellow.dir/build.make:95: recipe for target 'hellow' failed
make[2]: *** [hellow] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/hellow.dir/all' failed
make[1]: *** [CMakeFiles/hellow.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

有多种解决方案,其中一种是取消注释上面CMakeLists.txt中的3行注释。然后执行以下操作:


$ cmake ../hellow/
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/imk/dev/so/build_hellow

$ make
Scanning dependencies of target hello
[ 25%] Building C object CMakeFiles/hello.dir/libhello.c.o
[ 50%] Linking C static library libhello.a
[ 50%] Built target hello
Scanning dependencies of target hellow
[ 75%] Building C object CMakeFiles/hellow.dir/hello.c.o
[100%] Linking C executable hellow
[100%] Built target hellow

$ ./hellow 
Hello

这个修复方案利用了以下事实。
造成构建失败的问题:
/usr/bin/ar: CMakeFiles/hello.dir/libhello.c.o: plugin needed to handle lto object
...
/usr/bin/ranlib: libhello.c.o: plugin needed to handle lto object

可以通过给 arranlib 添加选项来解决:

--plugin=$(gcc --print-file-name=liblto_plugin.so)

然而,GNU ranlib 只是 ar -s 的同义词,gcc-ar 是一个包装器,用于提供该插件的 ar
CMake 用于 C 静态库的构建模板为:
CMAKE_C_ARCHIVE_CREATE ( = <CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>)
CMAKE_C_ARCHIVE_FINISH ( = <CMAKE_RANLIB> <TARGET>)

对于GNU ar命令而言,这相当于:

CMAKE_C_ARCHIVE_CREATE ( = <CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>)
CMAKE_C_ARCHIVE_FINISH ( = true) # Or any other no-op command

因此,加上这些设置:

SET(CMAKE_AR  "gcc-ar")

我们很好。

对于一个 C++ 项目,当然要设置 CMAKE_CXX_ARCHIVE_CREATECMAKE_CXX_ARCHIVE_FINISH


1
我尝试了使用GCC5.4的这些步骤,虽然它“与LTO编译”,但您不会看到您期望的任何优化发生。 - BlamKiwi
1
@BlamKiwi 在这个存档的消息中,修改了CMAKE_ARCMAKE_NMCMAKE_RANLIB。这可能是原因吗?如果是这样的话,能否有人更新答案(我的技术知识不足以透彻理解和正确解释)。 - Halil Sen
@HalilŞEN 我从来没有真正弄清楚发生了什么。尽管我注意到当进行LTO时,Clang会尊重always_inline。 - BlamKiwi
<|im_start|>assistant @bobeff lib.so 是支持 LTO 的工具的共享库插件。我之前从未听说过 -ffat-lto-objects,它是在我回答这个问题时还未发布的 GCC 7 中引入的。它的文档在这里 - Mike Kinghan
2
SET(CMAKE_AR "gcc-ar") 有所帮助 - 谢谢!您能把它移到顶部吗? - RushPL
显示剩余7条评论

1

在切换到g++-11后,我遇到了类似的问题。这可能是由于默认值的更改 - 使用“slim”对象而不是“fat”对象 - 添加-ffat-lto-objects解决了它。

另请参见this SO answer和其中的评论。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接