Bagaimana cara menentukan preferensi jalur perpustakaan?

95

Saya sedang menyusun program c ++ menggunakan g++dan ld. Saya memiliki .soperpustakaan yang ingin saya gunakan selama menautkan. Namun, perpustakaan dengan nama yang sama ada di dalamnya /usr/local/lib, dan ldmemilih perpustakaan itu daripada yang saya tentukan secara langsung. Bagaimana cara memperbaikinya?

Untuk contoh di bawah ini, file perpustakaan saya adalah /my/dir/libfoo.so.0. Hal-hal yang saya coba yang tidak berhasil:

  • perintah g ++ saya adalah g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • menambahkan /my/dirke awal atau akhir $PATHvariabel en` saya
  • menambahkan /my/dir/libfoo.so.0sebagai argumen ke g ++
Heinrich Schmetterling
sumber
1
Apa yang lainnya libfoo.*file ada dan di mana - .sow / o .0, .a, dll?
Alex Martelli

Jawaban:

94

Tambahkan jalur ke tempat perpustakaan baru Anda berada LD_LIBRARY_PATH(memiliki nama yang sedikit berbeda di Mac ...)

Solusi Anda harus bekerja dengan menggunakan -L/my/dir -lfooopsi, pada waktu proses gunakan LD_LIBRARY_PATH untuk menunjuk ke lokasi perpustakaan Anda.

Hati-hati dengan menggunakan LD_LIBRARY_PATH - singkatnya (dari tautan):

..implikasi ..:
Keamanan : Ingat bahwa direktori yang ditentukan dalam LD_LIBRARY_PATH dicari sebelum (!) lokasi standar? Dengan cara itu, orang jahat dapat membuat aplikasi Anda memuat versi pustaka bersama yang berisi kode berbahaya! Itulah salah satu alasan mengapa executable setuid / setgid mengabaikan variabel itu!
Performa: Pemuat tautan harus mencari semua direktori yang ditentukan, sampai menemukan direktori tempat perpustakaan bersama berada - untuk SEMUA perpustakaan bersama yang ditautkan dengan aplikasi! Ini berarti banyak panggilan sistem ke open (), yang akan gagal dengan “ENOENT (Tidak ada file atau direktori seperti itu)”! Jika jalur berisi banyak direktori, jumlah panggilan yang gagal akan meningkat secara linier, dan Anda dapat mengetahuinya dari waktu start-up aplikasi. Jika beberapa (atau semua) direktori berada dalam lingkungan NFS, waktu start-up aplikasi Anda bisa sangat lama - dan dapat memperlambat seluruh sistem!
Inkonsistensi: Ini adalah masalah yang paling umum. LD_LIBRARY_PATH memaksa aplikasi untuk memuat pustaka bersama yang tidak ditautkan, dan kemungkinan besar tidak kompatibel dengan versi aslinya. Ini bisa sangat jelas, yaitu aplikasi macet, atau dapat menyebabkan hasil yang salah, jika perpustakaan yang diambil tidak cukup berfungsi seperti yang dilakukan versi aslinya. Terutama yang terakhir terkadang sulit untuk di-debug.

ATAU

Gunakan opsi rpath melalui gcc ke linker - jalur pencarian pustaka runtime, akan digunakan alih-alih mencari di dir standar (opsi gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

Ini bagus untuk solusi sementara. Linker terlebih dahulu mencari pustaka LD_LIBRARY_PATH sebelum melihat ke direktori standar.

Jika Anda tidak ingin memperbarui LD_LIBRARY_PATH secara permanen, Anda dapat melakukannya dengan cepat di baris perintah:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

Anda dapat memeriksa apa yang diketahui linker perpustakaan tentang penggunaan (contoh):

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

Dan Anda dapat memeriksa perpustakaan mana yang digunakan aplikasi Anda:

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
sumber
23
LD_LIBRARY_PATHdicari saat runtime, pada waktu kompilasi yang ingin Anda setel LIBRARY_PATH. Lihat gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Bjoern Dahlgren
1
Jika perpustakaan Anda benar-benar berbeda dari perpustakaan sistem, yaitu yang selalu digunakan, harap gunakan solusi rpath. LD_LIBRARY_PATH adalah hack untuk pengujian dan tidak diperlukan untuk membuat pekerjaan yang dapat dieksekusi dengan benar.
pengguna2746401
1
DYLD_LIBRARY_PATH untuk Mac
cbinder
Berikut adalah contoh perintah lengkap (untuk C) yang bekerja berdasarkan jawaban ini:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue
25

Ini adalah pertanyaan lama, tapi sepertinya tidak ada yang menyebutkan ini.

Anda beruntung karena semuanya terhubung.

Anda perlu berubah

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

untuk ini:

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

Linker Anda melacak simbol yang perlu diselesaikan. Jika ia membaca pustaka terlebih dahulu, ia tidak memiliki simbol yang diperlukan, jadi ia mengabaikan simbol di dalamnya. Tentukan pustaka setelah hal-hal yang perlu ditautkan ke mereka sehingga penaut Anda memiliki simbol untuk ditemukan di dalamnya.

Juga, -lfoobuat itu mencari file bernama libfoo.aatau libfoo.sosesuai kebutuhan. Tidak libfoo.so.0. Begitu jugaln nama atau ganti nama perpustakaan sebagai appopriate.

Untuk mengutip halaman manual 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.

Menambahkan file secara langsung ke g++baris perintah seharusnya sudah bekerja, kecuali tentu saja, Anda meletakkannya sebelumnya bar.cpp, menyebabkan linker mengabaikannya karena tidak memiliki simbol yang diperlukan, karena belum ada simbol yang diperlukan.

Michael Speer
sumber
22

Menentukan jalur absolut ke perpustakaan seharusnya berfungsi dengan baik:

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

Apakah Anda ingat untuk menghapus -lfoosetelah Anda menambahkan jalur absolut?

R Samuel Klatchko
sumber
1
Solusi ini juga berfungsi dengan baik untuk saya - mencoba menautkan ke versi Qt5 selain paket pengembangan distro. Terima kasih.
wump
Bagaimana cara membuat ini berfungsi untuk @simbol berversi? Contoh minimal: github.com/cirosantilli/cpp-cheat/blob/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
11

Sebagai alternatif, Anda bisa menggunakan variabel lingkungan LIBRARY_PATHdan CPLUS_INCLUDE_PATH, yang masing-masing menunjukkan di mana mencari perpustakaan dan di mana mencari header ( CPATHjuga akan melakukan pekerjaan itu), tanpa menentukan opsi -L dan -I.

Edit: CPATHmenyertakan tajuk dengan -Idan CPLUS_INCLUDE_PATHdengan -isystem.

Alexandre Hamez
sumber
Bisakah Anda menambahkan contoh untuk penggunaan?
Hanna Khalil
export LIBRARY_PATH = /path/to/libdalam sesi konsol yang sama di mana Anda mengompilasi
Alexandre Hamez
0

Jika salah satu digunakan untuk bekerja dengan DLL di Windows dan ingin melewati nomor versi .so di linux / QT, menambahkan CONFIG += pluginakan menghilangkan nomor versi. Untuk menggunakan jalur absolut ke .so, memberikannya ke linker berfungsi dengan baik, seperti yang disebutkan oleh Tn. Klatchko.

Pekka Lehtikoski
sumber