Что делать, если у меня есть две библиотеки, которые предоставляют функции с эквивалентными именами?
Что делать, если две библиотеки предоставляют функцию с тем же именем, что и конфликт?
Ответ 1
- Если вы управляете одним или обоими: отредактируйте его, чтобы изменить имя и перекомпилировать. Или аналогично см. Ben и unknown ответы, которые будут работать без доступа к исходному коду.
- Если вы не контролируете ни один из них, вы можете обернуть один из них. Это компилирует другую ( статически связанную!) Библиотеку, которая ничего не делает, кроме реэкспорта всех символов оригинала, за исключением оскорбительного, который достигается через оболочку с альтернативным именем. Какая хлопот.
- Добавлено позже:. Поскольку qeek говорит, что он говорит о динамических библиотеках, решения, предлагаемые Ferruccio и mouviciel, вероятно, лучше всего. (Кажется, я живу в давние времена, когда статическая привязка была по умолчанию. Она окрашивает мои мысли.)
По поводу комментариев: "Экспорт" я хочу сделать видимым для модулей, связанных с библиотекой, - эквивалентно ключевому слову extern
в области файлов. Как это контролируется, зависит OS и линкер. И это то, что мне всегда нужно искать.
Ответ 2
Можно переименовать символы в объектном файле с помощью objcopy --redefine-sym old=new file
(см. man objcopy).
Затем просто вызовите функции, используя их новые имена и связавшись с новым объектным файлом.
Ответ 3
В 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 поддерживают аналогичную функциональность, но я не могу придумать их имена.
Ответ 4
Вот мысль. Откройте одну из библиотек-нарушителей в шестнадцатеричном редакторе и измените все вхождения строк-нарушителей на что-то другое. Затем вы сможете использовать новые имена во всех будущих вызовах.
UPDATE: Я просто сделал это с этой целью и, похоже, сработал. Конечно, я не тестировал это полностью - это может быть не более, чем действительно хороший способ взорвать ногу с ружьем с гекседитом.
Ответ 5
Вы не должны использовать их вместе. Если я правильно помню, компоновщик выдает ошибку в таком случае.
Я не пытался, но решение может быть с dlopen()
, dlsym()
и dlclose()
, которые позволяют программно обрабатывать динамические библиотеки. Если вам не нужны две функции одновременно, вы можете открыть первую библиотеку, использовать первую функцию и закрыть первую библиотеку перед использованием второй библиотеки/функции.
Ответ 6
Поклянись? Насколько мне известно, вы не можете сделать это, если у вас есть две библиотеки, которые выставляют точки ссылок с тем же именем, и вам нужно связать их с обоими.
Ответ 7
Эта проблема является причиной того, что С++ имеет пространства имен. Там нет действительно отличного решения в c для 2 сторонних библиотек, имеющих одинаковое имя.
Если это динамический объект, вы можете явно загружать совместно используемые объекты (LoadLibrary/dlopen/etc) и называть его таким образом. Альтернативно, если вам не нужны обе библиотеки одновременно в одном и том же коде, вы можете сделать что-то со статической связью (если у вас есть файлы .lib/.a).
Ни одно из этих решений не относится ко всем проектам, конечно.
Ответ 8
Предполагая, что вы используете Linux, вам сначала нужно добавить
#include <dlfcn.h>
Объявить переменную указателя функции в соответствующем контексте, например,
int (*alternative_server_init)(int, char **, char **);
Как Ферруччио заявил в fooobar.com/questions/93514/..., загрузите явно библиотеку, которую вы хотите использовать, выполнив (выберите ваши любимые флаги)
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);
Ответ 9
Вы должны написать библиотеку обертки вокруг одного из них. Ваша библиотека обертки должна выставлять символы с уникальными именами и не выставлять символы неповторимых имен.
Другой вариант - переименование имени функции в файле заголовка и переименование символа в архиве объектов библиотеки.
В любом случае, чтобы использовать оба варианта, это будет трудная работа.
Ответ 10
Я никогда не использовал dlsym, dlopen, dlerror, dlclose, dlvsym и т.д., но я смотрю на страницу man, и это дает пример открытия libm.so и извлечения функции cos. Проводит ли dlopen процесс поиска столкновений? Если это не так, OP может просто загрузить обе библиотеки вручную и назначить новые имена всем функциям, которые предоставляют его библиотеки.
Ответ 11
Если у вас есть файлы .o, здесь есть хороший ответ: fooobar.com/questions/80338/...
Резюме:
-
objcopy --prefix-symbols=pre_string test.o
, чтобы переименовать символы в .o файле
или
-
objcopy --redefine-sym old_str=new_str test.o
, чтобы переименовать определенный символ в файле .o.
Ответ 12
Вопрос приближается к десятилетнему, но есть новые поиски все время...
Как уже было сказано, objcopy с флагом -redefine-sym является хорошим выбором в Linux. См., Например, https://linux.die.net/man/1/objcopy для полной документации. Это немного неуклюже, потому что вы по существу копируете всю библиотеку при внесении изменений, и для каждого обновления требуется повторить эту работу. Но, по крайней мере, он должен работать.
Для Windows динамическая загрузка библиотеки - это решение, и постоянный, такой как альтернатива dlopen в Linux, будет. Однако как dlopen(), так и LoadLibrary() добавляют дополнительный код, которого можно избежать, если единственная проблема - это дубликаты имен. Здесь решение Windows более элегантно, чем подход objcopy: просто сообщите компоновщику, что символы в библиотеке известны другим именем и используют это имя. Вот несколько шагов, чтобы сделать это. Вам нужно создать файл def и предоставить перевод имени в разделе EXPORTS. См. 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 в вызывающем. Если в библиотеке много файлов, проще использовать заголовок или заголовки, которые обертывают определения, включает и отменяет, а затем используют этот заголовок.
Надеюсь, что эта информация была полезной!