sách gpt4 ăn đã đi

Bạn sẽ xử lý việc liên kết hai [thư viện động] với "tên giống hệt nhau" như thế nào?

In lại Tác giả: qq735679552 Thời gian cập nhật: 29-09-2022 22:32:09 26 4
mua khóa gpt4 giày nike

CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.

Bài viết trên blog CFSDN này liên kết hai [thư viện động] với "tên giống hệt nhau". Bạn sẽ xử lý nó như thế nào? Được tác giả sưu tầm và biên soạn. Nếu các bạn quan tâm tới bài viết này thì nhớ like nhé.

Bạn sẽ xử lý việc liên kết hai [thư viện động] với

[Mục lục]

  • Tệp thư viện động đầu tiên
  • ứng dụng
  • Tệp thư viện động thứ hai
  • Cách tiếp cận sai: đổi tên trực tiếp
  • Câu trả lời đúng: công cụ patchelf
  • Một điều nữa

Trong quá trình phát triển các ứng dụng Linux, việc sử dụng trực tiếp các thư viện làm sẵn của bên thứ ba (thường được gọi là: bánh xe) để hoàn thành các chức năng kinh doanh của riêng bạn là điều rất phổ biến.

Tôi không biết bạn có gặp phải trường hợp như vậy không: ứng dụng cần sử dụng các hàm có chức năng khác nhau trong hai thư viện động, nhưng tác giả của hai thư viện động có thần giao cách cảm và thực tế đã đặt cùng một tên thư viện động. ?

Cụ thể, vấn đề gặp phải là: khi biên dịch một chương trình thực thi, một thư viện động có thể được liên kết động thông qua -lXXX của tham số biên dịch gcc.

Tuy nhiên, bây giờ bạn muốn liên kết hai thư viện động, tên của chúng giống nhau!!

Tệp thư viện động đầu tiên

Bây giờ, giả sử chúng ta đang phát triển một ứng dụng robot yêu cầu sử dụng thuật toán từ thư viện động của bên thứ ba.

Mã nguồn của thư viện này rất đơn giản như sau:

  1. // Tệp nguồn thư viện động đầu tiên RobotMath.c:
  2. gấp đôihàm0(gấp đôitranh luận)
  3. {
  4. gấp đôiret=arg+arg;
  5. trở lạiPhải;
  6. }
  7. gấp đôifunc1(gấp đôiarg1,gấp đôiđối số2)
  8. {
  9. gấp đôiphải=arg1+arg2;
  10. trở lạiPhải;
  11. }

Lệnh biên dịch cho thư viện động là:

  1. $gcc-m32-fPIC--shared-olibRobotMath.so-Wl,--soname,libRobotMath.soRobotMath.c

Các thuộc tính trên tương đối phổ biến, vui lòng lưu ý -Wl, --soname, libRobotMath.so, được sử dụng để chỉ định SONAME của thư viện động được tạo và thường được sử dụng trong quản lý phiên bản của thư viện động.

Để thuận tiện, thông tin phiên bản không được đưa vào đây.

Sau khi thực hiện lệnh gcc, bạn nhận được một tệp thư viện động: libRobotMath.so.

Bạn có thể sử dụng công cụ patchelf (trong hệ thống Ubuntu, bạn có thể cài đặt trực tiếp thông qua apt-get) để kiểm tra SONAME của tệp thư viện động này:

  1. $vá vá--print-sonamelibRobotMath.so
  2. libRobotMath.so//SONAME

Những gì được in ở dòng 2 được gọi là SONAME.

Bạn cũng có thể kiểm tra nó bằng cách chỉ định SONAME khác, ví dụ:

$ gcc -m32 -fPIC --shared -o libRobotMath.so -Wl,--soname,libRobotMath-1.2.3.so RobotMath.c 。

$ patchelf --print-soname libRobotMath.so 。

libRobotMath-1.2.3.so // SONAME .

Trên đây là thư viện động đầu tiên. Bây giờ chúng ta hãy xem ứng dụng đơn giản nhất.

ứng dụng

  1. // Tệp nguồn chương trình có thể thực thi: main.c
  2. bên ngoàigấp đôihàm0(gấp đôitranh luận);
  3. bên ngoàigấp đôifunc1(gấp đôiarg1,gấp đôiđối số2);
  4. số nguyênchủ yếu(số nguyênđối số,char*agv[])
  5. {
  6. gấp đôiđối số = 1,1;
  7. gấp đôikết quả0=func0(arg);
  8. inf("kết quả0=%lf\n",kết quả0);
  9. gấp đôiđối số1=1,1, đối số2=2,2;
  10. gấp đôikết quả1=func1(arg1,arg2);
  11. inf("kết quả1=%lf\n",kết quả1);
  12. trở lại0;
  13. }

