หมายเลข SO (วัตถุที่ใช้ร่วมกัน) ทำงานอย่างไร


123

ฉันทราบว่าวัตถุที่ใช้ร่วมกันภายใต้ Linux ใช้ "หมายเลข" คือวัตถุที่ใช้ร่วมกันรุ่นต่าง ๆ จะได้รับส่วนขยายต่างกันตัวอย่างเช่น

  • example.so.1
  • example.so.2

ฉันเข้าใจความคิดที่จะมีสองไฟล์ที่แตกต่างกันเช่นที่ไลบรารีสองเวอร์ชันสามารถมีอยู่บนระบบ (ตรงข้ามกับ "DLL Hell" บน Windows) ฉันต้องการที่จะรู้วิธีการทำงานในทางปฏิบัติ? บ่อยครั้งที่ผมเห็นว่าexample.soในความเป็นจริงการเชื่อมโยงสัญลักษณ์example.so.2ที่.2เป็นรุ่นล่าสุด แอปพลิเคชันนั้นขึ้นอยู่กับเวอร์ชันที่เก่ากว่าของการexample.soระบุว่าถูกต้องอย่างไร มีกฎใดที่ต้องใช้ตัวเลขหรือไม่ หรือนี่เป็นเพียงแค่การประชุม? เป็นกรณีที่ไม่เหมือนกับใน Windows ที่มีการถ่ายโอนซอฟต์แวร์ระหว่างระบบหากระบบมีวัตถุที่ใช้ร่วมกันรุ่นใหม่กว่ามันถูกเชื่อมโยงไปยังรุ่นที่เก่ากว่าโดยอัตโนมัติเมื่อรวบรวมจากแหล่งที่มาหรือไม่

ฉันสงสัยว่าสิ่งนี้เกี่ยวข้องกับldconfigแต่ไม่แน่ใจว่าจะทำอย่างไร

คำตอบ:


87

ตัวไบนารีเองทราบว่าพวกเขาพึ่งพาไลบรารี่ประเภทใดและขอเป็นพิเศษ คุณสามารถใช้lddเพื่อแสดงการอ้างอิง; สำหรับฉันlsคือ:

$ ldd /bin/ls
    linux-gate.so.1 =>  (0xb784e000)
    librt.so.1 => /lib/librt.so.1 (0xb782c000)
    libacl.so.1 => /lib/libacl.so.1 (0xb7824000)
    libc.so.6 => /lib/libc.so.6 (0xb76dc000)
    libpthread.so.0 => /lib/libpthread.so.0 (0xb76c3000)
    /lib/ld-linux.so.2 (0xb784f000)
    libattr.so.1 => /lib/libattr.so.1 (0xb76bd000)

ในขณะที่คุณสามารถดูจะชี้ไปเช่นไม่เพียงlibpthread.so.0libpthread.so


เหตุผลในการเชื่อมโยงสัญลักษณ์สำหรับตัวเชื่อมโยงนั้น เมื่อคุณต้องการที่จะเชื่อมโยงlibpthread.soโดยตรงคุณให้gccธง-lpthreadและมันจะเพิ่มในlibคำนำหน้าและ.soคำต่อท้ายโดยอัตโนมัติ คุณไม่สามารถบอกให้เพิ่มใน.so.0ส่วนต่อท้ายได้ดังนั้นลิงก์สัญลักษณ์จะชี้ไปยัง lib เวอร์ชันใหม่ล่าสุดเพื่อให้ง่ายขึ้น


เครื่องหมายเท่ากับ "= ls" ไม่ควรมีอยู่ เพียงแค่ใช้ "ldd ls"
bmacnaughton

1
@bmacnaughton นั่นอาจจะทำให้คุณมีข้อผิดพลาดเพราะlddต้องใช้เส้นทางที่สมบูรณ์เพื่อปฏิบัติการ =lsทำอย่างนั้นใน zsh แต่ฉันเปลี่ยนเพราะไม่ใช่ทุกคนที่ใช้เปลือกนั้น
Michael Mrozek

น่าสนใจ ฉันใช้ทุบตีบน Ubuntu และดูเหมือนว่าจะทำงานโดยไม่ต้องใช้เส้นทางแบบเต็ม ขอบคุณสำหรับคำอธิบาย - ฉันไม่ได้ใช้ zsh
bmacnaughton

60

หมายเลขในไลบรารีแบบแบ่งใช้เป็นแบบแผนที่ใช้ใน Linux เพื่อระบุ API ของไลบรารี รูปแบบโดยทั่วไปคือ:

libFOO.so.MAJOR.MINOR

และตามที่คุณสังเกตเห็นมักจะมีลิงค์สัญลักษณ์จาก libFOO.so ไปยัง libFOO.so.MAJOR.MINOR ldconfig รับผิดชอบในการอัพเดทลิงค์นี้เป็นเวอร์ชั่นใหม่ล่าสุด

โดยทั่วไป MAJOR จะเพิ่มขึ้นเมื่อมีการเปลี่ยนแปลง API (จุดเข้าใหม่จะถูกลบออกหรือพารามิเตอร์หรือประเภทที่เปลี่ยนแปลง) โดยทั่วไป MINOR จะเพิ่มขึ้นสำหรับการแก้ไขข้อผิดพลาดหรือเมื่อมีการนำ API ใหม่มาใช้โดยไม่ทำลาย API ที่มีอยู่

การอภิปรายที่กว้างขวางมากขึ้นสามารถพบได้ที่นี่: การแยกไลบรารีที่แบ่งใช้


