我的系统使用什么C库版本?


43

如何确定系统使用的userland C库?需要此信息的可能原因包括:

  • 我正在考虑下载一个巨大的源程序包,我相信它将进行适当的检查并列出一个最小的库版本,但是我宁愿先检查一下是否可以工作,以免自己陷入麻烦。

  • 我担心我要尝试在系统的程序包管理系统外部安装的某些第三方二进制文件的ABI兼容性

  • 我有一个源软件包,其文档中提到需要最低版本的系统库,但是构建过程不会执行任何检查。

  • 我正在构建针对特定系统的交叉编译器,并且不想冒前向兼容性问题的风险。


为什么不试试看。我不知道版本是否能告诉您一切;那补丁呢?还是发行人在更改ABI时是否谨慎?导出的符号是否已解析或类似问题不是问题吗?
Faheem Mitha 2014年

好的答案,但是没有人解决在没有的Mac上如何做到这一点ldd。我不确定是否otool --version可以提供相同的信息。
dubiousjim 2015年

@dubiousjim有人可以;只是不是我,因为我不是Mac用户。在这附近,您可能需要特别询问-部分问题也许是人们通常在OSX上不使用纯C?但是我敢肯定会有一个常识的人。您也可以在聊天中发布与此相关的链接,看看会发生什么,但是可能有一个新的,更具体的问题会更好。
goldilocks 2015年

Answers:


50

GNU / Linux系统通常使用glibc(Fedora / Redhat家族,Arch)或它的近亲,例如liblibc(Debian / Ubuntu家族)。由于eglibc现在已被合并回glibc(请参阅“新闻”下创建的EGLIBC 2.19分支),因此在不久的将来它们将再次全部变为glibc。

检查确切版本的最简单方法是ask ldd,它随C库一起提供。

在Fedora 20上:

> ldd --version
ldd (GNU libc) 2.18

那就是glibc 2.18。

在Raspbian上(用于ARMv6 Broadcom SoC的Debian 7端口):

> 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

不幸的是,手册页没有提供版本号。 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 2014年

1
@ElliottFrisch打算将其应用于GNU / Linux,如“普通GNU / Linux”(形容词,名词)一样,因为可能存在(我确定)使用(e)glibc但确实使用使用其余的GNU堆栈(bash,binutils等)。我会考虑那些“异常”的GNU / Linux系统。但是我删除了“常规”并将其更改为“ 通常使用...的GNU / Linux系统”。注意:我故意将问题保留为开放的WRT OS特定问题(没有linux或GNU或glibc标签),因此,如果要添加有关适用于U&L的任何系统的答案,请执行。
goldilocks 2014年

1
在找到您显示的内容并查询了版本后,它还会打印可用的扩展名!(在我的情况下为存根,crypt,libidn,本机线程和绑定),并引用为ABI:libc ABI:UNIQUE IFUNC。

Debian使用/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
困惑

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.6rpm -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软件包所需的依赖的最低版本一起。基本上,它查看二进制Debian软件包导出的符号,然后找到包含这些符号的库的最低版本。


9

显而易见的答案(虽然不是最全面的)是检查软件包管理器,例如

rpm -qi glibc
dpkg -l libc6

(遗憾的是,glibc没有pkconfig .pc文件,因此pkgconfig --modversion glibc没有运行者。)另请参见@Gnouc的出色getconf建议。

最简单的情况是使用gcc + glibc,而我最常使用的情况是执行libc.so,如此处其他一些答案所述。无需传递任何参数,默认情况下会输出其版本。这可以追溯到glibc-2.1(glibc-2.0 seg-faults,尽管回溯到那时,您可以检查(现已退休)glibcbug脚本以确认版本)。此方法还可以与musl-libc的最新版本(> 0.9.15)配合使用(3月20日今天才发布1.0)。它不能与uClibc一起使用,它会出现段错误。

准确说明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和/或多个编译器)。(我怀疑它虽然不能正确区分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的(13759的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的软件已经使用了几年,与未检查的glibc功能相比,我对未检查gccg++要求的问题更多。)


5

GNU libc(大多数Linux发行版以一种形式或另一种形式使用)竭尽全力保持严格的向后兼容性。因此,仅当您尝试在旧版本(或“企业”发行版)上运行太新的二进制文件时,您才应该遇到麻烦。 。我相信您更容易遇到其他库的问题(C ++在最近的内存中对API / ABI进行了一些更改,其他一些库只是关心向后兼容性)。

可悲的是,确定的唯一方法就是尝试。


+1实际上,他们有一个关于向后兼容性的图表,我认为不是100%的唯一原因是因为利用了深奥的GNU扩展的代码。但是,我不知道关于前向兼容性的图表,正如您所注意到的,这是更实际的问题。
goldilocks 2014年

5

(这与goldilocks的回答基本相同,但对幕后情况进行了更多解释。)

GNU libc的核心共享库libc.so.6(在Linux上; Hurd具有不同的SONAME)具有非同寻常的属性(对于共享库),您可以将其作为可执行文件调用。如果这样做,它将打印出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,或一些更怪的(在这种情况下)。方便地,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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.