Общие библиотеки и компоновка в Linux (elf)

Я прочитал ветку Создание библиотеки с обратно совместимым ABI, которая использует Boost, и теперь я пытаюсь понять, как связать свои разделяемые библиотеки, чтобы поддерживать стабильный ABI и избегать проблем с мешающими символами.

Я создал следующий простой тестовый проект:

cat <<EOF > a.c
#define ABI __attribute__((visibility("default")))

int common();
int ABI a() { return common() + 1; }
EOF

cat <<EOF > b.c
#define ABI __attribute__((visibility("default")))

int common();
int ABI b() { return common() + 2; }
EOF

cat <<EOF > common_v1.c
int common() { return 1; }
EOF

cat <<EOF > common_v2.c
int common() { return 2; }
EOF

cat <<EOF > test.c
#include <assert.h>

int a();
int b();

int main(int argc, const char *argv[])
{
    assert( a() + b() == 6 );
    return 0;
}
EOF

cat <<EOF > CMakeLists.txt
cmake_minimum_required(VERSION 2.8)

project(TEST)

add_library(common_v1 STATIC common_v1.c)
add_library(common_v2 STATIC common_v2.c)

SET_SOURCE_FILES_PROPERTIES( a.c b.c COMPILE_FLAGS -fvisibility=hidden )
add_library(a SHARED a.c)
target_link_libraries(a common_v1)

add_library(b SHARED b.c)
target_link_libraries(b common_v2)

add_executable(test test.c)
target_link_libraries(test a b)
EOF

Библиотеки common_v1 и common_v2 должны имитировать внешнюю зависимость библиотек a и b (например, Boost). Поскольку common_v1 и common_v2 считаются внешними библиотеками, я бы предпочел не менять их систему сборки (и не менять там флаги, с которыми они компилируются).

Вышеупомянутый проект компилируется нормально, но не работает! Когда тестовое приложение выполняется, оно переходит к оператору assert.

Это заставляет меня поверить, что одно и то же определение common используется как в liba, так и в libb. Почему так и что я делаю не так?


person Allan    schedule 07.12.2011    source источник


Ответы (1)


Вы можете исправить свою тестовую программу, используя параметр --retain-symbols-file в ld при создании ваших библиотек a и b и сохраните только символы a() и b(), так что символ common() не будет экспортирован этими библиотеками (и, следовательно, одна библиотека не будет пытаться использовать символ common() из другой):

  --retain-symbols-file filename
        Retain only the symbols listed in the file filename, discarding all
        others. filename is simply a flat file, with one symbol name per line.

Также вы можете использовать опцию --version-script:

  --version-script=version-scriptfile
        Specify the name of a version script to the linker.

где version-scriptfile это следующее:

  FOO {
    global: a; b; # symbols to be exported
    local: *;     # hide others
  };

Связанные темы:

person linuxbuild    schedule 07.12.2011