Hệ thống của tôi sử dụng phiên bản thư viện C nào?


43

Làm cách nào tôi có thể biết chắc thư viện C của người dùng mà hệ thống của tôi sử dụng là gì? Những lý do có thể cần thông tin này bao gồm:

  • Có một gói nguồn khổng lồ mà tôi đang xem xét tải xuống mà tôi chắc chắn sẽ kiểm tra đúng cách và liệt kê một phiên bản thư viện tối thiểu, nhưng tôi muốn tiết kiệm cho mình một rắc rối tiềm năng bằng cách kiểm tra trước xem nó có hoạt động không.

  • Tôi lo ngại về khả năng tương thích ABI với một số nhị phân của bên thứ ba mà tôi muốn thử và cài đặt bên ngoài hệ thống quản lý gói của hệ thống.

  • Tôi có một gói nguồn mà tài liệu đề cập đến sự cần thiết của một phiên bản tối thiểu của thư viện hệ thống của tôi, nhưng quá trình xây dựng không thực hiện bất kỳ kiểm tra nào.

  • Tôi đang xây dựng một trình biên dịch chéo nhắm mục tiêu vào một hệ thống cụ thể và không muốn gặp rủi ro về các vấn đề tương thích về phía trước .


Tại sao không thử nó và xem. Tôi không biết nếu phiên bản cho bạn biết tất cả mọi thứ; Còn miếng vá thì sao? Hoặc sự phân tâm cẩn thận về việc thay đổi ABI? Không phải là vấn đề liệu các biểu tượng xuất khẩu có được giải quyết hay không?
Faheem Mitha

Câu trả lời hay, nhưng không ai giải quyết cách làm điều này trên máy Mac, nơi không có ldd. Tôi không chắc otool --versioncó thể được coi là cung cấp thông tin tương tự.
dubiousjim

@dubiousjim Ai đó có thể; không phải tôi, vì tôi không phải là người dùng Mac. Ở đây bạn có thể phải hỏi cụ thể về điều đó - một phần của vấn đề có lẽ mọi người thường không sử dụng C đơn giản trên OSX? Nhưng tôi chắc chắn sẽ có một người thường xuyên biết. Bạn cũng có thể đăng một liên kết đến điều này trong trò chuyện và xem điều gì xảy ra, nhưng có lẽ một câu hỏi mới, cụ thể hơn sẽ tốt hơn.
goldilocks

Câu trả lời:


50

Các hệ thống GNU / Linux thường sử dụng glibc (họ Fedora / Redhat, Arch) hoặc anh em họ thân của nó, eglibc (họ Debian / Ubuntu); kể từ eglibc hiện đang được sáp nhập trở lại vào glibc ( xem Chi nhánh EGLIBC 2.19 được tạo trong "Tin tức" ), trong tương lai gần, tất cả chúng sẽ lại được glibc.

Cách dễ nhất để kiểm tra phiên bản chính xác là hỏi ldd, tàu nào có thư viện C.

Trên Fedora 20:

> ldd --version
ldd (GNU libc) 2.18

Đó là glibc 2.18.

Trên Raspbian (cổng Debian 7 cho ARMv6 Broadcom SoC):

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

Đó là eglibc 2.13.

Nếu vì bất kỳ lý do gì bạn đã trộn và kết hợp một số phần hoặc không chắc chắn về điều đó ldd, bạn có thể truy vấn trực tiếp thư viện C.

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

Không ai trong số đó có thể thực thi được nhưng họ cung cấp manh mối về nơi tìm thấy nó.

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

Tuy nhiên, nó không nhất thiết phải dễ dàng như vậy, vì thư viện C không phải cư trú ở đâu đó whereiscó thể tìm thấy nó.

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

Thật không may, trang man không cung cấp số phiên bản. lddvẫn có ích, vì mọi hoạt động, được thực thi liên kết động trên hệ thống (ví dụ: hầu hết mọi thứ trong /usr/bin) sẽ liên kết với thư viện 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 là trên dòng thứ ba.