Mã này gần như ở trình độ mẫu giáo, không cần giải thích, chỉ cần biên dịch trực tiếp (giả sử thư viện động đã được sao chép vào cùng thư mục với main.c):

  1. $gcc-m32-omainmain.c-lRobotMath-L./-Wl,-rpath=./

thực hiện:

  1. $./chính
  2. kết quả0=2.200000
  3. kết quả1=3.300000

Hoàn hảo.

Tệp thư viện động thứ hai

Vấn đề ở đây là: Bây giờ ứng dụng cần triển khai một thuật toán phức tạp khác. Với tinh thần lười biếng, cuối cùng tôi đã tìm thấy thuật toán này trong một thư viện khác liên quan đến thuật toán robot.

  1. // Tệp nguồn thư viện động thứ hai RobotMath.c:
  2. gấp đôihàm2(gấp đôiarg1,gấp đôiđối số 2,gấp đôiarg3)
  3. {
  4. gấp đôiret=arg1*arg2*arg3;
  5. trở lạiPhải;
  6. }
  7. // biên dịch hướng dẫn
  8. $gcc-m32-fPIC--shared-olibRobotMath.so-Wl,--soname,libRobotMath.soRobotMath.c

Nhưng mẹo nhỏ là tên của thư viện động mà thư viện thuật toán này xuất ra thực ra là libRobotMath.so.

Nó có cùng tên với tên file của thư viện thuật toán đầu tiên. Có vẻ như tên này quá phổ biến.

Nếu tác giả chỉ chọn một cái tên khác thì đã không có chuyện gì xảy ra.

Nếu: Tên là libRobotUltra.so thì bạn chỉ cần copy trực tiếp rồi liên kết trực tiếp -lRobotUltra khi biên dịch và thực thi chương trình.

Cách tiếp cận sai: đổi tên trực tiếp

Trong trường hợp này, chúng ta có thể đổi tên trực tiếp không? Hãy thử:

  1. $mvlibRobotMath.solibRobotMath2.so

Sau đó sao chép libRobotMath2.so vào thư mục của ứng dụng và trong main.c, gọi hàm thuật toán func2 trong thư viện này.

  1. bên ngoàigấp đôihàm2(gấp đôiarg1,gấp đôiđối số 2,gấp đôiarg3);
  2. số nguyênchủ yếu(số nguyênđối số,char*agv[])
  3. {
  4. // mã khác trước
  5. //...
  6. gấp đôiarg3=1.1,arg4=2.2,arg5=3.3;
  7. gấp đôiresult2=func2(arg3,arg4,arg5);
  8. inf("kết quả2=%lf\n",kết quả2);
  9. trở lại0;
  10. }

Hãy thử biên dịch nó:

  1. $gcc-m32-omainmain.c-lRobotMath-lRobotMath2-L./-Wl,-rpath=./
  2. /tmp/ccDGqFkl.o:TRONGchức năng`chính':
  3. main.c:(.text+0xb4):undefinedreferenceĐẾN`hàm2'
  4. collect2:lỗi:ldreturned1trạng thái thoát

Lỗi: Không tìm thấy hàm func2.

Nhưng thư viện libRobotMath2.so rõ ràng đã có chức năng này. Nếu bạn không tin tôi, hãy xem qua:

  1. $readelf-slibRobotMath2.so|grepfunc2
  2. 8:0000052a69VUI VẺTOÀN CẦUMẶC ĐỊNH11 chức năng2
  3. 51:0000052a69VUI VẺTOÀN CẦUMẶC ĐỊNH11 chức năng2

Tại sao gcc vẫn không thể tìm thấy nó?

Có vẻ như việc buộc đổi tên tệp thư viện động thứ hai một cách thô lỗ không phải là cách chính xác để giải quyết vấn đề.

Câu trả lời đúng: công cụ patchelf

Bạn có nhớ trong thư viện đầu tiên, chúng ta đã sử dụng tiện ích patchelf để xem SONAME của thư viện động không?

Tiếp tục sử dụng nó để xem libRobotMath2.so mà chúng tôi đã đổi tên:

  1. $vá vá--print-sonamelibRobotMath2.so
  2. libRobotMath.so

SONAME vẫn là tên gốc, nghĩa là việc đổi tên thông qua lệnh mv chỉ thay đổi hình thức chứ không thay đổi bản chất của nó.

Nếu bạn quen thuộc với hệ thống tệp, bạn sẽ biết rằng lệnh mv chỉ thay đổi tên của tệp thư viện trong nút inode, nhưng không gian lưu trữ khối nơi lưu trữ nội dung thực tế của tệp thư viện không thay đổi chút nào.

