Tidak dapat menemukan .so di direktori yang sama dengan yang dapat dieksekusi?


45

Saya memiliki executable yang perlu dihubungkan dengan libtest.sosecara dinamis, jadi saya meletakkannya di direktori yang sama, lalu:

cd path_to_dir
./binary

Tapi dapatkan ini:

error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

Bagaimana tidak dapat menemukan libtest.soyang sudah ada di direktori yang sama dengan yang dapat dieksekusi itu sendiri?

Jawaban:


25

Loader tidak pernah memeriksa direktori saat ini untuk objek yang dibagikan kecuali secara eksplisit diarahkan ke via $LD_LIBRARY_PATH. Lihat ld.so(8)halaman manual untuk lebih jelasnya.


echo $LD_LIBRARY_PATHkosong di komputer saya :(
linuxer

Biasanya begitu.
Ignacio Vazquez-Abrams

2
Ini menentukan direktori tambahan untuk loader untuk mencari perpustakaan.
Ignacio Vazquez-Abrams

1
Path di * nix dipisahkan oleh titik dua ( :), bukan titik koma.
Ignacio Vazquez-Abrams

3
LD_LIBRARY_PATH umumnya merupakan pilihan yang buruk dalam produksi. Ini bagus untuk peretasan cepat, dan hal-hal seperti membantu binari yang dihapus instal menemukan pustaka bersama mereka saat menjalankan tes unit (pikirkan ./configure; make; make check). Saat membuat biner, Anda bisa meletakkan pustaka di lokasi standar (terdaftar di /etc/ld.so.conf) atau meneruskan flag -R ke linker untuk memberi tahu biner ke mana harus mencari.
automatthias

57

Meskipun Anda dapat mengatur LD_LIBRARY_PATH agar pemberi tautan dinamis tahu ke mana harus mencari, ada opsi yang lebih baik. Anda dapat meletakkan perpustakaan Anda bersama di salah satu tempat standar, lihat /etc/ld.so.conf(di Linux) dan /usr/bin/crle(di Solaris) untuk daftar tempat-tempat ini

Anda dapat meneruskan -R <path>ke tautan saat membuat biner, yang akan menambah <path>daftar direktori yang dipindai untuk pustaka bersama Anda. Ini sebuah contoh. Pertama, menunjukkan masalah:

libtest.h:

void hello_world(void);

libtest.c:

#include <stdio.h>
void hello_world(void) {
  printf("Hello world, I'm a library!\n");
}

hello.c:

#include "libtest.h"
int main(int argc, char **argv) {
  hello_world();
}

Makefile (tab harus digunakan):

all: hello
hello: libtest.so.0
%.o: %.c
        $(CC) $(CFLAGS) -fPIC -c -o $@ $<
libtest.so.0.0.1: libtest.o
        $(CC) -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
libtest.so.0: libtest.so.0.0.1
        ln -s $< $@
clean:
        rm -f hello libtest.o hello.o libtest.so.0.0.1 libtest.so.0

Mari kita jalankan:

$ make
cc  -fPIC -c -o libtest.o libtest.c
cc -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
ln -s libtest.so.0.0.1 libtest.so.0
cc     hello.c libtest.so.0   -o hello
$ ./hello 
./hello: error while loading shared libraries: libtest.so.0: cannot open shared object file: No such file or directory

Bagaimana memperbaikinya? Tambahkan -R <path>ke bendera linker (di sini, dengan pengaturan LDFLAGS).

$ make clean
(...)
$ make LDFLAGS="-Wl,-R -Wl,/home/maciej/src/tmp"
(...)
cc   -Wl,-R -Wl,/home/maciej/src/tmp  hello.c libtest.so.0   -o hello
$ ./hello 
Hello world, I'm a library!

Melihat biner, Anda dapat melihat bahwa ia membutuhkan libtest.so.0:

$ objdump -p hello | grep NEEDED
  NEEDED               libtest.so.0
  NEEDED               libc.so.6

Biner akan mencari perpustakaannya, terlepas dari tempat standar, di direktori yang ditentukan:

$ objdump -p hello | grep RPATH
  RPATH                /home/maciej/src/tmp

Jika Anda ingin biner terlihat di direktori saat ini, Anda dapat mengatur RPATH ke $ORIGIN. Ini agak sulit, karena Anda perlu memastikan bahwa tanda dolar tidak ditafsirkan oleh make. Inilah satu cara untuk melakukannya:

$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$ORIGIN'"
$ objdump -p hello | grep RPATH
  RPATH                $ORIGIN
$ ./hello 
Hello world, I'm a library!

1
Jika tidak menggunakan make, seperti saat menelepon secara manual g++, coba -Wl,-rpath='$ORIGIN'(catat tanda kutip tunggal) untuk mencegah $ORIGINmeluas ke string kosong.
Morpork

14

Untuk memuat objek yang dibagikan dari direktori yang sama dengan executable Anda, cukup jalankan:

$ LD_LIBRARY_PATH=. ./binary

Catatan: Itu tidak akan mengubah variabel LD_LIBRARY_PATH dari sistem Anda. Perubahan hanya berdampak pada ini, dan hanya ini, eksekusi program Anda.


4

Bagi siapa pun yang masih berjuang tanpa jawaban, saya menemukan sendiri dengan saran berikut:

Anda dapat mencoba memperbarui ld.so.cache menggunakan: sudo ldconfig -v

Bekerja untukku.


Bekerja untuk saya juga.
Joel

3

Bagi siapa saja yang menggunakan CMake untuk build mereka, Anda dapat mengatur hal CMAKE_EXE_LINKER_FLAGS-hal berikut:

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'")

Ini akan menyebarkan flag tautan dengan benar untuk semua tipe build (mis., Debug, Release, dll ...) untuk mencari file .so di direktori kerja saat ini terlebih dahulu.


0

Linker dinamis akan memutuskan di mana mencari perpustakaan. Dalam kasus Linux, biasanya dynamic linker adalah GNU ld.so(atau alternatif yang biasanya akan berperilaku identik karena alasan kompatibilitas).

Mengutip dari Wikipedia:

Linker dinamis Perpustakaan GNU C mencari perpustakaan bersama di lokasi berikut:

  1. Path (dipisahkan usus besar) di DT_RPATHatribut bagian dinamis dari biner jika ada dan DT_RUNPATHatribut tidak ada.
  2. Path (dipisahkan oleh usus besar) dalam variabel lingkungan LD_LIBRARY_PATH, kecuali dieksekusi adalah setuid/ setgidbiner, dalam hal ini diabaikan. LD_LIBRARY_PATHdapat diganti dengan memanggil tautan dinamis dengan opsi --library-path (mis / /lib/ld-linux.so.2 --library-path $ HOME / mylibs myprogram).
  3. Path (dipisahkan usus besar) di DT_RUNPATHatribut bagian dinamis dari biner jika ada.
  4. Pencarian berdasarkan file cache ldconfig (sering berlokasi di /etc/ld.so.cache) yang berisi daftar daftar pustaka kandidat yang sebelumnya ditemukan di jalur pustaka yang ditambah (ditetapkan oleh /etc/ld.so.conf). Namun, jika biner dikaitkan dengan -z nodefaultlibopsi tautan , pustaka di jalur pustaka default dilewati.
  5. Di jalur default tepercaya /lib, lalu /usr/lib. Jika biner dikaitkan dengan opsi -z nodefaultlib linker, langkah ini dilewati.

Sumber: https://en.wikipedia.org/wiki/Rpath

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.