> /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.

Điều gì làm cho một hệ thống GNU / Linux "bình thường"? Điều gì về phân phối sử dụng musl ?
Elliott Frisch

1
@ElliottFrisch Nó được dự định áp dụng cho GNU / Linux, như trong "GNU / Linux bình thường" (tính từ, danh từ), vì có thể có (tôi chắc chắn) các hệ thống không sử dụng (e) glibc nhưng làm sử dụng phần còn lại của ngăn xếp GNU (bash, binutils, v.v.). Tôi sẽ xem xét các hệ thống GNU / Linux "bất thường" đó. Nhưng tôi đã xóa "bình thường" và thay đổi nó thành "hệ thống GNU / Linux thường sử dụng ...". Lưu ý Tôi cố tình để các câu hỏi cụ thể về hệ điều hành WRT mở (không có thẻ linux hoặc GNU hoặc glibc), vì vậy nếu bạn muốn thêm câu trả lời về bất kỳ hệ thống nào phù hợp với U & L, vui lòng làm.
goldilocks

1
Sau khi tôi tìm thấy nó giống như bạn đã hiển thị và tôi đã truy vấn phiên bản, nó cũng đã in các tiện ích mở rộng có sẵn! (trong trường hợp của tôi là sơ khai, mật mã, libidn, chủ đề gốc và liên kết) và được đề cập đến ABI: libc ABIs: UNIQUE IFUNC.

Debian sử dụng /lib/`uname -m`*đường dẫn. Vì vậy, cách di động sẽ là : find /lib/`uname -m`* /usr/lib* -executable -name "*libc.so*" | xargs --version. Cảm ơn lời giải thích tốt đẹp.
pevik

@pevik: Wrong, trên cánh tay của nó /lib/arm-linux-gnueabihf/libc.so.6, và không /lib/armv7l/libc.so.6
tình thế khó khăn

14

Một hệ thống không thực sự giới hạn trong một thư viện C. Mặc dù vậy, hầu hết, chủ yếu chỉ sử dụng một, đây cũng sẽ là trình biên dịch mặc định sử dụng. Và vì bạn đang tải xuống mã nguồn để biên dịch, đó là thứ bạn quan tâm.

Bắt đầu với một chương trình tầm thường:

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

biên dịch nó bằng trình biên dịch bạn sẽ sử dụng cho mã nguồn, sau đó sử dụng lddđể tìm ra thư viện C ở đâu:

$ 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)

Bây giờ bạn có đường dẫn đến thư viện C. Bạn có thể tra cứu điều này trong trình quản lý gói của bạn để tìm gói (ví dụ: dpkg -S /lib/x86_64-linux-gnu/libc.so.6hoặc rpm -q -f /lib/x86_64-linux-gnu/libc.so.6).

Ít nhất là trong trường hợp eglibc / glibc, bạn có thể chạy nó:

$ /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.

Cuối cùng, bạn có thể xem liệu bạn có thể nhận được manh mối từ hay không objdump -p /lib/x86_64-linux-gnu/libc.so.6, bằng cách xem trong phần định nghĩa phiên bản :

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 

Lưu ý cách biểu tượng GLIBC_2,18 có số phiên bản gần đây nhất trong số các biểu tượng được liệt kê và phiên bản thư viện thực sự là 2,18. Tuy nhiên, đó là eglibc (nó nhằm mục đích tương thích nhị phân với glibc 2.18, vì vậy nó sử dụng các phiên bản ký hiệu tương tự).

Bạn cũng có thể cố gắng sử dụng stringsđể tìm hiểu điều gì đó về nó. Bạn sẽ muốn chỉ định độ dài tối thiểu dài hơn ( -n) hoặc sử dụng grep để tìm kiếm thứ gì đó:

$ 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'

cả hai đều làm việc cho eglibc này.