Thư viện động là một tệp ở định dạng ELF. Khi hệ điều hành tải thư viện động, nó sẽ phân tích nội dung của tệp theo từng lớp theo tiêu chuẩn định dạng ELF.

Bạn có thể tham khảo một bài viết tôi đã viết cách đây rất lâu: Nền tảng của việc biên dịch và liên kết trong hệ thống Linux - Tệp ELF: bóc tách các lớp của nó và khám phá nó từ độ chi tiết của mã byte.

Công cụ patchelf cung cấp chức năng xem hoặc sửa đổi thông tin nội bộ của các file thư viện động, bao gồm: SONAME, các thư viện động phụ thuộc khác, thông tin đường dẫn rpath, v.v.

  1. $patchelf-h
  2. cú pháp:patchelf
  3. [--set-interpreterTÊN_TẬP_TIN]
  4. [--kích thước trangKÍCH THƯỚC]
  5. [--trình biên dịch in]
  6. [--print-soname]In mục nhập 'DT_SONAME' của.dynamicsection.Nâng cao lỗi nếu DT_SONAME không tồn tại
  7. [--set-sonameSONAME]Đặt'DT_SONAME'entrytoSONAME.
  8. [--set-rpathRPATH]
  9. [--remove-rpath]
  10. [--shrink-rpath]
  11. [--in-rpath]
  12. [--lực-rpath]
  13. [--add-needLIBRARY]
  14. [--remove-needLIBRARY]
  15. [--replace-needLIBRARYTHƯ VIỆN MỚI]
  16. [--cần in]
  17. [--no-default-lib]
  18. [--gỡ lỗi]
  19. [--phiên bản]
  20. TÊN TỆP

Chúng ta có thể sử dụng tham số --set-soname để sửa đổi SONAME của nó:

  1. $vá vá--set-sonamelibRobotMath2.solibRobotMath2.so

libRobotMath2.so đầu tiên là bộ tên SONAME,

libRobotMath2.so thứ hai là SONAME chỉ định tệp thư viện động nào cần sửa đổi.

Sau khi sửa đổi, kiểm tra lại xem sửa đổi có đúng không:

  1. $vá vá--print-sonamelibRobotMath2.so
  2. libRobotMath2.so

Bingo!SONAME đã được sửa đổi chính xác.

Biên dịch lại chương trình thực thi:

  1. $gcc-m32-omainmain.c-lRobotMath-lRobotMath2-L./-Wl,-rpath=./

Không có lỗi nào được báo cáo.

Thực hiện nó:

  1. $./chính
  2. kết quả0=2.200000
  3. kết quả1=3.300000
  4. kết quả2=7.986000

Vấn đề đã được giải quyết.

Một điều nữa

Bạn đang nói rằng một câu hỏi như vậy chỉ quay lại một lần trong một ngàn năm? Bạn chỉ đang cố gắng bày tỏ nỗi buồn của mình về việc tạo ra những từ mới? Điều đó có nghĩa là con đường đã đi không đủ dài.

Tôi nhớ rằng vào khoảng năm 2015, chúng tôi đang phát triển một cổng và cần mô phỏng nó trên nền tảng Ubuntu (x86) trước khi phần cứng ra mắt.

Để hỗ trợ đa nền tảng, thư viện glib đã được chọn, nhưng một phần nhỏ mã nguồn đã được phát triển lại.

Tuy nhiên, hệ thống máy tính để bàn của Ubuntu dựa trên GTK (lớp dưới cùng sử dụng thư viện glib), có nghĩa là hệ điều hành đã tải thư viện glib vào thư mục hệ thống khi nó khởi động.

Sau đó, khi ứng dụng của chúng tôi được biên dịch, thực sự có thể liên kết đến thư viện glib do chính chúng tôi phát triển (được đặt trong một thư mục cục bộ), nhưng khi thực thi thì tải không thành công, nguyên nhân là do xung đột tên của thư viện động.

Cuối cùng, tôi không còn lựa chọn nào khác ngoài việc sử dụng công cụ patchelf để viết lại tên của thư viện động, trong đó có SONAME, để giải quyết vấn đề.

Liên kết gốc: https://mp.weixin.qq.com/s/FCe9nzSRkIsV-bGzqbiDIg.

Cuối cùng, bài viết này nói về việc liên kết hai [thư viện động] có "tên giống hệt nhau". Bạn sẽ xử lý nó như thế nào? Bài viết kết thúc ở đây Nếu bạn muốn biết thêm về cách liên kết hai [thư viện động] có "cùng tên", bạn sẽ giải quyết vấn đề đó như thế nào? Về nội dung, vui lòng tìm kiếm các bài viết của CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .

26 4 0
qq735679552
Hồ sơ

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá taxi Didi miễn phí
Phiếu giảm giá taxi Didi
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress