链接到共享库时,不会导出静态库中的符号

S.M*_*.M. 2 c cmake clang

共享库的代码是模块化的,由几个独立的单元组成。每个单元都内置在一个静态库中。


单元1.c

#include <stdio.h>

void HelloWorld() {
  printf("Hello World!\n");
}
Run Code Online (Sandbox Code Playgroud)

单元2.c

#include <stdio.h>

void GoodbyeWorld() {
  printf("Goodbye World!\n");
}
Run Code Online (Sandbox Code Playgroud)

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.2)

add_library(unit1 STATIC unit1.c)
target_compile_options(unit1 PRIVATE -fPIC)

add_library(unit2 STATIC unit2.c)
target_compile_options(unit2 PRIVATE -fPIC)

add_library(merged SHARED)
target_link_libraries(merged unit1 unit2)
set_target_properties(merged PROPERTIES LINKER_LANGUAGE C)
Run Code Online (Sandbox Code Playgroud)

构建步骤:

cmake . && cmake --build .
Run Code Online (Sandbox Code Playgroud)

libmerged.so 导出的符号:

$ nm -D --defined-only libmerged.so 
0000000000201020 B __bss_start
0000000000201020 D _edata
0000000000201028 B _end
00000000000005a0 T _fini
0000000000000458 T _init
Run Code Online (Sandbox Code Playgroud)

Q为什么不导出符号 HelloWorld 和 GoodbyeWorld?如何解决?

ser*_*gej 6

您需要将--whole-archive选项传递给链接器。在 CMake 中,您可以按如下方式进行。

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.2)

add_library(unit1 STATIC unit1.c)
target_compile_options(unit1 PRIVATE -fPIC)

add_library(unit2 STATIC unit2.c)
target_compile_options(unit2 PRIVATE -fPIC)

add_library(merged SHARED)
set_target_properties(merged PROPERTIES LINKER_LANGUAGE C)
target_link_libraries(merged
        "-Wl,--whole-archive libunit1.a libunit2.a -Wl,--no-whole-archive"
        unit1 unit2
)
Run Code Online (Sandbox Code Playgroud)

注意:该target_link_libraries命令还可用于指定链接器标志,而不仅仅是库名称。引号很重要,否则 CMake 可能会重新排列标志并删除重复项。

导出的符号

$ nm libmerged.so | grep " T "
000000000000065d T GoodbyeWorld
000000000000064a T HelloWorld
0000000000000670 T _fini
0000000000000520 T _init
Run Code Online (Sandbox Code Playgroud)

为避免该问题,另一种选择是为和创建OBJECT而不是STATIC库。unit1unit2

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.2)

add_library(unit1 STATIC unit1.c)
target_compile_options(unit1 PRIVATE -fPIC)

add_library(unit2 STATIC unit2.c)
target_compile_options(unit2 PRIVATE -fPIC)

add_library(merged SHARED)
set_target_properties(merged PROPERTIES LINKER_LANGUAGE C)
target_link_libraries(merged
        "-Wl,--whole-archive libunit1.a libunit2.a -Wl,--no-whole-archive"
        unit1 unit2
)
Run Code Online (Sandbox Code Playgroud)