GHI CHÚ: Tiện ích gói Debian dpkg-shlibdepssử dụng objdumptrong phần mềm, cùng với thông tin ký hiệu được lưu trữ trong các gói thư viện Debian để xác định các phiên bản phụ thuộc tối thiểu được yêu cầu bởi các gói Debian nhị phân tại thời điểm xây dựng. Về cơ bản, nó xem xét các ký hiệu được xuất ra bởi gói Debian nhị phân và sau đó tìm các phiên bản tối thiểu của các thư viện có chứa các ký hiệu đó.


9

Câu trả lời rõ ràng, mặc dù không phải là toàn diện nhất, là kiểm tra trình quản lý gói của bạn, vd

rpm -qi glibc
dpkg -l libc6

(Đáng buồn thay, glibc không có .pctệp pkconfig , vì vậy pkgconfig --modversion glibckhông phải là người chạy.) Xem thêm getconfđề xuất tuyệt vời của @ Gnouc .

Trường hợp đơn giản nhất, với gcc + glibc, và trường hợp tôi chủ yếu sử dụng đầu tiên là chỉ thực hiện libc.so, như được nêu trong một số câu trả lời khác ở đây. Không cần phải vượt qua bất kỳ đối số nào, nó xuất ra phiên bản của nó theo mặc định. Điều này hoạt động trở lại như glibc-2.1 (lỗi phân tách glibc-2.0, mặc dù cách đó trở lại sau đó bạn có thể kiểm tra tập lệnh (hiện đã nghỉ hưu) glibcbugđể xác nhận phiên bản). Phương pháp này cũng hoạt động với các phiên bản gần đây (> 0.9.15) của musl-libc (vừa mới ra mắt ngày hôm nay, 20 tháng 3). Nó không hoạt động với uClibc, nó segfaults.

Một cách đơn giản để nói chính xác những gì bạn gccsẽ làm là biên dịch:

#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;
}

(với glibc, <stdio.h>bao gồm <features.h>định nghĩa các macro GLIBC có liên quan, bạn cần <gnu/libc-version.h>cho các khai báo hàm.)

Điều này nắm bắt các trường hợp phức tạp hơn (nhiều libc và / hoặc nhiều trình biên dịch), giả sử bạn đang sử dụng đúng trình biên dịch (và cờ). (Tôi nghi ngờ rằng nó sẽ không phân biệt giữa eglibc và glibc thích hợp.)

Nếu bạn chắc chắn rằng bạn đang sử dụng glibc (hoặc eglibc) thì ldcũng sẽ xác nhận phiên bản (xin lỗi, điều này không chính xác).

Nếu __GNU_LIBRARY__không được xác định, bạn sẽ gặp lỗi, đó là thời gian cho kế hoạch B.

gcc -dumpmachinecó thể giúp đỡ, ví dụ như đối với uclibc, nó có -uclibchậu tố gcc -dumpspecs | grep dynamic-linker. Điều này cũng có thể ngụ ý ABI.

gcc -print-file-name=libc.sosẽ cho bạn biết trình biên dịch nào sẽ sử dụng cho " -lc", đây gần như chắc chắn là một tập lệnh liên kết trong cài đặt gcc của bạn, mà bạn có thể đọc nó dưới dạng văn bản thuần túy. Điều đó sẽ chỉ ra đường dẫn chính xác đến libc.so. Điều này cũng sẽ hoạt động nếu bạn truyền cờ như -m32hoặc -m64.

Trong trường hợp bạn đang sử dụng uclibc (như được sử dụng bởi OpenWRT và nhiều hơn nữa), nó định nghĩa __UCLIBC_MAJOR__, __UCLIBC_MINOR____UCLIBC_SUBLEVEL__cũng như __UCLIBC__trong <features.h>, vì vậy nó dễ dàng phát hiện sử dụng một biến thể nhỏ trên trên C đoạn mã. Vì lợi ích của tính tương thích, uClibc cũng có thể định nghĩa các macro GNU / GLIBC như được sử dụng ở trên, hiện tại nó giả vờ là glibc-2.2. Nó hiện không thực hiện các gnu_get_libc_X()chức năng, nhưng nó không thực hiện getconfmà cũng có thể gây nhầm lẫn (tôi nghi ngờ nó sẽ trả về một câu trả lời trống getconf GNU_LIBC_VERSION, xây dựng của tôi env đang hờn dỗi ngày nay vì vậy tôi không thể xác nhận.)