สวัสดีมิเกลขอบคุณสำหรับความอัปยศที่ฉันไม่สามารถยอมรับสองคำตอบเพราะที่เติมเต็มอย่างดี +1 จากฉันลิงค์ยอดเยี่ยมขอบคุณอีกครั้ง!

4
เกือบจะถูกต้อง แต่จริง ๆ แล้วlibFOO.so.MAJOR.MINOR(ไม่ใช่ตอนท้าย)
JonnyJD

6
คำตอบนี้ผิดมาก ก่อนอื่นตัวเลขที่คุณเห็นไม่เกี่ยวข้องกับ API นี่คือ ABI ล้วนๆ ประการที่สองการประชุมที่นี่ไม่ใช่การกำหนดเวอร์ชันความหมายเหมือนที่คุณตอบรับ ค่อนข้างเป็นการประชุมแบบ libtool ที่มีคุณสมบัติที่ดีของการจับคู่กับหมายเลขเวอร์ชันไลบรารี่เดียวที่ ld.so สามารถเปรียบเทียบ (ดูgnu.org/software/libtool/manual/html_node/สำหรับข้อมูลเพิ่มเติม)
NewbiZ

23

ไลบรารีที่แบ่งใช้ควรเป็นเวอร์ชันตามแบบแผนต่อไปนี้:

blah.so.X.Y.Z

ที่ไหน

  • X = ปล่อย ABI ที่เข้ากันไม่ได้ย้อนหลัง
  • Y = รีลีส ABI ที่เข้ากันได้แบบย้อนหลัง
  • Z = การเปลี่ยนแปลงภายในเท่านั้น - ไม่มีการเปลี่ยนแปลง ABI

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

ldconfigรักษาตารางของไลบรารีที่แบ่งใช้ที่มีอยู่บนระบบและที่ที่พา ธ ไปยังไลบรารีนั้นมีอยู่ คุณสามารถยืนยันสิ่งนี้ได้ด้วยการเรียกใช้:

ldconfig -p

เมื่อแพ็กเกจถูกสร้างขึ้นเพื่ออะไรอย่าง Red Hat ไลบรารีที่แบ่งใช้ที่ถูกเรียกใช้ในไบนารีจะถูกค้นหาและเพิ่มเป็นการอ้างอิงของแพ็คเกจที่เวลาสร้าง RPM ดังนั้นเมื่อคุณไปติดตั้งแพคเกจติดตั้งจะขึ้นไปดูหรือไม่ว่ามีการติดตั้งในระบบโดยการตรวจสอบhello.so.1ldconfig

คุณสามารถดูการพึ่งพาของแพ็คเกจโดยทำสิ่งที่ชอบ:

rpm -qpR hello.rpm

ระบบนี้ (ต่างจาก Windows) อนุญาตให้hello.soติดตั้งได้หลายเวอร์ชันในระบบและใช้งานโดยแอพพลิเคชั่นต่าง ๆ ในเวลาเดียวกัน


ฉันคิดว่านี่เป็นคำตอบที่ดีที่สุด
Kemin Zhou

1
ไลบรารีที่แบ่งใช้ควรเป็นเวอร์ชันตามแบบแผนต่อไปนี้ (... ) - คุณช่วยอ้างอิงสำหรับคำสั่งนี้ได้ไหม
Piotr Dobrogost

19

libNAME.so เป็นชื่อไฟล์ที่ใช้โดยคอมไพเลอร์ / ลิงเกอร์เมื่อค้นหาไลบรารีที่ระบุโดย -lNAME เป็นครั้งแรก ภายในไฟล์ไลบรารีที่แชร์เป็นฟิลด์ที่เรียกว่า SONAME ฟิลด์นี้ถูกตั้งค่าเมื่อไลบรารีตัวเองถูกเชื่อมโยงครั้งแรกกับวัตถุที่ใช้ร่วมกัน (ดังนั้น) โดยกระบวนการสร้าง SONAME นี้จริง ๆ แล้วสิ่งที่ linker จัดเก็บในการปฏิบัติการขึ้นอยู่กับวัตถุที่แชร์นั้นเชื่อมโยงกับมัน โดยทั่วไปแล้ว SONAME จะอยู่ในรูปแบบของ libNAME.so.MAJOR และมีการเปลี่ยนแปลงเมื่อใดก็ตามที่ห้องสมุดไม่สามารถใช้งานร่วมกับ executables ที่มีอยู่ซึ่งเชื่อมโยงกับมันและไลบรารีหลักทั้งสองรุ่นสามารถติดตั้งได้ตามต้องการ (แม้ว่าจะมีเพียงอันเดียวเท่านั้น ในฐานะ libNAME) ดังนั้นเพื่อสนับสนุนการอัปเกรดระหว่างไลบรารีรุ่นรองอย่างง่ายดาย libNAME.so.MAJOR จึงเป็นลิงก์ไปยังไฟล์เช่น libNAME.so.MAJOR.MINOR สามารถติดตั้งเวอร์ชันย่อยใหม่ได้และเมื่อเสร็จสิ้นลิงก์ไปยังเวอร์ชันรองเดิมจะถูกชนเพื่อให้ชี้ไปที่เวอร์ชันย่อยใหม่อัปเกรดการเรียกใช้ใหม่ทั้งหมดทันทีเพื่อใช้ไลบรารี่ที่อัปเกรดแล้ว ดูคำตอบของฉันด้วยLinux, GNU GCC, ld, สคริปต์เวอร์ชันและรูปแบบไบนารีของ ELF - มันทำงานอย่างไร

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