ระบบของฉันใช้ไลบรารี C เวอร์ชันใด


43

ฉันจะบอกได้อย่างไรว่าห้องสมุดของฉันใช้ระบบผู้ใช้อะไร เหตุผลที่เป็นไปได้ที่จะต้องการข้อมูลนี้ ได้แก่ :

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

  • ฉันกังวลเกี่ยวกับความเข้ากันได้ของ ABIกับไบนารีของบุคคลที่สามที่ฉันต้องการลองและติดตั้งนอกระบบการจัดการแพ็กเกจของระบบ

  • ฉันมีแพ็กเกจซอร์สซึ่งเอกสารระบุถึงความต้องการไลบรารีเวอร์ชันระบบขั้นต่ำของฉัน แต่กระบวนการบิลด์ไม่ดำเนินการตรวจสอบใด ๆ

  • ฉันกำลังสร้าง cross-compiler ที่กำหนดเป้าหมายไปยังระบบเฉพาะและไม่ต้องการที่จะเสี่ยงต่อปัญหาความเข้ากัน


ทำไมไม่ลองดูล่ะ ฉันไม่รู้ว่าเวอร์ชั่นบอกทุกอย่างให้คุณหรือไม่ แล้วแพทช์ล่ะ? หรือมีการกระจายความระมัดระวังเกี่ยวกับการเปลี่ยนแปลง ABI หรือไม่? ไม่ใช่ปัญหาที่ว่าสัญลักษณ์ที่ส่งออกจะได้รับการแก้ไขหรืออะไรแบบนั้น?
Faheem Mitha

คำตอบที่ดี แต่ไม่มีใครอยู่กับวิธีการทำเช่นนี้บน Mac lddที่ไม่มี ฉันไม่แน่ใจว่าotool --versionจะถือเป็นการให้ข้อมูลเดียวกันได้หรือไม่
dubiousjim

@dubiousjim มีคนที่สามารถ; ไม่ใช่ฉันเพราะฉันไม่ใช่ผู้ใช้ Mac รอบ ๆ ที่นี่คุณอาจต้องถามอย่างเฉพาะเจาะจงเกี่ยวกับเรื่องนั้น - ส่วนหนึ่งของปัญหาคือบางทีคนทั่วไปไม่ได้ใช้ C ธรรมดาใน OSX มาก? แต่ฉันแน่ใจว่าจะมีคนปกติที่รู้ คุณสามารถโพสต์ลิงก์ไปยังสิ่งนี้ในการแชทและดูว่าเกิดอะไรขึ้น แต่อาจเป็นคำถามใหม่ที่เฉพาะเจาะจงมากขึ้นจะดีกว่า
goldilocks

คำตอบ:


50

ระบบ GNU / Linuxมักใช้ทั้ง glibc (ตระกูล Fedora / Redhat, Arch) หรือลูกพี่ลูกน้องที่ใกล้ชิด, eglibc (ตระกูล Debian / Ubuntu); เนื่องจาก eglibc กำลังถูกรวมกลับเข้าสู่ glibc ( ดูEGLIBC 2.19 สาขาที่สร้างภายใต้ "ข่าว" ) ในอนาคตอันใกล้พวกเขาทั้งหมดจะถูก glibc อีกครั้ง

วิธีที่ง่ายที่สุดในการตรวจสอบเวอร์ชั่นที่แน่นอนคือการถามlddซึ่งมาพร้อมกับไลบรารี C

ใน Fedora 20:

> ldd --version
ldd (GNU libc) 2.18

นั่นเป็น glibc 2.18

บน Raspbian (พอร์ต Debian 7 สำหรับ ARMv6 Broadcom SoC):

> ldd --version
ldd (Debian EGLIBC 2.13-38+rpi2) 2.13

นั่นคือ eglibc 2.13

หากคุณผสมและจับคู่บางส่วนด้วยเหตุผลใดก็ตามหรือไม่แน่ใจlddคุณสามารถสอบถามไลบรารี C ได้โดยตรง

> whereis libc.so
libc: /usr/lib64/libc.a /usr/lib64/libc.so /usr/share/man/man7/libc.7.gz