Trong trường hợp không thể xảy ra khi bạn sử dụng dietlibc , chạy diet -vsẽ hiển thị phiên bản.

(FWIW, trong nhiều năm với phần mềm sử dụng autoconf, tôi gặp nhiều vấn đề hơn với các yêu cầu gccg++yêu cầu không được kiểm tra so với các tính năng glibc đã kiểm tra.)


5

GNU libc (thứ mà hầu hết các bản phân phối Linux sử dụng ở dạng này hay dạng khác) đều có độ dài lớn để giữ khả năng tương thích ngược nghiêm ngặt. Vì vậy, bạn chỉ gặp rắc rối nếu bạn cố chạy nhị phân quá mới trên phiên bản cũ (hoặc phân phối "doanh nghiệp", chúng thường đóng băng các phiên bản, đặc biệt là các phiên bản nền tảng như thư viện C, sửa lỗi trong khi vẫn giữ khả năng tương thích nhị phân nghiêm ngặt) . Tôi tin rằng bạn có nhiều khả năng gặp phải vấn đề với các thư viện khác (C ++ có một vài thay đổi API / ABI trong bộ nhớ gần đây, một số thư viện khác không quan tâm đến khả năng tương thích ngược).

Đáng buồn thay, cách duy nhất để tìm hiểu chắc chắn là thử.


+1 Trên thực tế, họ có một biểu đồ liên quan đến khả năng tương thích ngược và tôi sẽ cho rằng lý do duy nhất đó không phải là tất cả 100% là do mã khai thác các phần mở rộng GNU bí truyền. Tuy nhiên, không có biểu đồ nào như vậy tôi biết về khả năng tương thích về phía trước , mà như bạn lưu ý là mối quan tâm thực sự hơn.
goldilocks

5

(Điều này về cơ bản giống như câu trả lời của goldilocks nhưng với một số giải thích thêm về những gì đang diễn ra dưới mui xe.)

Thư viện chia sẻ lõi cho GNU libc, libc.so.6(trên Linux; Hurd có SONAME khác), có thuộc tính bất thường (đối với các thư viện dùng chung) mà bạn có thể gọi nó dưới dạng thực thi. Nếu bạn làm như vậy, nó sẽ in ra thứ mà các tiện ích GNU thường in khi chạy với --version, như thế này:

$ /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/>.

Nhưng tất nhiên thư mục nơi libc.so.6cuộc sống không ở trong đó $PATH, vì vậy bạn phải biết nơi để tìm nó. Nó có thể là trong /lib, /lib64, /usr/lib, hoặc một cái gì đó thậm chí wackier (như trong trường hợp này). Thuận tiện, lddsẽ cho bạn biết:

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

Để làm việc đó, tất nhiên, bạn phải biết tên đường dẫn đầy đủ của một tệp thực thi nhị phân được liên kết động. Tệp shthực thi được đảm bảo có trong /bin(vì rất nhiều #!tập lệnh mong đợi nó) và bản thân nó không thể là #!tập lệnh. Nó có thể được liên kết tĩnh, nhưng tôi đã không gặp phải một hệ thống đã làm điều đó trong nhiều năm.

Tôi không biết bạn sẽ làm gì nếu bạn đang chạy với uClibc hoặc musl hoặc thứ gì đó kỳ lạ hơn.


2
Chà, bạn không cần phải biết đường dẫn đầy đủ đến / bin / sh hay bất cứ thứ gì. Bạn có thể luôn luôn $ ldd $(which sh) | grep libc. : D
Matt Nordhoff

5

Một cách khác để có được nó:

getconf GNU_LIBC_VERSION

Một cái tốt, cái này sẽ hoạt động đáng tin cậy kể từ glibc-2.3.3.
mr.spuratic 21/03 '
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.