Jak określić preferencje dotyczące ścieżki biblioteki?

95

Kompiluję program w języku C ++ przy użyciu g++i ld. mam.so bibliotekę, z której chcę korzystać podczas łączenia. Jednak biblioteka o tej samej nazwie istnieje w programie /usr/local/libi ldwybiera tę bibliotekę zamiast tej, którą bezpośrednio określam. Jak mogę to naprawić?

W poniższych przykładach mój plik biblioteki to /my/dir/libfoo.so.0 . Rzeczy, które próbowałem, ale nie działają:

  • moje polecenie g ++ to g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • dodanie /my/dir na początku lub na końcu mojej $PATHzmiennej en`
  • dodanie /my/dir/libfoo.so.0jako argumentu do g ++
Heinrich Schmetterling
źródło
1
Jakie inne libfoo.*istnieją pliki i gdzie - .sow / o .0, .aitp itd?
Alex Martelli

Odpowiedzi:

94

Dodaj ścieżkę do miejsca, w którym znajduje się twoja nowa biblioteka LD_LIBRARY_PATH(ma nieco inną nazwę na Macu ...)

Twoje rozwiązanie powinno działać z wykorzystaniem -L/my/dir -lfooopcji, w czasie wykonywania użyj LD_LIBRARY_PATH, aby wskazać lokalizację biblioteki.

Ostrożnie z użyciem LD_LIBRARY_PATH - w skrócie (z linku):

..implikacje ..:
Bezpieczeństwo : Pamiętasz, że katalogi określone w LD_LIBRARY_PATH są przeszukiwane przed (!) standardowymi lokalizacjami? W ten sposób nieprzyjemna osoba może spowodować, że aplikacja załaduje wersję biblioteki współdzielonej, która zawiera złośliwy kod! To jeden z powodów, dla których pliki wykonywalne setuid / setgid zaniedbują tę zmienną!
Występ: Program ładujący dowiązania musi przeszukać wszystkie określone katalogi, aż znajdzie katalog, w którym znajduje się biblioteka współdzielona - dla WSZYSTKICH bibliotek współdzielonych, z którymi aplikacja jest połączona! Oznacza to wiele wywołań systemowych open (), które zakończą się niepowodzeniem z komunikatem „ENOENT (Brak takiego pliku lub katalogu)”! Jeśli ścieżka zawiera wiele katalogów, liczba nieudanych wywołań będzie rosła liniowo i można to rozpoznać po uruchomieniu aplikacji. Jeśli niektóre (lub wszystkie) katalogi znajdują się w środowisku NFS, czas uruchamiania aplikacji może być naprawdę długi - i może spowolnić cały system!
Niezgodność: To jest najczęstszy problem. LD_LIBRARY_PATH wymusza na aplikacji załadowanie biblioteki współdzielonej, z którą nie jest połączona, a to prawdopodobnie nie jest zgodne z wersją oryginalną. Może to być bardzo oczywiste, np. Awaria aplikacji, lub może prowadzić do błędnych wyników, jeśli wybrana biblioteka nie do końca robi to, co zrobiłaby wersja oryginalna. Szczególnie to drugie jest czasami trudne do debugowania.

LUB

Użyj opcji rpath przez gcc do konsolidatora - ścieżka przeszukiwania biblioteki uruchomieniowej zostanie użyta zamiast szukać w standardowym katalogu (opcja gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

Jest to dobre rozwiązanie tymczasowe. Linker najpierw przeszukuje LD_LIBRARY_PATH w poszukiwaniu bibliotek, zanim zajrzy do standardowych katalogów.

Jeśli nie chcesz trwale aktualizować LD_LIBRARY_PATH, możesz to zrobić w locie z wiersza poleceń:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

Możesz sprawdzić, o czym konsolidator bibliotek wie (przykład):

/sbin/ldconfig -p | grep libpthread
        libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

Możesz też sprawdzić, której biblioteki używa Twoja aplikacja:

ldd foo
        linux-gate.so.1 =>  (0xffffe000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
        librt.so.1 => /lib/librt.so.1 (0xb7e65000)
        libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
        libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
        /lib/ld-linux.so.2 (0xb7fc7000)
        libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
        libz.so.1 => /lib/libz.so.1 (0xb7c18000)
stefanB
źródło
23
LD_LIBRARY_PATHjest przeszukiwany w czasie wykonywania, w czasie kompilacji, który chcesz ustawić LIBRARY_PATH. Zobacz gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Bjoern Dahlgren
1
Jeśli Twoja biblioteka jest zupełnie inna niż biblioteka systemowa, tj. Jest tą, której należy zawsze używać, użyj rozwiązania rpath. LD_LIBRARY_PATH to hack do testowania i nie powinien być wymagany do prawidłowego działania pliku wykonywalnego.
user2746401
1
jego DYLD_LIBRARY_PATH dla komputerów Mac
cbinder
Oto pełne przykładowe polecenie (dla C), które działa w oparciu o tę odpowiedź:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue
25

To stare pytanie, ale chyba nikt o tym nie wspomniał.

Miałeś szczęście, że coś w ogóle się łączyło.

Musiałeś się zmienić

g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp

do tego:

g++ -g -Wall -o my_binary -L/my/dir bar.cpp -lfoo

Twój linker śledzi symbole, które musi rozwiązać. Jeśli najpierw czyta bibliotekę, nie ma żadnych potrzebnych symboli, więc ignoruje zawarte w niej symbole. Określ biblioteki po rzeczach, które muszą się do nich łączyć, aby twój linker miał symbole do znalezienia w nich.

Ponadto -lfoopowoduje, że wyszukuje konkretnie plik o nazwie libfoo.alub libfoo.sow razie potrzeby. Nie libfoo.so.0. Więc lnnazwij lub zmień nazwę biblioteki odpowiednio.

Cytując stronę podręcznika gcc:

-l library
   ...
   It makes a difference where in the command you 
   write this option; the linker searches and processes 
   libraries and object files in the order they are 
   specified.  Thus, foo.o -lz bar.o searches library z 
   after file foo.o but before bar.o.  If bar.o refers 
   to functions in z, those functions may not be loaded.

Dodanie pliku bezpośrednio do g++wiersza poleceń powinno zadziałać, chyba że oczywiście umieściłeś go wcześniej bar.cpp, powodując, że linker ignoruje go z powodu braku jakichkolwiek potrzebnych symboli, ponieważ żadne symbole nie były jeszcze potrzebne.

Michael Speer
źródło
22

Określenie bezwzględnej ścieżki do biblioteki powinno działać poprawnie:

g++ /my/dir/libfoo.so.0  ...

Czy pamiętałeś, aby usunąć -lfooraz dodaną ścieżkę bezwzględną?

R Samuel Klatchko
źródło
1
To rozwiązanie również działało dobrze - próbowałem połączyć się z wersją Qt5 inną niż pakiet deweloperski dystrybucji. Dzięki.
wump
Jak to działa w przypadku @symboli wersjonowanych? Minimalny przykład: github.com/cirosantilli/cpp-cheat/blob/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
11

Alternatywnie możesz użyć zmiennych środowiskowych LIBRARY_PATHi CPLUS_INCLUDE_PATH, które odpowiednio wskazują, gdzie szukać bibliotek i gdzie szukać nagłówków (CPATH również wykonają zadanie), bez określania opcji -L i -I.

Edit: CPATHzawiera nagłówek z -Ii CPLUS_INCLUDE_PATHz -isystem.

Alexandre Hamez
źródło
Czy mógłbyś dodać przykład do użycia?
Hanna Khalil
export LIBRARY_PATH = /path/to/lib w tej samej sesji konsoli, w której kompilujesz
Alexandre Hamez,
0

Jeśli ktoś jest używany do pracy z DLL w systemie Windows i chciałby pominąć numery wersji .so w linux / QT, dodanie CONFIG += pluginspowoduje usunięcie numerów wersji. Aby użyć bezwzględnej ścieżki do .so, przekazanie jej do linkera działa dobrze, jak wspomniał pan Klatchko.

Pekka Lehtikoski
źródło