2010-07-12 2 views
26

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

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

Ошибок во время сборки нет, но во время выполнения приложения seg faults. Причина, по-видимому, заключается в том, что в версии X используются структуры, размер которых отличается от Y, а компоновщик времени исполнения, похоже, смешивается, и к ним привыкнуть.

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

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

+0

Можете ли вы настроить динамическое подключение своего приложения к VENDOR1? –

+0

Никоим образом не является нейтральным языком. Это очень специфично для компоновщика компилятора и ОС, как все они работают вместе. Самый простой способ - отправить по электронной почте обоих вендеров и посмотреть, как они решают эту проблему. –

+0

Наше настоящее мышление, по крайней мере, по Linux, для использования dlopen() на libbar.so с флагом RTLD_DEEPBIND. Другая возможность состоит в том, чтобы отделить использование libfoo.a от приложений в общей библиотеке libbaz.so, которая обертывает использование libfoo.a, а затем приложение dlopen libbaz.so и libbar.so с RTLD_LOCAL, которое, как мы думаем, может содержать все дубликаты символов. Это может работать для Linux, но нам это нужно, поэтому работайте над Solaris, AIX и HPUX. – YerBlues

ответ

11

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

В 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; 
} 

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

#include <stdio.h> 

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

Compile 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 

Compile main.c и связь с общей библиотеки libfoo.so

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

Установить LD_LIBRARY_PATH, чтобы найти libfoo.поэтому и запустить 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, но оно устраняет мою проблему.

Еще раз спасибо за комментарии.

1

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

+0

"и, возможно, большинство * nixes" - кроме AIX. В AIX, который действительно возможен, и поведение компоновщика по умолчанию делает именно то, что задает вопрос. – Dummy00001

+0

OS X также обрабатывает это изящно. У каждого .so/.dylib есть своя таблица ссылок/ссылок. Я сказал * most * именно потому, что знаю, что это еще не все. Во всяком случае, Linux не делает этого, AFAIK. – Gianni

5

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

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

Смежные вопросы