Co powinienem zrobić, jeśli mam dwie biblioteki, które udostępniają funkcje o równoważnych nazwach?
vorbis_...
, sf_...
, sdl_...
). To jest zasadniczo to, co C ++ robi z nazwami symboli dla funkcji w przestrzeni nazw.
Co powinienem zrobić, jeśli mam dwie biblioteki, które udostępniają funkcje o równoważnych nazwach?
vorbis_...
, sf_...
, sdl_...
). To jest zasadniczo to, co C ++ robi z nazwami symboli dla funkcji w przestrzeni nazw.
Odpowiedzi:
A propos komentarzy: Przez „eksport” mam na myśli pokazanie modułów łączących się z biblioteką - odpowiednik extern
słowa kluczowego w zakresie pliku. Sposób kontrolowania tego zależy od systemu operacyjnego i konsolidatora. I zawsze muszę na to patrzeć.
Istnieje możliwość zmiany nazw symboli w pliku obiektowym za pomocą objcopy --redefine-sym old=new file
(zobacz man objcopy).
Następnie po prostu wywołaj funkcje, używając ich nowych nazw i połącz się z nowym plikiem obiektowym.
W systemie Windows możesz użyć LoadLibrary (), aby załadować jedną z tych bibliotek do pamięci, a następnie użyć GetProcAddress (), aby uzyskać adres każdej funkcji, którą musisz wywołać, i wywołać funkcje za pomocą wskaźnika funkcji.
na przykład
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);
pobierze adres funkcji o nazwie bar w foo.dll i wywoła ją.
Wiem, że systemy Unix obsługują podobną funkcjonalność, ale nie mogę wymyślić ich nazw.
dlopen
dlsym
, i dlclose
. Jednak hermetyzacja w systemie Unix może nie być tak skuteczna, jak w systemie Windows.
Oto myśl. Otwórz jedną z naruszających bibliotek w edytorze szesnastkowym i zmień wszystkie wystąpienia naruszających ciągów na coś innego. Powinieneś wtedy móc używać nowych nazw we wszystkich przyszłych połączeniach.
AKTUALIZACJA: Właśnie to zrobiłem w tym celu i wydaje się, że działa. Oczywiście nie przetestowałem tego dokładnie - może to być nic więcej niż naprawdę dobry sposób na odstrzelenie nogi za pomocą strzelby hekseditowej.
Jeśli masz tam pliki .o, dobra odpowiedź tutaj: https://stackoverflow.com/a/6940389/4705766
Podsumowanie:
objcopy --prefix-symbols=pre_string test.o
aby zmienić nazwy symboli w pliku .o lub
objcopy --redefine-sym old_str=new_str test.o
aby zmienić nazwę określonego symbolu w pliku .o.Zakładając, że używasz Linuksa, musisz najpierw dodać
#include <dlfcn.h>
Zadeklaruj zmienną wskaźnika funkcji w odpowiednim kontekście, na przykład
int (*alternative_server_init)(int, char **, char **);
Jak Ferruccio podał na https://stackoverflow.com/a/678453/1635364 , załaduj jawnie bibliotekę, której chcesz użyć, wykonując (wybierz swoje ulubione flagi)
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
Przeczytaj adres funkcji, którą chcesz wywołać później
sym = dlsym(dlhandle, "conflicting_server_init");
przypisać i obsadzić w następujący sposób
alternative_server_init = (int (*)(int, char**, char**))sym;
Zadzwoń podobnie jak oryginał. Na koniec zwolnij, wykonując
dlclose(dlhandle);
Nie powinieneś ich używać razem. O ile dobrze pamiętam, w takim przypadku linker wystawia błąd.
Nie próbowałem, ale to rozwiązanie może być z dlopen()
, dlsym()
i dlclose()
które pozwalają obsłużyć programowo bibliotek dynamicznych. Jeśli nie potrzebujesz tych dwóch funkcji w tym samym czasie, możesz otworzyć pierwszą bibliotekę, użyć pierwszej funkcji i zamknąć pierwszą bibliotekę przed użyciem drugiej biblioteki / funkcji.
Ten problem jest powodem, dla którego C ++ ma przestrzenie nazw. Nie ma dobrego rozwiązania w c dla 2 bibliotek innych firm o tej samej nazwie.
Jeśli jest to obiekt dynamiczny, możesz jawnie załadować udostępnione obiekty (LoadLibrary / dlopen / etc) i wywołać je w ten sposób. Alternatywnie, jeśli nie potrzebujesz obu bibliotek w tym samym czasie w tym samym kodzie, możesz zrobić coś z łączeniem statycznym (jeśli masz pliki .lib / .a).
Oczywiście żadne z tych rozwiązań nie dotyczy wszystkich projektów.
Przysięgać? O ile mi wiadomo, niewiele możesz zrobić, jeśli masz dwie biblioteki, które ujawniają punkty dowiązań o tej samej nazwie i musisz połączyć je z obydwoma.
Wokół jednego z nich należy napisać bibliotekę opakowującą. Twoja biblioteka opakowań powinna udostępniać symbole o unikalnych nazwach, a nie symbole o nieunikalnych nazwach.
Inną opcją jest zmiana nazwy funkcji w pliku nagłówkowym i zmiana nazwy symbolu w archiwum obiektów biblioteki.
Tak czy inaczej, aby użyć obu, będzie to hack.
Pytanie zbliża się do dekady, ale cały czas pojawiają się nowe wyszukiwania ...
Jak już odpowiedziałem, objcopy z flagą --redefine-sym to dobry wybór w Linuksie. Zobacz na przykład https://linux.die.net/man/1/objcopy aby uzyskać pełną dokumentację. Jest to trochę niezgrabne, ponieważ zasadniczo kopiujesz całą bibliotekę podczas wprowadzania zmian, a każda aktualizacja wymaga powtórzenia tej pracy. Ale przynajmniej powinno działać.
W przypadku systemu Windows dynamiczne ładowanie biblioteki jest rozwiązaniem i trwałym rozwiązaniem, takim jak alternatywa dlopen w systemie Linux. Jednak zarówno dlopen (), jak i LoadLibrary () dodają dodatkowy kod, którego można uniknąć, jeśli jedynym problemem są zduplikowane nazwy. W tym przypadku rozwiązanie Windows jest bardziej eleganckie niż podejście objcopy: po prostu powiedz konsolidatorowi, że symbole w bibliotece są znane pod inną nazwą i użyj tej nazwy. Jest kilka kroków, aby to zrobić. Musisz utworzyć plik def i podać tłumaczenie nazwy w sekcji EKSPORT. Zobacz https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, ostatecznie zostanie zastąpiony przez nowsze wersje) lub http://www.digitalmars.com/ctg/ctgDefFiles.html(prawdopodobnie trwalsze) dla pełnych szczegółów składni pliku def. Proces polegałby na utworzeniu pliku def dla jednej z bibliotek, a następnie wykorzystaniu tego pliku def do zbudowania pliku lib, a następnie połączeniu z tym plikiem lib. (W przypadku bibliotek DLL systemu Windows pliki lib są używane tylko do łączenia, a nie wykonywania kodu). Zobacz Jak utworzyć plik .lib, jeśli mają plik .dll i plik nagłówkowy. dla procesu budowania pliku lib. Tutaj jedyną różnicą jest dodanie aliasów.
Zarówno w systemie Linux, jak i Windows zmień nazwy funkcji w nagłówkach biblioteki, której nazwy są aliasowane. Inną opcją, która powinna działać, byłaby w plikach odwołujących się do nowych nazw, #define stara_nazwa nowa_nazwa, # uwzględnienie nagłówków biblioteki, której eksport jest aliasowany, a następnie #undef stara_nazwa w programie wywołującym. Jeśli biblioteka korzysta z wielu plików, łatwiejszą alternatywą jest utworzenie nagłówka lub nagłówków, które zawijają definicje, dołączenia i undefs, a następnie użycie tego nagłówka.
Mam nadzieję, że te informacje były pomocne!
Nigdy nie używałem dlsym, dlopen, dlerror, dlclose, dlvsym itp., Ale patrzę na stronę podręcznika systemowego i podaje przykład otwarcia libm.so i wyodrębnienia funkcji cos. Czy dlopen przechodzi przez proces wyszukiwania kolizji? Jeśli tak się nie stanie, OP może po prostu załadować obie biblioteki ręcznie i przypisać nowe nazwy wszystkim funkcjom, które zapewniają jego biblioteki.