在Linux上用GCC编译静态库的正确方法是,当将链接时间优化(LTO)应用于可执行文件时,库是可消耗的,并且有可能达到最佳性能。
当库仅用-flto
编译时,无论它是否使用-flto
,都不能将可执行文件链接到它。错误是:
未定义的对“`hello”的引用
其中hello
是在库中定义的函数。
根据this堆栈溢出问题的答案,可能的解决方案如下:
set(CMAKE_AR gcc-ar)
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH true)
然后,库可以通过-flto
链接到可执行文件,而不用-flto
传递给链接器标志。
但是,根据this堆栈溢出问题的答案,如果我们想要以这样的方式编译静态库,那么就必须使用-ffat-lto-objects
。如果我们再次将此标志添加到库编译标志,则库可以链接到带有-flto
的可执行文件,而不需要传递给链接器标志的-flto
。
我的问题是:
gcc-ar
的第一个解决方案的确切含义是什么?-flto
编译库时,不同工作变量之间的区别是什么?
2.不需-flto
即可执行。- Library is using only `gcc-ar`.
- Library is using only `-ffat-lto-objects`.
- Library is using both `gcc-ar` and `-ffat-lto-objects`
2.2可执行的-flto
和相同的3个变体库。
下面是我的测试项目的最小、完整和可验证的示例,它是来自this堆栈溢出问题的示例的修改版本。我在使用GCC版本的7.2.0
。
CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(lto)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -g -O3")
add_subdirectory(lib)
add_subdirectory(exe)
exe/CMakeLists.txt
set(TARGET_NAME exe)
add_executable(${TARGET_NAME} src/main.c)
target_link_libraries(${TARGET_NAME} lib)
option(EXE_LTO "Use link time optimizations for the executable." OFF)
if(${EXE_LTO})
target_compile_options(${TARGET_NAME} PRIVATE "-flto")
endif()
exe/src/main.c
extern void hello();
int main()
{
hello();
return 0;
}
lib/CMakeLists.txt
set(TARGET_NAME lib)
add_library(${TARGET_NAME} STATIC src/lib.c)
option(LIB_LTO "Use link time optimizations for the library." OFF)
option(LIB_FAT_LTO "Create fat LTO objects for library files." OFF)
option(LIB_USE_LTO_AR "Use another AR program for LTO objects." OFF)
if(${LIB_LTO})
target_compile_options(${TARGET_NAME} PRIVATE -flto)
endif()
if(${LIB_FAT_LTO})
target_compile_options(${TARGET_NAME} PRIVATE -ffat-lto-objects)
endif()
if(${LIB_USE_LTO_AR})
set(CMAKE_AR gcc-ar)
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH true)
endif()
lib/src/lib.c
#include <stdio.h>
void hello()
{
puts("Hello");
}
发布于 2017-10-25 15:05:01
如果不将--plugin /psth/to/lto-plugin.so*
添加到ar
参数中,则将在链接时获得未定义的引用,并在归档创建时得到警告。或者至少这就是我想要的。您可能需要在这里添加它:
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> --plugin <LTO_PLUGIN_PATH> \
qcs <TARGET> <OBJECTS>")
(LINK_FLAGS
可能不属于这里,所以我省略了它们)。
我不知道如何自动设置LTO_PLUGIN_PATH。
该插件使ar
能够创建启用LTO的档案.所有其他方法要么根本不工作(存档中的非fat对象),要么实际上不会导致链接时间优化(归档中的fat对象-在这种情况下只使用传统的对象代码,LTO信息被忽略)。
发布于 2017-10-25 14:59:08
使用说明:
-flto -fno-fat-lto-objects
编译对象文件。-fno-fat-lto-objects
并不是绝对必要的,但是它确保它不是执行lto,就是失败(而不是回到非lto模式)。ar rcsT --plugin <path-to-lto-plugin> ...
创建静态库,这里需要liblto_plugin.so
的完整路径。选项T
在这里创建一个瘦存档(不复制.o
文件)。-flto
标志。示例:
$ cat library.cc
namespace library {
int f(int a) {
return a + 1;
}
}
$ cat test.cc
#include <iostream>
namespace library { int f(int); }
int main() {
std::cout << library::f(0) << '\n';
}
$ g++ -c -Wall -Wextra -std=gnu++14 -O3 -flto -fno-fat-lto-objects -o library.o library.cc
$ ar rcsT --plugin /usr/libexec/gcc/x86_64-redhat-linux/5.3.1/liblto_plugin.so library.a library.o
$ g++ -c -Wall -Wextra -std=gnu++14 -O3 -flto -fno-fat-lto-objects -o test.o test.cc
$ g++ -o test -flto -O3 test.o
/tmp/ccY0l2jQ.ltrans0.ltrans.o: In function `main':
<artificial>:(.text.startup+0x37): undefined reference to `library::f(int)'
collect2: error: ld returned 1 exit status
$ g++ -o test -flto test.o library.a
$ ./test
1
https://stackoverflow.com/questions/46934111
复制相似问题