จะระบุความชอบของไลบรารีพา ธ ได้อย่างไร?


96

ฉันกำลังรวบรวมโปรแกรม c ++ โดยใช้g++และld. ฉันมี.soไลบรารีที่ฉันต้องการใช้ระหว่างการเชื่อมโยง อย่างไรก็ตามมีไลบรารีที่มีชื่อเดียวกันอยู่/usr/local/libและldกำลังเลือกไลบรารีนั้นทับไลบรารีที่ฉันระบุโดยตรง ฉันจะแก้ไขปัญหานี้ได้อย่างไร?

สำหรับตัวอย่างด้านล่างไฟล์ไลบรารีของฉันคือ/my/dir/libfoo.so.0. สิ่งที่ฉันลองแล้วไม่ได้ผล:

  • คำสั่ง g ++ ของฉันคือ g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • เพิ่ม/my/dirไปยังจุดเริ่มต้นหรือจุดสิ้นสุดของ$PATHตัวแปร en` ของฉัน
  • เพิ่ม/my/dir/libfoo.so.0เป็นอาร์กิวเมนต์ให้กับ g ++

1
สิ่งอื่น ๆlibfoo.*ไฟล์ที่มีอยู่และสถานที่ - .sow / o การ.0, .aฯลฯ ฯลฯ ?
Alex Martelli

คำตอบ:


94

เพิ่มเส้นทางไปยังที่ที่ห้องสมุดใหม่ของคุณจะไปLD_LIBRARY_PATH(มีชื่อแตกต่างกันเล็กน้อยบน Mac ... )

โซลูชันของคุณควรทำงานร่วมกับการใช้-L/my/dir -lfooตัวเลือกในขณะรันไทม์ใช้ LD_LIBRARY_PATH เพื่อชี้ไปยังตำแหน่งของไลบรารีของคุณ

ระมัดระวังในการใช้ LD_LIBRARY_PATH - โดยย่อ (จากลิงค์):

.. ผลกระทบ .. :
ความปลอดภัย : โปรดจำไว้ว่าไดเรกทอรีที่ระบุใน LD_LIBRARY_PATH ได้รับการค้นหาก่อน (!) ตำแหน่งมาตรฐาน? ด้วยวิธีนี้บุคคลที่น่ารังเกียจอาจทำให้แอปพลิเคชันของคุณโหลดเวอร์ชันของไลบรารีที่ใช้ร่วมกันซึ่งมีโค้ดที่เป็นอันตรายได้! นั่นเป็นสาเหตุหนึ่งที่ทำให้ไฟล์ปฏิบัติการ setuid / setgid ละเลยตัวแปรนั้น!
ประสิทธิภาพ: ตัวโหลดลิงก์ต้องค้นหาไดเร็กทอรีทั้งหมดที่ระบุจนกว่าจะพบไดเร็กทอรีที่ไลบรารีที่แบ่งใช้อยู่ - สำหรับไลบรารีที่ใช้ร่วมกันทั้งหมดแอปพลิเคชันจะเชื่อมโยง! ซึ่งหมายความว่าระบบจำนวนมากเรียกให้เปิด () ซึ่งจะล้มเหลวด้วย“ ENOENT (ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว)”! หากพา ธ มีไดเร็กทอรีจำนวนมากจำนวนการโทรที่ล้มเหลวจะเพิ่มขึ้นแบบเชิงเส้นและคุณสามารถบอกได้ตั้งแต่เวลาเริ่มต้นของแอปพลิเคชัน หากไดเร็กทอรีบางส่วน (หรือทั้งหมด) อยู่ในสภาพแวดล้อม NFS เวลาเริ่มต้นแอปพลิเคชันของคุณอาจใช้เวลานานมากและอาจทำให้ทั้งระบบช้าลง!
ความไม่สอดคล้องกัน: นี่เป็นปัญหาที่พบบ่อยที่สุด LD_LIBRARY_PATH บังคับให้แอปพลิเคชันโหลดไลบรารีที่แชร์ที่ไม่ได้เชื่อมโยงและมีแนวโน้มว่าจะเข้ากันไม่ได้กับเวอร์ชันดั้งเดิม สิ่งนี้อาจชัดเจนมากเช่นแอปพลิเคชันขัดข้องหรืออาจนำไปสู่ผลลัพธ์ที่ไม่ถูกต้องหากไลบรารีที่หยิบขึ้นมาไม่ได้ทำสิ่งที่เวอร์ชันดั้งเดิมจะทำ โดยเฉพาะอย่างยิ่งหลังบางครั้งก็ยากที่จะแก้ไขข้อบกพร่อง

หรือ

ใช้ตัวเลือก rpath ผ่าน gcc ไปยัง linker - เส้นทางการค้นหาไลบรารีรันไทม์จะถูกใช้แทนการค้นหาใน dir มาตรฐาน (ตัวเลือก gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

นี่เป็นวิธีแก้ปัญหาชั่วคราว Linker ค้นหา LD_LIBRARY_PATH สำหรับไลบรารีก่อนที่จะค้นหาไดเร็กทอรีมาตรฐาน

หากคุณไม่ต้องการอัปเดต LD_LIBRARY_PATH อย่างถาวรคุณสามารถทำได้ทันทีบนบรรทัดคำสั่ง:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

คุณสามารถตรวจสอบสิ่งที่ตัวเชื่อมโยงไลบรารีรู้เกี่ยวกับการใช้ (ตัวอย่าง):

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

และคุณสามารถตรวจสอบว่าแอปพลิเคชันของคุณใช้ไลบรารีใด:

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)

23
LD_LIBRARY_PATHLIBRARY_PATHจะค้นหาที่รันไทม์ที่รวบรวมเวลาคุณต้องการชุด ดูgcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Bjoern Dahlgren

1
หากไลบรารีของคุณแตกต่างจากไลบรารีระบบอย่างสิ้นเชิงกล่าวคือเป็นไลบรารีที่ต้องใช้เสมอโปรดใช้โซลูชัน rpath LD_LIBRARY_PATH คือการแฮ็กสำหรับการทดสอบและไม่ควรจำเป็นเพื่อให้ปฏิบัติการทำงานได้อย่างถูกต้อง
user2746401

1
DYLD_LIBRARY_PATH สำหรับ Mac
cbinder

นี่คือตัวอย่างคำสั่งแบบเต็ม (สำหรับ C) ที่ทำงานตามคำตอบนี้:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue

25

นี่เป็นคำถามเก่า แต่ดูเหมือนจะไม่มีใครพูดถึงเรื่องนี้

คุณโชคดีที่สิ่งนั้นเชื่อมโยงกัน

คุณต้องเปลี่ยน

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

สำหรับสิ่งนี้:

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

ตัวเชื่อมโยงของคุณติดตามสัญลักษณ์ที่จำเป็นในการแก้ไข หากอ่านไลบรารีก่อนแสดงว่าไม่มีสัญลักษณ์ใด ๆ ที่จำเป็นดังนั้นจึงไม่สนใจสัญลักษณ์ในนั้น ระบุไลบรารีหลังสิ่งที่ต้องเชื่อมโยงเพื่อให้ตัวเชื่อมโยงของคุณมีสัญลักษณ์ที่จะค้นหา

นอกจากนี้ยัง-lfooทำให้ค้นหาไฟล์ที่ตั้งชื่อlibfoo.aหรือlibfoo.soตามต้องการโดยเฉพาะ libfoo.so.0ไม่ ดังนั้นlnชื่อหรือเปลี่ยนชื่อไลบรารีเป็น appopriate

หากต้องการอ้างถึงเพจ 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.

การเพิ่มไฟล์ลงในg++บรรทัดคำสั่งโดยตรงควรจะใช้งานได้เว้นแต่คุณจะวางไว้ก่อนbar.cppทำให้ตัวเชื่อมโยงไม่สนใจเนื่องจากไม่มีสัญลักษณ์ที่จำเป็นเนื่องจากยังไม่จำเป็นต้องใช้สัญลักษณ์ใด ๆ


22

การระบุพา ธ สัมบูรณ์ไปยังไลบรารีควรทำงานได้ดี:

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

คุณจำลบ-lfooเมื่อคุณเพิ่มเส้นทางสัมบูรณ์หรือไม่?


1
โซลูชันนี้ใช้งานได้ดีสำหรับฉันด้วย - พยายามเชื่อมโยงกับ Qt5 เวอร์ชันอื่นที่ไม่ใช่แพ็คเกจการพัฒนา distro ขอบคุณ.
wump

จะทำให้สิ่งนี้ใช้งานได้กับ@สัญลักษณ์ตามเวอร์ชันได้อย่างไร ตัวอย่างน้อยที่สุด: github.com/cirosantilli/cpp-cheat/blob/…
Ciro Santilli 郝海东冠状病六四事件法轮功

11

อีกทางเลือกหนึ่งคือคุณสามารถใช้ตัวแปรสภาพแวดล้อมLIBRARY_PATHและCPLUS_INCLUDE_PATHระบุตำแหน่งที่จะค้นหาไลบรารีและตำแหน่งที่จะค้นหาส่วนหัวได้ตามลำดับ ( CPATHจะทำงานด้วย) โดยไม่ต้องระบุอ็อพชัน -L และ -I

แก้ไข: CPATHรวมทั้งส่วนหัวกับ-IและกับCPLUS_INCLUDE_PATH-isystem


ช่วยเพิ่มตัวอย่างการใช้งานได้ไหม
Hanna Khalil

export LIBRARY_PATH = /path/to/libในเซสชันคอนโซลเดียวกับที่คุณรวบรวม
Alexandre Hamez

0

หากใช้เพื่อทำงานกับ DLL ใน Windows และต้องการข้าม. ดังนั้นหมายเลขเวอร์ชันใน linux / QT การเพิ่มCONFIG += pluginจะนำหมายเลขเวอร์ชันออก ในการใช้พา ธ สัมบูรณ์ไปยัง. ดังนั้นการให้ลิงค์เกอร์ทำงานได้ดีดังที่คุณ Klatchko กล่าวถึง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.