Символы из библиотеки stati c не экспортируются при связывании с общей библиотекой - PullRequest
1 голос
/ 17 апреля 2020

Код для разделяемой библиотеки является модульным, состоит из нескольких независимых блоков. Каждое устройство встроено в библиотеку stati c.


unit1. c

#include <stdio.h>

void HelloWorld() {
  printf("Hello World!\n");
}

unit2. c

#include <stdio.h>

void GoodbyeWorld() {
  printf("Goodbye World!\n");
}

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)

Этапы сборки:

cmake . && cmake --build .

Экспортированные символы по libmerged.so:

$ nm -D --defined-only libmerged.so 
0000000000201020 B __bss_start
0000000000201020 D _edata
0000000000201028 B _end
00000000000005a0 T _fini
0000000000000458 T _init

Q Почему символы HelloWorld и GoodbyeWorld не экспортируются? Как это исправить?

  • Я пробовал --version-script безуспешно.

    Дополнительные настройки в CMakeLists.txt

    set_target_properties(merged PROPERTIES LINK_FLAGS -Wl,--version- 
    script=merged.version)
    

    merged.version

    merged {
      global: HelloWorld; GoodbyeWorld;
      local: *;
    };
    
  • Также попытался принудительно загрузить данные c библиотеки без успеха
    set_target_properties(merged PROPERTIES LINK_FLAGS -Wl,-force_load,libunit1.a)
    

1 Ответ

2 голосов
/ 17 апреля 2020

Вам необходимо передать параметр --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
)

Примечание. Команда target_link_libraries может использоваться также для указания флагов компоновщика, а не только имен библиотек. Кавычки важны, в противном случае CMake может переставить флаги и удалить дубликаты.

Экспортируемые символы

$ nm libmerged.so | grep " T "
000000000000065d T GoodbyeWorld
000000000000064a T HelloWorld
0000000000000670 T _fini
0000000000000520 T _init

Другой вариант, чтобы избежать проблемы, - создать OBJECT вместо STATIC библиотек для unit1 и unit2.

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.2)

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

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

add_library(merged SHARED $<TARGET_OBJECTS:unit1> $<TARGET_OBJECTS:unit2>)
set_target_properties(merged PROPERTIES LINKER_LANGUAGE C)
...