Không thể tìm thấy .so trong cùng thư mục với tệp thực thi?


45

Tôi có một tệp thực thi cần liên kết với libtest.sođộng, vì vậy tôi đặt chúng vào cùng thư mục, sau đó:

cd path_to_dir
./binary

Nhưng có được điều này:

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

Làm thế nào nó có thể không thể tìm thấy libtest.socái đã có trong cùng thư mục với chính tệp thực thi?

Câu trả lời:


25

Trình tải không bao giờ kiểm tra thư mục hiện tại cho các đối tượng được chia sẻ trừ khi nó được định hướng rõ ràng thông qua $LD_LIBRARY_PATH. Xem ld.so(8)trang người đàn ông để biết thêm chi tiết.


echo $LD_LIBRARY_PATHtrống trên máy của tôi :(
linuxer

Nó thường là như vậy.
Ignacio Vazquez-Abrams

2
Nó chỉ định các thư mục bổ sung cho trình tải để tìm kiếm các thư viện.
Ignacio Vazquez-Abrams

1
Các đường dẫn trong * nix được phân tách bằng dấu hai chấm ( :), không phải dấu chấm phẩy.
Ignacio Vazquez-Abrams

3
LD_LIBRARY_PATH nói chung là một lựa chọn kém trong sản xuất. Rất tốt cho các bản hack nhanh và những thứ như giúp các tệp nhị phân được gỡ cài đặt tìm thấy các thư viện dùng chung của chúng khi chạy các bài kiểm tra đơn vị (nghĩ ./cool; make; make check). Khi xây dựng nhị phân của bạn, bạn có thể đặt thư viện của mình ở một vị trí tiêu chuẩn (được liệt kê tại /etc/ld.so.conf) hoặc chuyển cờ -R cho trình liên kết để cho nhị phân biết nơi cần tìm.
automatthias

57

Mặc dù bạn có thể đặt LD_LIBRARY_PATH để cho trình liên kết động biết nơi cần tìm, có nhiều tùy chọn tốt hơn. Bạn có thể đặt thư viện dùng chung của mình ở một trong những nơi tiêu chuẩn, xem /etc/ld.so.conf(trên Linux) và /usr/bin/crle(trên Solaris) để biết danh sách những nơi này

Bạn có thể chuyển -R <path>đến trình liên kết khi xây dựng tệp nhị phân của mình, phần này sẽ thêm <path>vào danh sách các thư mục được quét cho thư viện dùng chung của bạn. Đây là một ví dụ. Đầu tiên, hiển thị vấn đề:

libtest.h:

void hello_world(void);

libtest.c:

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

chào c:

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

Makefile (các tab phải được sử dụng):

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

Hãy chạy nó:

$ 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

Làm thế nào để khắc phục nó? Thêm -R <path>vào các cờ liên kết (ở đây, bằng cách thiết lập 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!

Nhìn vào nhị phân, bạn có thể thấy rằng nó cần libtest.so.0:

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

Nhị phân sẽ tìm các thư viện của nó, ngoài các vị trí tiêu chuẩn, trong thư mục được chỉ định:

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

Nếu bạn muốn tệp nhị phân tìm trong thư mục hiện tại, bạn có thể đặt RPATH thành $ORIGIN. Điều này là một chút khó khăn, bởi vì bạn cần chắc chắn rằng ký hiệu đô la không được giải thích bằng cách thực hiện. Đây là một cách để làm điều đó:

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

1
Nếu không sử dụng make, chẳng hạn như khi gọi thủ công g++, hãy thử -Wl,-rpath='$ORIGIN'(lưu ý các dấu ngoặc đơn) để ngăn không cho $ORIGINmở rộng thành một chuỗi trống.
Morpork

14

Để tải các đối tượng được chia sẻ từ cùng thư mục với tệp thực thi của bạn, chỉ cần thực hiện:

$ LD_LIBRARY_PATH=. ./binary

Lưu ý: Nó sẽ không sửa đổi biến LD_LIBRARY_PATH trong hệ thống của bạn. Thay đổi chỉ ảnh hưởng đến điều này và chỉ điều này, thực hiện chương trình của bạn.


4

Đối với bất cứ ai vẫn đấu tranh mà không có câu trả lời, tôi đã tìm thấy một mình với gợi ý sau:

Bạn có thể thử cập nhật ld.so.cache bằng cách sử dụng: sudo ldconfig -v

Đã làm cho tôi.


Làm việc cho tôi là tốt.
Joel

3

Đối với bất kỳ ai sử dụng CMake cho bản dựng của họ, bạn có thể đặt CMAKE_EXE_LINKER_FLAGSnhư sau:

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

Điều này sẽ truyền đúng các cờ liên kết cho tất cả các loại bản dựng (ví dụ: Gỡ lỗi, Phát hành, v.v.) để tìm các tệp .so trong thư mục làm việc hiện tại trước tiên.


0

Trình liên kết động sẽ quyết định nơi tìm thư viện. Trong trường hợp của Linux, trình liên kết động thường là GNU ld.so(hoặc một giải pháp thay thế thường sẽ hoạt động giống hệt nhau vì lý do tương thích.

Để trích dẫn từ Wikipedia:

Trình liên kết động của Thư viện GNU C tìm kiếm các thư viện dùng chung ở các vị trí sau:

  1. Các đường dẫn (được phân tách bằng dấu hai chấm) trong DT_RPATHthuộc tính phần động của nhị phân nếu có và DT_RUNPATHthuộc tính không tồn tại.
  2. Các đường dẫn (được phân tách bằng dấu hai chấm) trong biến môi trường LD_LIBRARY_PATH, trừ khi tệp thực thi là setuid/ setgidnhị phân, trong trường hợp này, nó bị bỏ qua. LD_LIBRARY_PATHcó thể được ghi đè bằng cách gọi trình liên kết động với tùy chọn --l thư viện-đường dẫn (ví dụ /lib/ld-linux.so.2 - thư viện đường dẫn $ HOME / mylibs myprogram).
  3. Các đường dẫn (được phân tách bằng dấu hai chấm) trong DT_RUNPATHthuộc tính phần động của nhị phân nếu có.
  4. Tra cứu dựa trên tệp bộ đệm ldconfig (thường được đặt tại /etc/ld.so.cache) chứa danh sách tổng hợp các thư viện ứng cử viên được tìm thấy trước đây trong đường dẫn thư viện tăng (được đặt bởi /etc/ld.so.conf). Tuy nhiên, nếu nhị phân được liên kết với -z nodefaultlibtùy chọn liên kết, các thư viện trong đường dẫn thư viện mặc định sẽ bị bỏ qua.
  5. Trong đường dẫn mặc định đáng tin cậy /lib, và sau đó /usr/lib. Nếu nhị phân được liên kết với tùy chọn liên kết gật đầu -z, bước này được bỏ qua.

Nguồn: https://en.wikipedia.org/wiki/Rpath

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.