ไม่มีสิ่งใดที่สามารถใช้งานได้ แต่ให้เบาะแสเกี่ยวกับตำแหน่งที่จะค้นหา

> $(find /usr/lib64/ -executable -name "*libc.so*") --version
GNU C Library (GNU libc) stable release version 2.18, by Roland McGrath et al.

อย่างไรก็ตามมันไม่จำเป็นต้องง่ายนักเพราะไลบรารี C ไม่จำเป็นต้องอยู่ที่ไหนสักแห่งwhereisสามารถค้นหาได้

> whereis libc.so
libc: /usr/share/man/man7/libc.7.gz

น่าเสียดายที่หน้า man ไม่ได้ระบุหมายเลขเวอร์ชั่น lddยังคงมีประโยชน์เนื่องจากการทำงานใด ๆ ลิงก์ปฏิบัติการแบบไดนามิกบนระบบ (เช่นเกือบทุกอย่าง/usr/bin) จะเชื่อมโยงไปยังไลบรารี C

> ldd /usr/bin/touch
    /usr/lib/arm-linux-gnueabihf/libcofi_rpi.so (0xb6eed000)
    librt.so.1 => /lib/arm-linux-gnueabihf/librt.so.1 (0xb6ed0000)
    libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6da1000)
    /lib/ld-linux-armhf.so.3 (0xb6efb000)
    libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6d82000)

libc.so.6 อยู่ในบรรทัดที่สาม

> /lib/arm-linux-gnueabihf/libc.so.6 --version
GNU C Library (Debian EGLIBC 2.13-38+rpi2) stable release version 2.13, by Roland McGrath et al.

อะไรที่ทำให้ระบบ GNU / Linux "ปกติ" คืออะไร? แล้วการแจกแจงโดยใช้muslล่ะ?
Elliott Frisch

1
@ElliottFrisch มันตั้งใจที่จะนำไปใช้กับ GNU / Linux เช่นเดียวกับใน "ปกติ GNU / Linux" (คำคุณศัพท์คำนาม) เนื่องจากอาจมี (เป็นฉันแน่ใจ) ระบบที่ไม่ได้ใช้ (e) glibc แต่ทำใช้ส่วนที่เหลือของสแต็ก GNU (ทุบตี binutils ฯลฯ ) ฉันจะพิจารณาระบบ GNU / Linux เหล่านั้น "ผิดปกติ" แต่ฉันได้ลบ "ปกติ" และเปลี่ยนเป็น "ระบบ GNU / Linux มักจะใช้ ... " หมายเหตุฉันตั้งใจทิ้งคำถามไว้เฉพาะการเปิด WRT OS (ไม่มีลินุกซ์หรือแท็ก GNU หรือ glibc) ดังนั้นหากคุณต้องการเพิ่มคำตอบเกี่ยวกับระบบใด ๆ ที่เหมาะสมกับ U&L โปรดทำ
goldilocks

1
หลังจากที่ฉันพบว่ามันเหมือนกับที่คุณแสดงให้เห็นและฉันถามรุ่นมันก็พิมพ์ส่วนขยายที่มี! (ในกรณีของฉันสมบูรณ์, ฝังศพใต้ถุนโบสถ์, libidn, กระทู้พื้นเมืองและผูก) และอ้างถึง ABI: libc ABIs: UNIQUE IFUNC

เดเบียนใช้/lib/`uname -m`*เส้นทาง วิธีพกพาน่าจะเป็น: find /lib/`uname -m`* /usr/lib* -executable -name "*libc.so*" | xargs --version. ขอบคุณสำหรับคำอธิบายที่ดี
pevik

@pevik: ผิดบนแขนมัน /lib/arm-linux-gnueabihf/libc.so.6 และไม่ใช่ /lib/armv7l/libc.so.6
Quandary

14

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

เริ่มด้วยโปรแกรมเรื่องเล็กน้อย:

#include <stdio.h>
int main() {
    printf("Hello, world\n");
    return 0;
}

คอมไพล์โดยใช้คอมไพเลอร์ที่คุณจะใช้สำหรับซอร์สโค้ดจากนั้นใช้lddเพื่อค้นหาว่าไลบรารี C คืออะไร:

$ ldd ./libc-test 
        linux-vdso.so.1 (0x00007fff2e5fe000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8c8ad98000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8c8b171000)

ตอนนี้คุณมีเส้นทางไปยังไลบรารี C คุณสามารถค้นหาสิ่งนี้ได้ในผู้จัดการแพ็คเกจเพื่อค้นหาแพ็คเกจ (เช่นdpkg -S /lib/x86_64-linux-gnu/libc.so.6หรือrpm -q -f /lib/x86_64-linux-gnu/libc.so.6)

อย่างน้อยในกรณีของ eglibc / glibc คุณสามารถรันได้:

$ /lib/x86_64-linux-gnu/libc.so.6  
GNU C Library (Debian EGLIBC 2.18-4) stable release version 2.18, by Roland McGrath et al.
Copyright (C) 2013 Free Software Foundation, Inc.

สุดท้ายคุณสามารถดูว่าคุณสามารถรับเบาะแสจากobjdump -p /lib/x86_64-linux-gnu/libc.so.6โดยดูในส่วนคำจำกัดความรุ่น :

Version definitions:
1 0x01 0x0865f4e6 libc.so.6
2 0x00 0x09691a75 GLIBC_2.2.5
3 0x00 0x09691a76 GLIBC_2.2.6
21 0x00 0x06969197 GLIBC_2.17
        GLIBC_2.16 
22 0x00 0x06969198 GLIBC_2.18
        GLIBC_2.17 
23 0x00 0x0963cf85 GLIBC_PRIVATE
        GLIBC_2.18 

สังเกตว่าสัญลักษณ์ GLIBC_2.18 มีหมายเลขเวอร์ชันล่าสุดท่ามกลางสัญลักษณ์ที่แสดงรายการและรุ่นไลบรารี่เป็น 2.18 แม้ว่า eglibc จะเป็น (มันมีจุดมุ่งหมายที่จะใช้งานร่วมกันได้กับ glibc 2.18 ดังนั้นจึงใช้สัญลักษณ์รุ่นเดียวกัน)

คุณสามารถลองใช้stringsเพื่อค้นหาบางสิ่งเกี่ยวกับมัน คุณจะต้องการระบุความยาวน้อยที่สุด ( -n) หรือใช้ grep เพื่อค้นหาบางสิ่ง:

$ strings  /lib/x86_64-linux-gnu/libc.so.6 | grep 'version [0-9]'
$ strings  /lib/x86_64-linux-gnu/libc.so.6 | grep -iC1 'copyright'

ทั้งทำงานให้กับ eglibc นี้

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


9

คำตอบที่ชัดเจนแม้ว่าจะไม่ครอบคลุมมากที่สุดคือการตรวจสอบผู้จัดการแพ็คเกจของคุณเช่น

rpm -qi glibc
dpkg -l libc6

(น่าเศร้าที่ glibc ไม่มี.pcไฟล์pkconfig ดังนั้นจึงpkgconfig --modversion glibcไม่ใช่นักวิ่ง) ดูgetconfคำแนะนำที่ยอดเยี่ยมของ @ Gnouc

กรณีที่ง่ายที่สุดด้วย gcc + glibc และสิ่งที่ฉันใช้เป็นอันดับแรกคือเรียกใช้libc.soงานตามที่ระบุไว้ในคำตอบอื่น ๆ ที่นี่ ไม่จำเป็นต้องผ่านการขัดแย้งใด ๆ มันเอาท์พุทรุ่นของมันโดยค่าเริ่มต้น วิธีนี้ใช้งานได้ไกลถึง glibc-2.1 (glibc-2.0 seg-faults แต่ถึงอย่างนั้นคุณก็สามารถตรวจสอบglibcbugสคริปต์(ตอนนี้เลิกใช้) เพื่อยืนยันเวอร์ชัน) วิธีนี้ยังใช้ได้กับmusl-libcรุ่นล่าสุด (> 0.9.15) (ซึ่งเพิ่งไป 1.0 วันนี้, 20 มีนาคม) มันไม่ทำงานกับ uClibc มันเป็น segfaults

