Что мне делать, если у меня есть две библиотеки, которые предоставляют функции с эквивалентными именами?
vorbis_...
, sf_...
, sdl_...
). По сути, это то, что C ++ делает с именами символов для функций с именами.
Что мне делать, если у меня есть две библиотеки, которые предоставляют функции с эквивалентными именами?
vorbis_...
, sf_...
, sdl_...
). По сути, это то, что C ++ делает с именами символов для функций с именами.
Ответы:
По поводу комментариев: Под "экспортом" я подразумеваю сделать видимыми модули, связанные с библиотекой - эквивалент 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 поддерживают аналогичную функциональность, но не могу вспомнить их названия.
dlopen
dlsym
, и dlclose
. Однако инкапсуляция в Unix может быть не такой эффективной, как в Windows.
Вот такая мысль. Откройте одну из проблемных библиотек в шестнадцатеричном редакторе и замените все вхождения ошибочных строк на что-то другое. После этого вы сможете использовать новые имена во всех будущих звонках.
ОБНОВЛЕНИЕ: я только что сделал это с этой целью, и, похоже, это сработало. Конечно, я не проверял это полностью - это может быть не более чем действительно хороший способ оторвать себе ногу из дробовика hexedit.
Если у вас есть файлы .o, хороший ответ здесь: https://stackoverflow.com/a/6940389/4705766
Резюме:
objcopy --prefix-symbols=pre_string test.o
переименовать символы в файле .o или
objcopy --redefine-sym old_str=new_str test.o
для переименования конкретного символа в файле .o.Предполагая, что вы используете 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);
Не используйте их вместе. Если я правильно помню, в этом случае компоновщик выдает ошибку.
Я не пробовал, но решение может быть с dlopen()
, dlsym()
и dlclose()
которые позволяют программно обрабатывать динамические библиотеки. Если вам не нужны две функции одновременно, вы можете открыть первую библиотеку, использовать первую функцию и закрыть первую библиотеку перед использованием второй библиотеки / функции.
Эта проблема является причиной того, что в C ++ есть пространства имен. На самом деле нет отличного решения в c для двух сторонних библиотек с одинаковым именем.
Если это динамический объект, вы можете явно загрузить общие объекты (LoadLibrary / dlopen / etc) и вызвать их таким образом. В качестве альтернативы, если вам не нужны обе библиотеки одновременно в одном и том же коде, вы можете что-то сделать со статической компоновкой (если у вас есть файлы .lib / .a).
Конечно, ни одно из этих решений не применимо ко всем проектам.
Поклясться? Насколько мне известно, вы мало что можете сделать, если у вас есть две библиотеки, которые предоставляют точки ссылок с одинаковыми именами, и вам нужно связать их с обеими.
Вы должны написать библиотеку-оболочку вокруг одного из них. Ваша библиотека-оболочка должна предоставлять символы с уникальными именами, а не символы с неуникальными именами.
Другой вариант - переименовать имя функции в файле заголовка и переименовать символ в архиве объектов библиотеки.
В любом случае, использовать оба, это будет хакерская работа.
Вопрос почти десятилетней давности, но все время новые поиски ...
Как уже было сказано, 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. (Для библиотек DLL Windows файлы lib используются только для связывания, но не для выполнения кода.) См. Раздел Как создать файл .lib при наличии файла .dll и файла заголовка, чтобы узнать о процессе построения файла lib. Единственное отличие - добавление псевдонимов.
И для Linux, и для Windows переименуйте функции в заголовках библиотеки, имена которых имеют псевдонимы. Другой вариант, который должен работать, - это в файлах, относящихся к новым именам, #define old_name new_name, #include заголовки библиотеки, экспорт которой является псевдонимом, а затем #undef old_name в вызывающей стороне. Если в библиотеке используется много файлов, более простой альтернативой является создание заголовка или заголовков, которые обертывают определения, включают и undefs, а затем использовать этот заголовок.
Надеюсь, эта информация была полезной!
Я никогда не использовал dlsym, dlopen, dlerror, dlclose, dlvsym и т. Д., Но я смотрю справочную страницу, и на ней приводится пример открытия libm.so и извлечения функции cos. Проходит ли dlopen процесс поиска коллизий? Если этого не произойдет, OP может просто загрузить обе библиотеки вручную и присвоить новые имена всем функциям, которые предоставляют его библиотеки.