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

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

Ответ 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 файле

или

  1. 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 в вызывающем. Если в библиотеке много файлов, проще использовать заголовок или заголовки, которые обертывают определения, включает и отменяет, а затем используют этот заголовок.

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