ฉันควรทำอย่างไรหากฉันมีสองไลบรารีที่ให้ฟังก์ชันที่มีชื่อเทียบเท่ากัน
vorbis_...
, sf_...
, sdl_...
) นี่คือสิ่งที่ C ++ ทำกับชื่อสัญลักษณ์สำหรับฟังก์ชันเนมสเปซ
ฉันควรทำอย่างไรหากฉันมีสองไลบรารีที่ให้ฟังก์ชันที่มีชื่อเทียบเท่ากัน
vorbis_...
, sf_...
, sdl_...
) นี่คือสิ่งที่ C ++ ทำกับชื่อสัญลักษณ์สำหรับฟังก์ชันเนมสเปซ
คำตอบ:
แสดงความคิดเห็น: โดย "ส่งออก" ฉันหมายถึงการทำให้โมดูลที่ลิงก์ไปยังไลบรารีมองเห็นได้ --- เทียบเท่ากับextern
คีย์เวิร์ดที่ขอบเขตไฟล์ วิธีการควบคุมนี้ขึ้นอยู่กับ OS และตัวเชื่อมโยง และมันก็เป็นสิ่งที่ผมมักจะต้องมองขึ้น
เป็นไปได้ที่จะเปลี่ยนชื่อสัญลักษณ์ในอ็อบเจ็กต์ไฟล์โดยใช้objcopy --redefine-sym old=new file
(ดู man objcopy)
จากนั้นเรียกใช้ฟังก์ชันโดยใช้ชื่อใหม่และเชื่อมโยงกับไฟล์ออบเจ็กต์ใหม่
ใน Windows คุณสามารถใช้LoadLibrary ()เพื่อโหลดหนึ่งในไลบรารีเหล่านั้นลงในหน่วยความจำจากนั้นใช้GetProcAddress ()เพื่อรับที่อยู่ของแต่ละฟังก์ชันที่คุณต้องการเรียกและเรียกใช้ฟังก์ชันผ่านตัวชี้ฟังก์ชัน
เช่น
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);
จะได้รับที่อยู่ของฟังก์ชันชื่อ bar ใน foo.dll และเรียกมัน
ฉันรู้ว่าระบบ Unix รองรับฟังก์ชันการทำงานที่คล้ายกัน แต่ฉันนึกชื่อไม่ออก
dlopen
dlsym
และdlclose
. อย่างไรก็ตามการห่อหุ้มบน Unix อาจไม่มีประสิทธิภาพเท่ากับบน Windows
นี่คือความคิด เปิดหนึ่งในไลบรารีที่ละเมิดในตัวแก้ไขฐานสิบหกและเปลี่ยนการเกิดขึ้นทั้งหมดของสตริงที่ละเมิดเป็นอย่างอื่น จากนั้นคุณจะสามารถใช้ชื่อใหม่ในการโทรในอนาคตทั้งหมด
UPDATE: ฉันเพิ่งทำในตอนนี้และดูเหมือนว่าจะได้ผล แน่นอนฉันไม่ได้ทดสอบสิ่งนี้อย่างละเอียด - มันอาจจะไม่มากไปกว่าวิธีที่ดีจริงๆในการระเบิดขาของคุณด้วยปืนลูกซอง hexedit
หากคุณมีไฟล์. o มีคำตอบที่ดีที่นี่: https://stackoverflow.com/a/6940389/4705766
สรุป:
objcopy --prefix-symbols=pre_string test.o
เพื่อเปลี่ยนชื่อสัญลักษณ์ในไฟล์. o หรือ
objcopy --redefine-sym old_str=new_str test.o
เพื่อเปลี่ยนชื่อสัญลักษณ์เฉพาะในไฟล์. oสมมติว่าคุณใช้ linux ก่อนอื่นคุณต้องเพิ่ม
#include <dlfcn.h>
ประกาศตัวแปรตัวชี้ฟังก์ชันในบริบทที่เหมาะสมตัวอย่างเช่น
int (*alternative_server_init)(int, char **, char **);
เช่นเดียวกับที่ Ferruccio ระบุไว้ในhttps://stackoverflow.com/a/678453/1635364ให้โหลดไลบรารีที่คุณต้องการใช้อย่างชัดเจนโดยดำเนินการ (เลือกแฟล็กที่คุณชื่นชอบ)
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
อ่านที่อยู่ของฟังก์ชันที่คุณต้องการเรียกใช้ในภายหลัง
sym = dlsym(dlhandle, "conflicting_server_init");
กำหนดและส่งดังต่อไปนี้
alternative_server_init = (int (*)(int, char**, char**))sym;
โทรในลักษณะที่คล้ายกันมากกว่าแบบเดิม สุดท้ายยกเลิกการโหลดโดยดำเนินการ
dlclose(dlhandle);
คุณไม่ควรใช้ร่วมกัน ถ้าฉันจำไม่ผิดตัวเชื่อมโยงเกิดข้อผิดพลาดในกรณีดังกล่าว
ผมไม่ได้ลอง แต่วิธีการแก้ปัญหาอาจจะมีdlopen()
, dlsym()
และdlclose()
ที่ช่วยให้คุณจัดการกับโปรแกรมห้องสมุดแบบไดนามิก หากคุณไม่ต้องการสองฟังก์ชันในเวลาเดียวกันคุณสามารถเปิดไลบรารีแรกใช้ฟังก์ชันแรกและปิดไลบรารีแรกก่อนที่จะใช้ไลบรารี / ฟังก์ชันที่สอง
ปัญหานี้เป็นสาเหตุที่ c ++ มีเนมสเปซ ไม่มีวิธีแก้ปัญหาที่ยอดเยี่ยมจริงๆใน c สำหรับ 2 บุคคลที่สาม libs ที่มีชื่อเดียวกัน
หากเป็นวัตถุแบบไดนามิกคุณอาจสามารถโหลดวัตถุที่ใช้ร่วมกันอย่างชัดเจน (LoadLibrary / dlopen / etc) และเรียกมันในรูปแบบนั้น อีกวิธีหนึ่งหากคุณไม่ต้องการ libs ทั้งสองพร้อมกันในรหัสเดียวกันคุณอาจทำอะไรบางอย่างด้วยการลิงก์แบบคงที่ (ถ้าคุณมีไฟล์. lib / .a)
แน่นอนว่าโซลูชันเหล่านี้ไม่สามารถใช้ได้กับทุกโครงการ
สาบาน? เท่าที่ฉันทราบไม่มีอะไรที่คุณสามารถทำได้หากคุณมีสองไลบรารีที่แสดงจุดเชื่อมโยงที่มีชื่อเดียวกันและคุณต้องเชื่อมโยงกับทั้งสอง
คุณควรเขียนไลบรารีเสื้อคลุมรอบ ๆ หนึ่งในนั้น ไลบรารี Wrapper ของคุณควรแสดงสัญลักษณ์ที่มีชื่อเฉพาะและไม่เปิดเผยสัญลักษณ์ของชื่อที่ไม่ซ้ำ
ตัวเลือกอื่นของคุณคือเปลี่ยนชื่อฟังก์ชันในไฟล์ส่วนหัวและเปลี่ยนชื่อสัญลักษณ์ในไฟล์เก็บถาวรของไลบรารี
ไม่ว่าจะใช้ทั้งสองวิธีมันจะเป็นงานแฮ็ค
คำถามใกล้จะครบสิบปีแล้ว แต่มีการค้นหาใหม่ ๆ ตลอดเวลา ...
ตามที่ตอบไปแล้ว objcopy ที่มีแฟล็ก --redefine-sym เป็นตัวเลือกที่ดีใน Linux ดูตัวอย่างเช่นhttps://linux.die.net/man/1/objcopyสำหรับเอกสารฉบับเต็ม มันค่อนข้างอึดอัดเล็กน้อยเนื่องจากคุณกำลังคัดลอกไลบรารีทั้งหมดในขณะที่ทำการเปลี่ยนแปลงและการอัปเดตทุกครั้งจำเป็นต้องมีการทำงานนี้ซ้ำ แต่อย่างน้อยก็ควรใช้งานได้
สำหรับ Windows การโหลดไลบรารีแบบไดนามิกเป็นวิธีแก้ปัญหาและแบบถาวรเช่นเดียวกับทางเลือก dlopen ใน Linux อย่างไรก็ตามทั้ง dlopen () และ LoadLibrary () เพิ่มรหัสพิเศษที่สามารถหลีกเลี่ยงได้หากปัญหาเดียวคือชื่อที่ซ้ำกัน วิธีการแก้ปัญหาของ Windows มีความสง่างามมากกว่าวิธีการ objcopy: เพียงบอกผู้เชื่อมโยงว่าสัญลักษณ์ในไลบรารีรู้จักชื่ออื่นและใช้ชื่อนั้น มีไม่กี่ขั้นตอนในการทำ คุณต้องสร้างไฟล์ def และแปลชื่อในส่วน EXPORTS โปรดดูที่https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015 ในที่สุดก็จะถูกแทนที่ด้วยเวอร์ชันที่ใหม่กว่า) หรือhttp://www.digitalmars.com/ctg/ctgDefFiles.html(อาจจะถาวรกว่า) สำหรับรายละเอียดไวยากรณ์ทั้งหมดของไฟล์ def กระบวนการนี้คือการสร้างไฟล์ def สำหรับหนึ่งในไลบรารีจากนั้นใช้ไฟล์ def นี้เพื่อสร้างไฟล์ lib จากนั้นเชื่อมโยงกับไฟล์ lib นั้น (สำหรับ Windows DLL ไฟล์ lib จะใช้สำหรับการเชื่อมโยงเท่านั้นไม่ใช่การเรียกใช้โค้ด) ดูวิธีสร้างไฟล์. lib เมื่อมีไฟล์. dll และไฟล์ส่วนหัวสำหรับขั้นตอนการสร้างไฟล์ lib ข้อแตกต่างเพียงอย่างเดียวคือการเพิ่มนามแฝง
สำหรับทั้ง Linux และ Windows ให้เปลี่ยนชื่อฟังก์ชันในส่วนหัวของไลบรารีที่มีการใช้นามแฝง อีกทางเลือกหนึ่งที่ควรใช้คือในไฟล์ที่อ้างถึงชื่อใหม่ไปที่ # กำหนด old_name new_name # รวมส่วนหัวของไลบรารีที่มีการเอ็กซ์พอร์ตถูกใช้นามแฝงจากนั้น #undef old_name ในตัวเรียก หากมีไฟล์จำนวนมากที่ใช้ไลบรารีทางเลือกที่ง่ายกว่าคือการสร้างส่วนหัวหรือส่วนหัวที่ล้อมรอบการกำหนดรวมถึงและอันเดอร์แล้วใช้ส่วนหัวนั้น
หวังว่าข้อมูลนี้จะเป็นประโยชน์!
ฉันไม่เคยใช้ dlsym, dlopen, dlerror, dlclose, dlvsym ฯลฯ แต่ฉันกำลังดู man page และมันให้ตัวอย่างของการเปิด libm.so และแยกฟังก์ชัน cos dlopen ผ่านกระบวนการมองหาการชนหรือไม่? หากไม่เป็นเช่นนั้น OP สามารถโหลดไลบรารีทั้งสองด้วยตนเองและกำหนดชื่อใหม่ให้กับฟังก์ชันทั้งหมดที่ไลบรารีมีให้