Làm thế nào để chỉ định tùy chọn của đường dẫn thư viện?


91

Tôi đang biên dịch một chương trình c ++ bằng cách sử dụng g++ld. Tôi có một .sothư viện mà tôi muốn được sử dụng trong quá trình liên kết. Tuy nhiên, có một thư viện cùng tên đang tồn tại /usr/local/libldđang chọn thư viện đó thay cho thư viện mà tôi đang trực tiếp chỉ định. Làm thế nào tôi có thể sửa lỗi này?

Đối với các ví dụ dưới đây, tệp thư viện của tôi là /my/dir/libfoo.so.0. Những điều tôi đã thử nhưng không hoạt động:

  • lệnh g ++ của tôi là g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • thêm /my/dirvào đầu hoặc cuối $PATHbiến en` của tôi
  • thêm /my/dir/libfoo.so.0làm đối số vào g ++

1
Có gì khác libfoo.*tập tin tồn tại và ở đâu - .sow / o .0, .a, vv vv?
Alex Martelli

Câu trả lời:


92

Thêm đường dẫn đến nơi đặt thư viện mới của bạn LD_LIBRARY_PATH(nó có tên hơi khác trên Mac ...)

Giải pháp của bạn sẽ hoạt động với việc sử dụng các -L/my/dir -lfootùy chọn, trong thời gian chạy, hãy sử dụng LD_LIBRARY_PATH để trỏ đến vị trí thư viện của bạn.

Cẩn thận với việc sử dụng LD_LIBRARY_PATH - trong ngắn hạn (từ liên kết):

..implication ..:
Security : Hãy nhớ rằng các thư mục được chỉ định trong LD_LIBRARY_PATH được tìm kiếm trước (!) các vị trí tiêu chuẩn? Bằng cách đó, một kẻ xấu có thể khiến ứng dụng của bạn tải một phiên bản của thư viện được chia sẻ có chứa mã độc hại! Đó là một lý do tại sao các tệp thực thi setuid / setgid lại bỏ qua biến đó!
Hiệu suất: Trình tải liên kết phải tìm kiếm tất cả các thư mục được chỉ định, cho đến khi nó tìm thấy thư mục chứa thư viện được chia sẻ - đối với TẤT CẢ các thư viện được chia sẻ, ứng dụng được liên kết với! Điều này có nghĩa là rất nhiều lệnh gọi hệ thống để mở (), sẽ không thành công với "ENOENT (Không có tệp hoặc thư mục như vậy)"! Nếu đường dẫn chứa nhiều thư mục, số lần gọi thất bại sẽ tăng lên một cách tuyến tính và bạn có thể biết điều đó ngay từ thời điểm khởi động ứng dụng. Nếu một số (hoặc tất cả) thư mục nằm trong môi trường NFS, thời gian khởi động ứng dụng của bạn thực sự có thể kéo dài - và nó có thể làm chậm toàn bộ hệ thống!
Không nhất quán: Đây là vấn đề phổ biến nhất. LD_LIBRARY_PATH buộc ứng dụng tải một thư viện được chia sẻ mà nó không được liên kết và điều đó có khả năng không tương thích với phiên bản gốc. Điều này có thể rất rõ ràng, tức là ứng dụng bị treo, hoặc nó có thể dẫn đến kết quả sai, nếu thư viện được chọn không thực hiện đúng như những gì phiên bản gốc đã làm. Đặc biệt là sau này đôi khi khó gỡ lỗi.

HOẶC LÀ

Sử dụng tùy chọn rpath qua gcc đến trình liên kết - đường dẫn tìm kiếm thư viện thời gian chạy, sẽ được sử dụng thay vì tìm kiếm trong dir tiêu chuẩn (tùy chọn gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

Điều này là tốt cho một giải pháp tạm thời. Đầu tiên, trình liên kết tìm kiếm thư viện LD_LIBRARY_PATH trước khi xem xét các thư mục chuẩn.

Nếu bạn không muốn cập nhật vĩnh viễn LD_LIBRARY_PATH, bạn có thể thực hiện việc này nhanh chóng trên dòng lệnh:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

Bạn có thể kiểm tra những gì trình liên kết thư viện biết về việc sử dụng (ví dụ):

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

Và bạn có thể kiểm tra thư viện mà ứng dụng của bạn đang sử dụng:

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)

21
LD_LIBRARY_PATHđược tìm kiếm trong thời gian chạy, tại thời gian biên dịch bạn muốn đặt LIBRARY_PATH. Xem gcc.gnu.org/onlineocs/gcc/Enosystem-Variables.html
Bjoern Dahlgren

1
Nếu thư viện của bạn hoàn toàn khác với thư viện hệ thống, tức là thư viện luôn sử dụng, hãy sử dụng giải pháp rpath. LD_LIBRARY_PATH là một bản hack để thử nghiệm và không cần thiết để thực thi hoạt động chính xác.
user2746401

1
DYLD_LIBRARY_PATH của nó dành cho Mac
cbinder

Đây là một lệnh mẫu đầy đủ (dành cho C) hoạt động dựa trên câu trả lời này:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue

25

Đây là một câu hỏi cũ, nhưng dường như không ai đề cập đến điều này.

Bạn đã may mắn rằng mọi thứ đã được liên kết.

Bạn cần thay đổi

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

đến điều này:

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

Trình liên kết của bạn theo dõi các ký hiệu mà nó cần giải quyết. Nếu nó đọc thư viện trước, nó không có bất kỳ ký hiệu cần thiết nào, vì vậy nó sẽ bỏ qua các ký hiệu trong đó. Chỉ định các thư viện sau những thứ cần liên kết với chúng để trình liên kết của bạn có các ký hiệu để tìm trong chúng.

Ngoài ra, -lfoolàm cho nó tìm kiếm cụ thể một tệp có tên libfoo.ahoặc libfoo.sokhi cần thiết. Không libfoo.so.0. Vì vậy, hoặc lnđặt tên hoặc đổi tên thư viện là appopriate.

Để trích dẫn trang gcc man:

-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.

Việc thêm tệp trực tiếp vào g++dòng lệnh của 'lẽ ra phải hoạt động, tất nhiên trừ khi bạn đặt nó trước đó bar.cpp, khiến trình liên kết bỏ qua nó vì thiếu bất kỳ ký hiệu cần thiết nào, vì chưa có ký hiệu nào.


21

Việc chỉ định đường dẫn tuyệt đối đến thư viện sẽ hoạt động tốt:

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

Bạn có nhớ xóa -lfookhi bạn thêm đường dẫn tuyệt đối không?


1
Giải pháp này cũng hoạt động tốt đối với tôi - cố gắng liên kết với phiên bản Qt5 khác với gói phát triển distro. Cảm ơn.
wump

Làm thế nào để làm cho điều này hoạt động cho @các ký hiệu được phiên bản? Ví dụ tối thiểu: github.com/cirosantilli/cpp-cheat/blob/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

11

Thay vào đó, bạn có thể sử dụng các biến môi trường LIBRARY_PATHvà các biến CPLUS_INCLUDE_PATHnày tương ứng cho biết nơi tìm thư viện và nơi tìm tiêu đề ( CPATHcũng sẽ thực hiện công việc) mà không cần chỉ định các tùy chọn -L và -I.

Chỉnh sửa: CPATHbao gồm tiêu đề với -ICPLUS_INCLUDE_PATHvới -isystem.


Bạn có thể vui lòng thêm ví dụ để sử dụng?
Hanna Khalil

export LIBRARY_PATH = /path/to/libtrong cùng một phiên giao diện điều khiển mà bạn đang biên soạn
Alexandre Hamez

0

Nếu một người được sử dụng để làm việc với DLL trong Windows và muốn bỏ qua số phiên bản .so trong linux / QT, việc thêm CONFIG += pluginsẽ lấy ra số phiên bản. Để sử dụng đường dẫn tuyệt đối tới .so, việc đưa nó tới trình liên kết hoạt động tốt, như ông Klatchko đã đề cập.

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.