2011-01-13 16 views
7

Giả sử tôi có:GCC liên kết đến tên mối liên kết một đối tượng chia sẻ của

  • /usr/lib/libsomething.so.1 trên máy A;
  • /usr/lib/libsomething.so.2 trên máy B.

Cả hai máy có /usr/lib/libsomething.so liên kết tượng trưng đến libs tương ứng của họ.

nếu tôi liên kết sử dụng gcc với -lsomething (hoặc thậm chí /usr/lib/libsomething.so) nó sẽ làm theo các liên kết tượng trưng, ​​và ldd trên máy A sản xuất cái gì đó như:

libsomething.so.1 => /usr/lib/libsomething.so.1 

Điều này có nghĩa nó sẽ không thể tìm thấy thư viện trên máy B.

Bây giờ tôi biết đây là những thay đổi số phiên bản chính và tôi biết chúng có thể không tương thích, nhưng tôi sẵn sàng chấp nhận rủi ro đó. Những gì tôi muốn nói với các mối liên kết là để tìm kiếm libsomething.so, và không tuân theo các liên kết tượng trưng để ldd sẽ hiển thị

libsomething.so => /usr/lib/libsomething.so.1 

trên A nhưng

libsomething.so => /usr/lib/libsomething.so.2 

trên B. Và sau đó nạp sẽ thực hiện theo các liên kết đến bất kỳ phiên bản nào.

Ngoài ra, tôi không muốn tải chậm với dlopen hoặc bất kỳ thứ gì. Tôi muốn nó liên kết với đối tượng được chia sẻ tại thời gian biên dịch.

Điều này có thể thực hiện được không?

Trả lời

8

Thực thi có sử dụng bất kỳ phiên bản thư viện được chia sẻ nào có sẵn, tất nhiên là có thể.

Vấn đề là bạn liên kết thực thi của bạn lên phiên bản cụ thể soname (libsomething.so.1libsomething.so.2). Bạn nên làm điều đó với soname không phiên bản libsomething.so thay thế.Để đạt được điều này, trên máy xây dựng, bạn nên biên dịch và cài đặt thư viện với soname (ELF SONAME) bằng libsomething.so (không có phiên bản) để liên kết có thể chọn soname này trong khi thực thi được xây dựng.

Theo Shared Libraries HOWTO, bạn có thể vượt qua được yêu cầu không phiên bản soname trong khi xây dựng thư viện:

gcc -shared -Wl,-soname,libsomething.so -o libsomething.so.X objectsomething.o 

Sau đó, ngay sau khi bạn cài đặt thư viện và chạy ldconfig, bạn có:

  • liên kết tượng trưng /lib/libsomething.so trỏ đến /lib/libsomething.so.1 trên máy A;
  • liên kết tượng trưng /lib/libsomething.so trỏ đến /lib/libsomething.so.2 trên máy B.

Bộ nạp (chạy ldd) sẽ chọn symlink không phiên bản không phân biệt nơi mà nó trỏ tới:

  • libsomething.so => /lib/libsomething.so (0xNNNNNNNN) trên máy A;
  • libsomething.so => /lib/libsomething.so (0xNNNNNNNN) trên máy B.

Linux nạp động (ld.so) giải quyết các thư viện dựa trên giá trị soname của họ bằng văn bản trong thực thi (ELF NEEDED). Giá trị được sao chép từ tệp thư viện (ELF SONAME) trong khi xây dựng tệp thi hành. Miễn là có một liên kết tượng trưng trên hệ thống đích khớp với tên son được ghi trong tệp thực thi, thư viện được chỉ bởi liên kết tượng trưng này sẽ được tải.


Hãy chạy qua thiết lập của bạn và hiển thị các lệnh để xác minh xác minh.

Tôi đã sử dụng Fedora 18 X86_64 để kiểm tra và điều chỉnh đầu ra thành i686 để rõ ràng.

  • Compile cả libsomething.so.1libsomething.so.2. Hãy chắc chắn rằng SONAME được thiết lập để không phiên bản libsomething.so:

    readelf -a libsomething.so.1 | grep SONAME 
    0xNNNNNNNN (SONAME)    Library soname: [libsomething.so] 
    
    readelf -a libsomething.so.2 | grep SONAME 
    0xNNNNNNNN (SONAME)    Library soname: [libsomething.so] 
    
  • Cài đặt các thư viện vào máy của mình dưới /lib/ thư mục. Chạy ldconfig -v trên cả hai máy và xác minh đầu ra.

    ldconfig -v 2>&1 | grep something 
    libsomething.so -> libsomething.so.1 (changed) 
    
    ldconfig -v 2>&1 | grep something 
    libsomething.so -> libsomething.so.2 (changed) 
    
  • Compile thực thi và chắc chắn rằng nó đề cập đến soname cùng mà không cần phiên bản trong NEEDED.

    readelf -a executable | grep NEEDED 
    0xNNNNNNNN (NEEDED)    Shared library: [libsomething.so] 
    
  • Bạn có thể thực thi tùy thuộc vào không phiên bản libsomething.so ngay bây giờ. Sao chép thực thi cho cả hai máy và chạy ldd đối với cả hai bản sao.

    ldd executable 
    libsomething.so => /lib/libsomething.so (0xNNNNNNNN) 
    

    Kết quả cuối cùng giống nhau trên cả hai máy là tệp thi hành được xây dựng với soname không có phiên bản. Điều này làm cho bộ nạp lấy các liên kết không được phiên bản trên các máy mục tiêu. Và tùy thuộc vào máy, liên kết tượng trưng có thể trỏ đến việc triển khai khác nhau của thư viện libsomething.so.1 hoặc libsomething.so.2.

+0

Tôi không xây dựng thư viện được đề cập, tôi nghĩ câu trả lời thực sự là không làm những gì tôi đề xuất, và nếu bạn thực sự muốn ăn gian, chỉ cần sử dụng liên kết tượng trưng. Điều này cung cấp một số thông tin tốt mặc dù vậy tôi chấp nhận. –

2

Điều này có nghĩa nó sẽ không thể tìm thấy thư viện trên máy B.

Và nó không phải anyway.

Theo định nghĩa của soversions, libsomething.so.2 biểu thị rằng API/ABI không tương thích với libsomething.so.1. Do đó, chỉ cần thêm libsomething.so trong bảng thư viện của chương trình được tải sẽ là sai sự thật. Liên kết tượng trưng libsomething.so chỉ phục vụ như một gợi ý cho ld là chuyển đổi để chọn theo mặc định.

Trong bất kỳ tệp nào ld thực sự đã kết thúc mở, sẽ mất trường DTNAME/SONAME để mã hóa trong chương trình. Nếu bạn không muốn điều đó, không trang bị libsomething với một soname. Nhưng nó có thể dễ dàng trở thành nỗi đau ... bắt đầu bằng việc chạy vào các biểu tượng không có sẵn khi cố chạy chương trình.