我正在游荡,这是使用GCC在Linux上编译静态库的正确方法,这样当链接时间优化(LTO)应用于可执行文件时,库可以被消耗并且可能实现最佳性能。 / p>
当只使用-flto
编译库时,无论是否使用-flto
,都无法将可执行文件链接到它。错误是:
对'hello'的未定义引用
其中hello
是库中定义的函数。
根据this Stack Overflow问题的答案,一个可能的解决方案如下:
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 Stack Overflow问题的答案,我们是否希望以这种方式编译静态库,以便在使用和不使用LTO时使用,而不是使用-ffat-lto-objects
。如果我们再次将此标志添加到库编译标志中,则库可以链接到可执行文件,并且-flto
和-flto
都不会传递给链接器标记。
我的问题是:
gcc-ar
的第一个解决方案的确切含义是什么?使用-flto
编译库时,不同工作变体之间的区别是什么。
2.1不带-flto
的可执行文件。
gcc-ar
。-ffat-lto-objects
。gcc-ar
和-ffat-lto-objects
2.2使用-flto
和库的相同3种变体可执行。
这是我的测试项目的Minimal,Complete和Verifiable示例,它是this Stack Overflow问题的示例的修改版本。我正在使用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");
}
答案 0 :(得分:2)
说明:
-flto -fno-fat-lto-objects
编译目标文件。 -fno-fat-lto-objects
并非绝对必要,但是,它确保它可以执行或失败(而不是回退到非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
答案 1 :(得分:2)
如果您未将--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的存档。所有其他方法要么根本不起作用(归档中的非胖对象),要么实际上不会导致链接时间优化(归档中的胖对象 - 在这种情况下只使用传统的目标代码,LTO信息被忽略了。)