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

gol*_*cks 48 c version shared-library

如何确定我的系统使用的是哪个用户级 C 库?需要此信息的可能原因包括:

  • 我正在考虑下载一个巨大的源包,我确信它会进行适当的检查并列出一个最小库版本,但我宁愿先检查它是否可以工作,从而避免潜在的麻烦。

  • 我担心ABI与一些我想尝试在系统包管理系统之外安装的第三方二进制文件的兼容性

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

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

gol*_*cks 56

GNU/Linux 系统通常使用 glibc(Fedora/Redhat 系列,Arch)或其近亲 eglibc(Debian/Ubuntu 系列);由于 eglibc 现在被合并回 glibc(参见“新闻”下创建的 EGLIBC 2.19 分支),在不久的将来它们都将再次成为 glibc。

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

在 Fedora 20 上:

> ldd --version
ldd (GNU libc) 2.18
Run Code Online (Sandbox Code Playgroud)

那是 glibc 2.18。

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

> ldd --version
ldd (Debian EGLIBC 2.13-38+rpi2) 2.13
Run Code Online (Sandbox Code Playgroud)

那是 eglibc 2.13。

如果由于某种原因您混合和匹配了某些部分或不确定ldd,您可以直接查询 C 库。

> whereis libc.so
libc: /usr/lib64/libc.a /usr/lib64/libc.so /usr/share/man/man7/libc.7.gz
Run Code Online (Sandbox Code Playgroud)

这些都不是可执行的,但它们提供了有关在哪里可以找到的线索。

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

然而,这并不一定那么容易,因为 C 库并不一定要驻留在某处whereis才能找到它。

> whereis libc.so
libc: /usr/share/man/man7/libc.7.gz
Run Code Online (Sandbox Code Playgroud)

不幸的是,手册页没有提供版本号。 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)
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)


der*_*ert 15

一个系统实际上并不限于一个 C 库。但是,大多数主要只使用一种,这也将是默认编译器使用的一种。由于您要下载源代码进行编译,这就是您所关心的问题。

从一个简单的程序开始:

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

使用您将用于源代码的编译器编译它,然后使用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)
Run Code Online (Sandbox Code Playgroud)

您现在拥有了 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.
?
Run Code Online (Sandbox Code Playgroud)

最后,您可以objdump -p /lib/x86_64-linux-gnu/libc.so.6通过查看版本定义部分来查看是否可以从 中获得线索:

$ 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)
Run Code Online (Sandbox Code Playgroud)

请注意 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'
Run Code Online (Sandbox Code Playgroud)

两者都适用于这个 eglibc。

注意:Debian 软件包实用程序在幕后dpkg-shlibdeps使用objdump以及 Debian 库软件包中存储的符号信息来确定二进制 Debian 软件包在构建时所需的最低依赖版本。基本上,它查看二进制 Debian 包导出的符号,然后找到包含这些符号的库的最低版本。


mr.*_*tic 10

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

rpm -qi glibc
dpkg -l libc6
Run Code Online (Sandbox Code Playgroud)

(遗憾的是,glibc 没有 pkconfig.pc文件,所以pkgconfig --modversion glibc没有运行程序。)另请参阅 @Gnouc 的极好getconf建议。

最简单的情况是 gcc+glibc,我最常使用的就是 execute libc.so,如这里的其他一些答案中所述。不需要传递任何参数,它默认输出它的版本。这适用于 glibc-2.1(glibc-2.0 seg-faults,尽管那时您可以检查(现已停用)glibcbug脚本以确认版本)。此方法也适用于最近 (>0.9.15) 版本的musl-libc(今天,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;
}
Run Code Online (Sandbox Code Playgroud)

(使用 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,我的构建环境今天生闷气,所以我无法确认。)

万一您使用的是dietlibc,运行diet -v将显示版本。

(FWIW,在使用 autoconf 软件的几年里,我在未检查gccg++要求方面遇到的问题比检查 glibc 功能要多。)


von*_*and 5

GNU libc(大多数 Linux 发行版以一种或另一种形式使用的)竭尽全力保持严格的向后兼容性。因此,只有当您尝试在旧版本(或“企业”发行版,它们通常冻结版本,特别是像 C 库这样的基础版本,在保持严格的二进制兼容性的同时向后移植修复程序)上运行太新的二进制文件时,才会遇到麻烦. 我相信您更容易遇到其他库的问题(C++ 在最近的内存中有一些 API/ABI 更改,其他一些库只是关心向后兼容性)。

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


zwo*_*wol 5

(这与金发姑娘的回答基本相同,但对引擎盖下发生的事情有更多解释。)

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/>.
Run Code Online (Sandbox Code Playgroud)

但是当然所在的目录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)
Run Code Online (Sandbox Code Playgroud)

当然,要使其工作,您必须知道动态链接的二进制可执行文件的完整路径名。该sh可执行文件是保证在/bin(因为这么多的#!脚本,希望它是),而自身不能是一个#!脚本。它可以是静态链接的,但我已经很多年没有遇到过这样做的系统了。

如果您使用 uClibc 或 musl 或更奇特的东西运行,我不知道您会做什么。

  • 好吧,您不必*必须*知道 /bin/sh 或其他任何内容的完整路径。你总是可以`$ ldd $(which sh) | grep libc`。:D (2认同)

cuo*_*glm 5

另一种获取方式:

getconf GNU_LIBC_VERSION
Run Code Online (Sandbox Code Playgroud)