Tôi nên làm gì nếu tôi có hai thư viện cung cấp các hàm có tên tương đương?
vorbis_...
, sf_...
, sdl_...
). Về cơ bản đây là những gì C ++ thực hiện với các tên ký hiệu cho các hàm có không gian tên.
Tôi nên làm gì nếu tôi có hai thư viện cung cấp các hàm có tên tương đương?
vorbis_...
, sf_...
, sdl_...
). Về cơ bản đây là những gì C ++ thực hiện với các tên ký hiệu cho các hàm có không gian tên.
Câu trả lời:
Apropos nhận xét: Bằng cách "xuất", ý tôi là hiển thị các mô-đun liên kết tới thư viện --- tương đương với extern
từ khóa ở phạm vi tệp. Điều này được kiểm soát như thế nào là phụ thuộc vào hệ điều hành và trình liên kết. Và nó là thứ mà tôi luôn phải tra cứu.
Có thể đổi tên các biểu tượng trong tệp đối tượng bằng cách sử dụng objcopy --redefine-sym old=new file
(xem man objcopy).
Sau đó, chỉ cần gọi các hàm bằng tên mới của chúng và liên kết với tệp đối tượng mới.
Trong Windows, bạn có thể sử dụng LoadLibrary () để tải một trong những thư viện đó vào bộ nhớ và sau đó sử dụng GetProcAddress () để lấy địa chỉ của từng hàm bạn cần gọi và gọi các hàm thông qua con trỏ hàm.
ví dụ
HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);
sẽ lấy địa chỉ của một thanh có tên hàm trong foo.dll và gọi nó.
Tôi biết các hệ thống Unix hỗ trợ chức năng tương tự, nhưng tôi không thể nghĩ ra tên của chúng.
dlopen
dlsym
, và dlclose
. Tuy nhiên, tính năng đóng gói trên Unix có thể không hiệu quả như trên Windows.
Đây là một suy nghĩ. Mở một trong các thư viện vi phạm trong trình chỉnh sửa hex và thay đổi tất cả các lần xuất hiện của các chuỗi vi phạm thành một thứ khác. Sau đó, bạn sẽ có thể sử dụng các tên mới trong tất cả các cuộc gọi trong tương lai.
CẬP NHẬT: Tôi vừa làm điều đó ở đầu này và nó có vẻ hoạt động. Tất nhiên, tôi đã không kiểm tra kỹ lưỡng điều này - nó có thể không phải là một cách thực sự tốt để thổi bay chân bạn bằng một khẩu súng ngắn hexedit.
Giả sử rằng bạn sử dụng linux, trước tiên bạn cần thêm
#include <dlfcn.h>
Khai báo biến con trỏ hàm trong ngữ cảnh thích hợp, ví dụ:
int (*alternative_server_init)(int, char **, char **);
Giống như Ferruccio đã nêu trong https://stackoverflow.com/a/678453/1635364 , tải rõ ràng thư viện bạn muốn sử dụng bằng cách thực thi (chọn cờ yêu thích của bạn)
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
Đọc địa chỉ của hàm bạn muốn gọi sau
sym = dlsym(dlhandle, "conflicting_server_init");
gán và truyền như sau
alternative_server_init = (int (*)(int, char**, char**))sym;
Gọi theo cách tương tự so với bản gốc. Cuối cùng, dỡ bỏ bằng cách thực thi
dlclose(dlhandle);
Bạn không nên sử dụng chúng cùng nhau. Nếu tôi nhớ không nhầm thì trình liên kết đã xảy ra lỗi trong trường hợp như vậy.
Tôi không cố gắng, nhưng một giải pháp có thể có dlopen()
, dlsym()
và dlclose()
cho phép bạn xử lý lập trình thư viện động. Nếu bạn không cần hai hàm cùng một lúc, bạn có thể mở thư viện đầu tiên, sử dụng hàm đầu tiên và đóng thư viện đầu tiên trước khi sử dụng thư viện / hàm thứ hai.
Nếu bạn có tệp .o ở đó, câu trả lời hay ở đây: https://stackoverflow.com/a/6940389/4705766
Tóm lược:
objcopy --prefix-symbols=pre_string test.o
để đổi tên các ký hiệu trong tệp .o hoặc là
objcopy --redefine-sym old_str=new_str test.o
để đổi tên ký hiệu cụ thể trong tệp .o.Vấn đề này là lý do c ++ có không gian tên. Không thực sự là một giải pháp tuyệt vời trong c cho 2 lib của bên thứ ba có cùng tên.
Nếu đó là một đối tượng động, bạn có thể tải rõ ràng các đối tượng được chia sẻ (LoadLibrary / dlopen / etc) và gọi nó theo kiểu đó. Ngoài ra, nếu bạn không cần cả hai lib cùng một lúc trong cùng một mã, bạn có thể làm điều gì đó với liên kết tĩnh (nếu bạn có tệp .lib / .a).
Tất nhiên, không có giải pháp nào trong số này áp dụng cho tất cả các dự án.
Xin thề? Theo như tôi được biết, bạn không thể làm gì nhiều nếu có hai thư viện để lộ các điểm liên kết có cùng tên và bạn cần liên kết với cả hai.
Bạn nên viết một thư viện trình bao bọc xung quanh một trong số chúng. Thư viện trình bao bọc của bạn phải hiển thị các ký hiệu có tên duy nhất và không hiển thị các ký hiệu của các tên không phải duy nhất.
Tùy chọn khác của bạn là đổi tên tên hàm trong tệp tiêu đề và đổi tên ký hiệu trong kho lưu trữ đối tượng thư viện.
Dù bằng cách nào, để sử dụng cả hai, đó sẽ là một công việc hack.
Câu hỏi đã gần tròn một thập kỷ, nhưng luôn có những tìm kiếm mới ...
Như đã được trả lời, đối tượng với cờ --redefine-sym là một lựa chọn tốt trong Linux. Ví dụ: xem https://linux.die.net/man/1/objcopy để có tài liệu đầy đủ. Nó hơi rắc rối vì về cơ bản bạn đang sao chép toàn bộ thư viện trong khi thực hiện các thay đổi và mọi bản cập nhật đều yêu cầu công việc này được lặp lại. Nhưng ít nhất nó sẽ hoạt động.
Đối với Windows, tải động thư viện là một giải pháp và một giải pháp vĩnh viễn giống như giải pháp thay thế dlopen trong Linux. Tuy nhiên, cả dlopen () và LoadLibrary () đều thêm mã bổ sung có thể tránh được nếu vấn đề duy nhất là tên trùng lặp. Ở đây, giải pháp Windows thanh lịch hơn cách tiếp cận đối tượng: Chỉ cần nói với trình liên kết rằng các ký hiệu trong thư viện được biết đến với một số tên khác và sử dụng tên đó. Có một vài bước để làm điều đó. Bạn cần tạo tệp def và cung cấp bản dịch tên trong phần XUẤT KHẨU. Xem https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, cuối cùng nó sẽ được thay thế bằng các phiên bản mới hơn) hoặc http://www.digitalmars.com/ctg/ctgDefFiles.html(có thể lâu dài hơn) để biết chi tiết cú pháp đầy đủ của tệp def. Quá trình này sẽ là tạo tệp def cho một trong các thư viện, sau đó sử dụng tệp def này để tạo tệp lib và sau đó liên kết với tệp lib đó. (Đối với Windows DLL, tệp lib chỉ được sử dụng để liên kết chứ không phải thực thi mã.) Xem Cách tạo tệp .lib khi có tệp .dll và tệp tiêu đề cho quá trình xây dựng tệp lib. Ở đây, sự khác biệt duy nhất là thêm các bí danh.
Đối với cả Linux và Windows, đổi tên các hàm trong tiêu đề của thư viện có tên đang được đặt bí danh. Một tùy chọn khác sẽ hoạt động là, trong các tệp tham chiếu đến tên mới, thành #define old_name new_name, # bao gồm các tiêu đề của thư viện có các bản xuất đang được đặt bí danh, sau đó #undef old_name trong trình gọi. Nếu có nhiều tệp sử dụng thư viện, một giải pháp thay thế dễ dàng hơn là tạo một tiêu đề hoặc các tiêu đề bao bọc các định nghĩa, bao gồm và hoàn tác và sau đó sử dụng tiêu đề đó.
Hy vọng thông tin này là hữu ích!
Tôi chưa bao giờ sử dụng dlsym, dlopen, dlerror, dlclose, dlvsym, v.v., nhưng tôi đang xem trang man và nó đưa ra một ví dụ về cách mở libm.so và giải nén hàm cos. Dlopen có trải qua quá trình tìm va chạm không? Nếu không, OP có thể tải cả hai thư viện theo cách thủ công và gán tên mới cho tất cả các chức năng mà thư viện của anh ta cung cấp.