这里是一个包含 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")
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
void hello(void)
{
puts("Hello");
}
配置良好:
$ mkdir build_hellow
$ cd build_hellow/
$ cmake ../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/
$ 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
可以通过给 ar
和 ranlib
添加选项来解决:
--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_CREATE
和 CMAKE_CXX_ARCHIVE_FINISH
。
CMakeCache.txt
中或通过CMake的GUI(在高级选项下)将CMAKE_AR
缓存变量中的ar
替换为gcc-ar
吗?GCC对于INTERPROCEDURAL_OPTIMIZATION
不起作用是CMake的GitLab页面上的一个已知问题。 - FlorianCMAKE_AR
不能解决问题。您还需要CMAKE_CXX_ARCHIVE_CREATE
和CMAKE_CXX_ARCHIVE_FINISH
(参见 @Mike Kinghan 的答案)。 - CpCd0y