วิธีง่ายๆในการบอกสิ่งที่คุณgccกำลังจะทำคือรวบรวม:

#include <gnu/libc-version.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("%s %s\n",gnu_get_libc_version(),gnu_get_libc_release());
    printf("glibc v%i %i.%i\n",__GNU_LIBRARY__,__GLIBC__,__GLIBC_MINOR__);
    return 0;
}

(ด้วย glibc <stdio.h>รวมถึงการ<features.h>กำหนดมาโคร GLIBC ที่เกี่ยวข้องคุณจำเป็นต้อง<gnu/libc-version.h>มีการประกาศฟังก์ชัน)

สิ่งนี้จะจับกรณีที่ซับซ้อนมากขึ้น (หลาย libc's และ / หรือคอมไพเลอร์หลายรายการ) สมมติว่าคุณใช้คอมไพเลอร์ที่ถูกต้อง (และตั้งค่าสถานะ) แน่นอน (ฉันสงสัยว่ามันจะไม่แยกความแตกต่างระหว่าง eglibc และ glibc ที่เหมาะสม)

หากคุณมั่นใจว่าคุณกำลังใช้ glibc (หรือ eglibc) แล้วldจะยืนยันเวอร์ชัน (ขออภัยนี่ไม่ถูกต้อง)

หาก__GNU_LIBRARY__ไม่ได้กำหนดไว้คุณจะได้รับข้อผิดพลาดจากนั้นก็ถึงเวลาสำหรับแผน B

gcc -dumpmachineอาจช่วยเช่นการ uClibc ก็มีคำต่อท้ายตามที่อาจ-uclibc gcc -dumpspecs | grep dynamic-linkerนี่อาจหมายถึง ABI

gcc -print-file-name=libc.soจะบอกให้คุณทราบว่าไฟล์ที่คอมไพเลอร์ใช้สำหรับ " -lc" นี่เป็นตัวเชื่อมโยงสคริปต์ในการติดตั้ง gcc ซึ่งคุณสามารถอ่านเป็นข้อความธรรมดาได้ libc.soที่จะแสดงเส้นทางที่แน่นอนที่จะ นอกจากนี้ยังจะทำงานหากคุณผ่านธงเหมือนหรือ-m32-m64

ในกรณีที่คุณกำลังใช้uClibc (ที่ใช้โดย OpenWRT และอื่น ๆ ) จะกำหนด__UCLIBC_MAJOR__, __UCLIBC_MINOR__และ__UCLIBC_SUBLEVEL__เช่นเดียวกับ__UCLIBC__ใน<features.h>จึงตรวจพบได้ง่ายโดยใช้รูปแบบเล็ก ๆ น้อย ๆ เกี่ยวกับการดังกล่าวข้างต้น C โค้ด เพื่อประโยชน์ในการใช้งานร่วมกันได้ uClibc อาจกำหนดมาโคร GNU / GLIBC ตามที่ใช้ด้านบนซึ่งในปัจจุบันมันอ้างว่าเป็น glibc-2.2 มันไม่ได้ขณะใช้gnu_get_libc_X()ฟังก์ชั่น แต่ก็ไม่ดำเนินการgetconfซึ่งอาจทำให้เข้าใจผิด (ผมสงสัยว่ามันจะกลับคำตอบที่ว่างเปล่าสำหรับgetconf GNU_LIBC_VERSION, สร้าง env ของฉันคือบูดบึ้งวันนี้ดังนั้นผมจึงไม่สามารถยืนยัน.)

ในกรณีที่คุณไม่ได้ใช้Dietlibc การวิ่งdiet -vจะแสดงเวอร์ชั่น

(FWIW เป็นเวลาหลายปีกับซอฟต์แวร์ที่ใช้ autoconf ฉันมีปัญหาเกี่ยวกับการตรวจสอบgccและg++ข้อกำหนดมากกว่าการตรวจสอบสำหรับคุณสมบัติ glibc)


5

GNU libc (ส่วนใหญ่ที่ลีนุกซ์ใช้ในรูปแบบใดรูปแบบหนึ่ง) ไปจนถึงความยาวที่ยอดเยี่ยมเพื่อรักษาความเข้ากันได้ย้อนหลังอย่างเข้มงวด ดังนั้นคุณควรพบปัญหาเฉพาะในกรณีที่คุณพยายามเรียกใช้ไบนารีที่ใหม่เกินไปในเวอร์ชันเก่า (หรือการกระจาย "องค์กร" โดยปกติจะหยุดเวอร์ชันโดยเฉพาะอย่างยิ่งรากฐานที่ต้องการไลบรารี C การแก้ไข backporting ขณะที่รักษาความเข้ากันได้ของไบนารี . ฉันเชื่อว่าคุณมีความรับผิดชอบมากกว่าที่จะประสบปัญหากับห้องสมุดอื่น ๆ (C ++ มีการเปลี่ยนแปลง API / ABI เล็กน้อยในหน่วยความจำล่าสุดห้องสมุดอื่น ๆ บางแห่งไม่สนใจความเข้ากันได้แบบย้อนหลัง)

น่าเศร้าวิธีเดียวที่จะตรวจสอบให้แน่ใจคือการลอง


+1 ในความเป็นจริงพวกเขามีแผนภูมิเกี่ยวกับความเข้ากันได้ย้อนหลังและฉันจะถือว่าเหตุผลเดียวที่ไม่ใช่ทั้งหมด 100% เป็นเพราะรหัสที่ใช้ประโยชน์จากส่วนขยาย GNU ที่ลึกลับ อย่างไรก็ตามไม่มีแผนภูมิดังกล่าวที่ฉันทราบเกี่ยวกับความเข้ากันได้ไปข้างหน้าซึ่งในขณะที่คุณทราบว่ามีความกังวลมากขึ้น
goldilocks

5

(นี่คือหลักคำตอบเดียวกับ goldilocks แต่มีคำอธิบายเพิ่มเติมเกี่ยวกับสิ่งที่เกิดขึ้นภายใต้ประทุน)

core shared library สำหรับ GNU libc libc.so.6(บน Linux; Hurd มี SONAME แตกต่างกัน) มีคุณสมบัติที่ผิดปกติ (สำหรับ shared library) ที่คุณสามารถเรียกใช้มันเป็น executable ถ้าคุณทำเช่นนั้นมันจะพิมพ์สิ่งต่าง ๆ ที่ยูทิลิตี้ GNU มักจะพิมพ์เมื่อทำงานด้วย--versionเช่นนี้:

$ /lib/x86_64-linux-gnu/libc.so.6 
GNU C Library (Debian EGLIBC 2.18-4) stable release version 2.18, by Roland McGrath et al.
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.2.
Compiled on a Linux 3.12.6 system on 2014-03-02.
Available extensions:
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

แต่แน่นอนไดเรกทอรีที่libc.so.6ชีวิตไม่ได้อยู่ใน$PATHดังนั้นคุณต้องรู้ว่าจะมองหามัน มันอาจจะอยู่ใน/lib, /lib64, /usr/libหรือบางสิ่งบางอย่างแม้ wackier (เช่นในกรณีนี้) สะดวกสบายlddจะบอกคุณ:

$ ldd /bin/sh | grep libc
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5660b93000)

แน่นอนว่าคุณต้องรู้ชื่อพา ธ แบบเต็มของไบนารีที่เชื่อมโยงแบบไดนามิกได้ shปฏิบัติการรับประกันได้ว่าจะใน/bin(เพราะจำนวนมากดังนั้น#!สคริปต์คาดว่าจะ) และตัวเองไม่สามารถจะเป็น#!สคริปต์ มันอาจจะเชื่อมโยงแบบคงที่ แต่ฉันไม่ได้พบระบบที่ไม่ว่าในหลายปีที่ผ่านมา

ฉันไม่รู้ว่าคุณกำลังทำอะไรถ้าคุณใช้ uClibc หรือ musl หรืออะไรแปลก ๆ


2
คุณไม่จำเป็นต้องรู้เส้นทางแบบเต็มไปยัง / bin / sh หรืออะไรก็ตาม $ ldd $(which sh) | grep libcคุณสามารถเสมอ : D
Matt Nordhoff

5

อีกวิธีในการรับ:

getconf GNU_LIBC_VERSION

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