Что мне делать, если две библиотеки предоставляют функцию с одинаковым именем, вызывающую конфликт? - PullRequest
75 голосов
/ 24 марта 2009

Что мне делать, если у меня есть две библиотеки, предоставляющие функции с эквивалентными именами?

Ответы [ 12 ]

43 голосов
/ 24 марта 2009

Можно переименовать символы в объектном файле, используя objcopy --redefine-sym old=new file (см. Man objcopy).

Затем просто вызовите функции, используя их новые имена, и свяжите их с новым объектным файлом.

42 голосов
/ 24 марта 2009
  • Если вы управляете одним или обоими: отредактируйте одно, чтобы изменить имя и перекомпилировать. Или эквивалентно посмотрите ответы Ben и unknown , которые будут работать без доступа к исходному коду.
  • Если вы не контролируете ни одного из них, вы можете свернуть один из них. Это компиляция другой ( статически связанной !) Библиотеки, которая ничего не делает, кроме как реэкспортирует все символы оригинала, кроме оскорбительного, который достигается через оболочку с альтернативным именем , Что за хлопоты.
  • Добавлено позже: Поскольку qeek говорит, что он говорит о динамических библиотеках, решения, предложенные Ферруччо и mouviciel , вероятно, являются лучшими. (Я, кажется, живу в давние времена, когда статическая связь была по умолчанию. Она окрашивает мое мышление.)

По поводу комментариев: под "экспортом" я подразумеваю сделать видимыми модули, ссылающиеся на библиотеку - эквивалентно ключевому слову extern в области видимости файла. Как это контролируется, зависит от ОС и линкера. И это то, что я всегда должен искать.

12 голосов
/ 24 марта 2009

В Windows вы можете использовать LoadLibrary () , чтобы загрузить одну из этих библиотек в память, а затем использовать GetProcAddress () , чтобы получить адрес каждой функции, которую нужно вызвать, и вызывать функции через указатель на функцию.

, например

HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);

получит адрес функции с именем bar в foo.dll и вызовет его.

Я знаю, что системы Unix поддерживают аналогичную функциональность, но я не могу вспомнить их имена.

8 голосов
/ 24 марта 2009

Вот мысль. Откройте одну из поврежденных библиотек в шестнадцатеричном редакторе и измените все вхождения поврежденных строк на что-то другое. После этого вы сможете использовать новые имена во всех будущих вызовах.

ОБНОВЛЕНИЕ: Я только что сделал это с этой целью, и, похоже, это сработало. Конечно, я не проверил это полностью - это может быть не более чем хороший способ оторвать ногу с шестигранным дробовиком.

6 голосов
/ 04 июля 2013

Предполагая, что вы используете Linux, вам сначала нужно добавить

#include <dlfcn.h>

Объявите переменную-указатель функции в соответствующем контексте, например,

int (*alternative_server_init)(int, char **, char **);

Как и Ферруччо, заявленный в https://stackoverflow.com/a/678453/1635364, явно загрузите библиотеку, которую вы хотите использовать, выполнив (выберите ваши любимые флаги)

void* dlhandle;
void* sym;

dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);

Считать адрес функции, которую вы хотите вызвать позже

sym = dlsym(dlhandle, "conflicting_server_init");

назначить и разыграть следующим образом

alternative_server_init = (int (*)(int, char**, char**))sym;

Звоните аналогично оригиналу. Наконец, выгрузите, выполнив

dlclose(dlhandle);
6 голосов
/ 24 марта 2009

Вы не должны использовать их вместе. Если я правильно помню, компоновщик выдает ошибку в таком случае.

Я не пробовал, но решение может быть с dlopen(), dlsym() и dlclose(), которые позволяют программно обрабатывать динамические библиотеки. Если вам не нужны две функции одновременно, вы можете открыть первую библиотеку, использовать первую функцию и закрыть первую библиотеку перед использованием второй библиотеки / функции.

4 голосов
/ 24 марта 2009

Эта проблема является причиной того, что c ++ имеет пространства имен. В c нет действительно отличного решения для двух сторонних библиотек с одинаковым именем.

Если это динамический объект, вы можете явно загрузить общие объекты (LoadLibrary / dlopen / и т. Д.) И вызвать его таким образом. С другой стороны, если вам не нужны обе библиотеки в одно и то же время в одном и том же коде, вы можете сделать что-то со статической связью (если у вас есть файлы .lib / .a).

Конечно, ни одно из этих решений не применимо ко всем проектам.

3 голосов
/ 29 декабря 2016

Если у вас есть файлы .o, хороший ответ здесь: https://stackoverflow.com/a/6940389/4705766

Резюме:

  1. objcopy --prefix-symbols=pre_string test.o для переименования символов в .o файле

или

  1. objcopy --redefine-sym old_str=new_str test.o для переименования конкретного символа в .o файле.
3 голосов
/ 24 марта 2009

Поклянись? Насколько я знаю, вы мало что можете сделать, если у вас есть две библиотеки, которые предоставляют точки ссылки с одинаковыми именами, и вам нужно ссылаться на обе.

2 голосов
/ 24 марта 2009

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

Другой вариант - переименовать имя функции в заголовочном файле и переименовать символ в архиве библиотечного объекта.

В любом случае, использовать оба, это будет хакерская работа.

...