c++ - 在 Linux 上构建带有链接时间代码生成的静态库的正确方法是什么?

标签 c++ c gcc linker lto

我在徘徊哪种是在 Linux 上使用 GCC 编译静态库的正确方法,这样当链接时间优化 (LTO) 应用于可执行文件时,库可以使用并可能实现最佳性能。

当仅使用-flto 编译库时,无论是否使用-flto 都无法将可执行文件链接到它。错误是:

undefined reference to `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 传递给链接器标志来将库链接到可执行文件。

我的问题是:

  1. gcc-ar 的第一个解决方案的确切含义是什么?
  2. 当使用-flto 编译库时,不同工作变体之间有什么区别。

    2.1 无需 -flto 即可执行。

    • 库仅使用 gcc-ar
    • 库仅使用 -ffat-lto-objects
    • 库同时使用 gcc-ar-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)

执行/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");
}

最佳答案

如果不将--plugin/psth/to/lto-plugin.so* 添加到ar 参数,您将在链接时得到 undefined reference < em>和存档创建时的警告。或者至少这就是我得到的。您可能需要在此处添加它:

set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> --plugin <LTO_PLUGIN_PATH> \
  qcs <TARGET> <OBJECTS>")

(LINK_FLAGS 可能不属于这里,所以我省略了它们)。

我不知道如何自动设置 LTO_PLUGIN_PATH。

该插件使 ar 能够创建支持 LTO 的存档。所有其他方法要么根本不起作用(存档中的非胖对象),要么实际上不会导致链接时间优化(存档中的胖对象——在这种情况下只使用传统的目标代码,LTO 信息被忽略)。

关于c++ - 在 Linux 上构建带有链接时间代码生成的静态库的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46934111/

相关文章:

android - 有没有办法让 Android NDK-build 使用更新版本的 gcc?

c++ - 使用 SCSI 传递的 ioctrl

c - 在非常长的字符串中查找频率的最佳方法

c++ - 我应该使用哪个容器来快速找到一个元素,因为知道通过构造它已经被订购了?

c - 获取任意数据的函数 : Use void* or char*?

c++ - 找到具有 3 个变量的丢番图方程的一个特定解和解的数量的有效算法

c++ - C 编译器错误 : cdefs. h 未找到

c++ - gcc 中的 undefined reference 与 elux 5 上的 udev 链接

c++ - 海龟模型 : MOCK_EXPECT fails if mocked class method returns a value

c++ - CMake:尝试在 Jenkins Build Machine 上运行时出现 "Linked Library"错误(0xc0000135)