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


Что делать, если у меня есть две библиотеки, которые содержат функции с аналогичными названиями?

12 67

12 ответов:

  • Если вы управляете одним или обоими: "правка", чтобы изменить имя и перекомпилировать или эквивалентно см. Бен и неизвестный ' ы ответы, которые будут работать без доступ к исходному коду.
  • Если вы не контролируете ни один из них, вы можете завернуть один из них. То есть составить другое (статически!) библиотека, которая ничего не делает, кроме реэкспорта всех символов оригинала, кроме оскорбительного, который достигается через обертку с альтернативным именем. Какая морока.
  • потом добавил: поскольку qeek говорит, что он говорит о динамических библиотеках, решения, предложенные Ферруччо и mouviciel, вероятно, лучше. (Я, кажется, живу в давние времена, когда статическая связь была по умолчанию. Это окрашивает мое мышление.)

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

можно переименовать символы в объектном файле с помощью objcopy --redefine-sym old=new file (см. man objcopy).

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

под 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 поддерживают подобную функциональность, но я не могу думать об их именах.

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

обновление: Я просто сделал это, и он, кажется, работает. конечно, я не проверял это тщательно - это может быть не более чем действительно хороший способ, чтобы взорвать вашу ногу с hexedit дробовика.

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

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

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

эта проблема является причиной того, что c++ имеет пространства имен. На самом деле нет отличного решения в c для 2 сторонних библиотек, имеющих одно и то же имя.

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

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

предполагая, что вы используете 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);

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

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

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

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

резюме:

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

или

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

Я никогда не использовал dlsym, dlopen, dlerror, dlclose, dlvsym и т. д., но я смотрю на man-страницу, и она дает пример открытия libm.so и извлечение функции cos. Проходит ли dlopen процесс поиска коллизий? Если это не так, OP может просто загрузить обе библиотеки вручную и назначить новые имена всем функциям, которые предоставляют его библиотеки.

вопрос приближается к десятилетней давности, но все время появляются новые поиски...

Как уже было сказано, objcopy с флагом --redefine-sym является хорошим выбором в Linux. См., например, https://linux.die.net/man/1/objcopy для полной документации. Это немного неуклюже, потому что вы по существу копируете всю библиотеку при внесении изменений, и каждое обновление требует повторения этой работы. Но, по крайней мере, это должно сработать.

для Windows, динамическая загрузка библиотеки-это решение и постоянное, как альтернатива dlopen в Linux. Однако и dlopen (), и LoadLibrary () добавляют дополнительный код, которого можно избежать, если единственной проблемой является дублирование имен. Здесь Решение Windows является более элегантным, чем подход objcopy: просто скажите компоновщику, что символы в библиотеке известны под каким-то другим именем и используйте это имя. Там несколько шагов, чтобы сделать это. Вам нужно сделать def-файл и предоставить перевод имени в раздел экспорта. См.https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, он в конечном итоге будет заменен более новыми версиями) или http://www.digitalmars.com/ctg/ctgDefFiles.html (вероятно, более постоянный) для полной синтаксической информации о файле def. Процесс будет состоять в том, чтобы сделать файл def для одной из библиотек, а затем использовать этот файл def для создания файла lib, а затем связать его с этим файлом lib. (Для Windows dll файлы lib используются только для связывания, а не для кода исполнение.) Смотрите как сделать .lib файл когда есть .dll файл и файл заголовка для процесса построения файла lib. Здесь единственное различие заключается в добавлении псевдонимов.

как для Linux, так и для Windows переименуйте функции в заголовках библиотеки, имена которых псевдонимы. Другим вариантом, который должен работать, было бы в файлах, ссылающихся на новые имена, #define old_name new_name, #include заголовки библиотеки, экспорт которой алиасируется, и затем #undef old_name в вызывающем абоненте. Если есть много файлов, использующих библиотеку, более простой альтернативой является создание заголовка или заголовков, которые обертывают defines, includes и undefs, а затем используют этот заголовок.

надеюсь, что эта информация была полезна!