Що робити, якщо у мене є дві бібліотеки, які надають функції з еквівалентними іменами?
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.
Ось думка. Відкрийте одну з бібліотек-порушників у шістнадцятковому редакторі та змініть усі випадки порушувальних рядків на щось інше. Тоді ви зможете використовувати нові імена у всіх майбутніх дзвінках.
ОНОВЛЕННЯ: Я щойно зробив це з цього приводу, і, здається, це працює. Звичайно, я цього ретельно не перевірив - можливо, це не більше, ніж справді хороший спосіб обдути ногу дробовиком із шестигранною рушницею.
Якщо припустити, що ви використовуєте 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()
яке дозволяє програмно обробляти динамічні бібліотеки. Якщо вам не потрібні дві функції одночасно, ви можете відкрити першу бібліотеку, використати першу функцію та закрити першу бібліотеку перед використанням другої бібліотеки / функції.
Якщо у вас там є .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.Ця проблема є причиною того, що c ++ має простори імен. Насправді не є чудовим рішенням в c для 2 сторонніх бібліотек, що мають однакову назву.
Якщо це динамічний об'єкт, ви можете явно завантажити спільні об'єкти (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. Чи проходить длопен процес пошуку зіткнень? Якщо цього не сталося, OP може просто завантажити обидві бібліотеки вручну і призначити нові імена всім функціям, які надають його бібліотеки.