Связывание с несколькими версиями библиотеки - PullRequest
30 голосов
/ 13 июля 2010

У меня есть приложение, которое статически связывается с версией X библиотеки, libfoo, от стороннего поставщика, VENDOR1. Он также связывается с динамической (общей) библиотекой libbar от другого стороннего поставщика, VENDOR2, которая статически связывает версию Y libfoo с VENDOR1.

Таким образом, libbar.so содержит версию Y файла libfoo.a, а мой исполняемый файл содержит версию X файла libfoo.a. libbar использует libfoo только для внутреннего использования, и из моего приложения в libbar не передаются объекты libfoo.

Нет ошибок во время сборки, но во время работы приложения происходит сбой. Кажется, причина в том, что версия X использует структуры, которые имеют другой размер, чем версия Y, и компоновщик времени выполнения, похоже, перепутывает, к чему привык.

И VENDOR1, и VENDOR2 являются закрытым исходным кодом, поэтому я не могу восстановить их.

Есть ли способ собрать / связать мое приложение так, чтобы оно всегда разрешалось до версии X, а libbar всегда разрешалось до версии Y, и эти два никогда не смешивались?

Ответы [ 3 ]

15 голосов
/ 14 июля 2010

Спасибо за все ответы.У меня есть решение, которое, кажется, работает.Вот проблема подробно с примером.

В main.c у нас есть:

#include <stdio.h>

extern int foo();

int bar()
{
    printf("bar in main.c called\n");
    return 0;
}

int main()
{
    printf("result from foo is %d\n", foo());
    printf("result from bar is %d\n", bar());
}

В foo.c у нас есть:

extern int bar();

int foo()
{
    int x = bar();
    return x;
}

В баре.c имеем:

#include <stdio.h>

int bar()
{
    printf("bar in bar.c called\n");
    return 2;
}

Скомпилируйте bar.c и foo.c:

$ gcc -fPIC -c bar.c
$ gcc -fPIC -c foo.c

Добавьте bar.o в статическую библиотеку:

$ ar r libbar.a bar.o

Сейчассоздать общую библиотеку, используя foo.o, и связать со статическим libbar.a

$ gcc -shared -o libfoo.so foo.o -L. -lbar

Скомпилировать main.c и связать с общей библиотекой libfoo.so

$ gcc -o main main.c -L. -lfoo

Установить LD_LIBRARY_PATH для поиска libfoo.so и запустите main:

$ setenv LD_LIBRARY_PATH `pwd`
$ ./main
bar in main.c called
result from foo is 0
bar in main.c called
result from bar is 0

Обратите внимание, что вызывается версия bar в main.c, а не версия, связанная с общей библиотекой.

В main2.c мы имеем:

#include <stdio.h>
#include <dlfcn.h>


int bar()
{
    printf("bar in main2.c called\n");
    return 0;
}

int main()
{
    int x;
    int (*foo)();
    void *handle = dlopen("libfoo.so", RTLD_GLOBAL|RTLD_LAZY);
    foo = dlsym(handle, "foo");
    printf("result from foo is %d\n", foo());
    printf("result from bar is %d\n", bar());
}

Скомпилируйте и запустите main2.c (обратите внимание, нам не нужно явно ссылаться на libfoo.so):

$ gcc -o main2 main2.c -ldl
$ ./main2
bar in bar.c called
result from foo is 2
bar in main2.c called
result from bar is 0

Теперь foo на панели вызовов общей библиотеки в общей библиотекеи панель основных вызовов в файле main.c

Я не думаю, что это поведение интуитивно понятно, и использование dlopen / dlsym требует больших усилий, но это действительно решает мою проблему.

Еще раз спасибо засomments.

6 голосов
/ 13 июля 2010

Попробуйте частичную ссылку, чтобы у вас был объектный файл "part.o" с libbar и libfoo-Y. Используйте objcopy с "--localize-symbols", чтобы сделать символы вpart.o из libfoo-Y локальными. Вы должны быть в состоянии генерировать, запустив nm на libfoo-Y и массируя вывод. Затем возьмите измененный файлpart.o и свяжите его с вашим приложением.

Я сделал нечто похожее с gcc toolchain на vxWorks, где динамические библиотеки - не сложность, а две версии одной и той же библиотеки, необходимые для чистой ссылки в монолитное приложение.

2 голосов
/ 13 июля 2010

Извините, нет. Я понимаю, что Linux (и, возможно, большинство * nixes) таков, что это невозможно. Единственное «решение» вашей проблемы, о котором я могу подумать, - это если вы создаете прокси-приложение, которое отображает то, что вам нужно, из libbar в виде некоторого IPC . Затем вы можете заставить этот прокси загружать правильную версию, используя LD_LIBRARY_PATH или что-то похожее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...