¿Qué versión de la biblioteca C usa mi sistema?

43

¿Cómo puedo saber con seguridad qué biblioteca de userland C utiliza mi sistema? Las posibles razones para necesitar esta información incluyen:

  • Hay un paquete fuente gigantesco que estoy considerando descargar, que estoy seguro hará las comprobaciones adecuadas y enumerará una versión de biblioteca mínima, pero prefiero ahorrarme una molestia potencial comprobando primero si funcionará.

  • Me preocupa la compatibilidad de ABI con algunos binarios de terceros que quiero probar e instalar fuera del sistema de administración de paquetes del sistema.

  • Tengo un paquete fuente cuya documentación menciona la necesidad de una versión mínima de la biblioteca de mi sistema, pero el proceso de compilación no realiza ninguna comprobación.

  • Estoy creando un compilador cruzado dirigido a un sistema específico y no quiero arriesgarme a problemas de compatibilidad .

encerrada dorada
fuente
¿Por qué no probarlo y ver? No sé si la versión te dice todo; ¿Qué pasa con los parches? ¿O las distribuciones tienen cuidado de alterar el ABI? ¿No es el problema si los símbolos exportados están resueltos o algo así?
Faheem Mitha
Buenas respuestas, pero nadie aborda cómo hacer esto en una Mac, donde no hay ldd. No estoy seguro de si otool --versionse puede considerar que proporciona la misma información.
dubiousjim
@dubiousjim Alguien podría; simplemente no yo, porque no soy un usuario de Mac. Por aquí, es posible que deba preguntar específicamente sobre eso: ¿parte del problema es que la gente generalmente no usa mucho C simple en OSX? Pero estoy seguro de que habrá un habitual que lo sabe. También puede publicar un enlace a esto en el chat y ver qué sucede, pero probablemente sería mejor una nueva pregunta más específica.
Ricitos

Respuestas:

50

Los sistemas GNU / Linux generalmente usan glibc (familia Fedora / Redhat, Arch) o su primo cercano, eglibc (familia Debian / Ubuntu); dado que eglibc ahora se está fusionando de nuevo en glibc ( ver EGLIBC 2.19 Rama creada en "Noticias" ), en un futuro cercano todos volverán a ser glibc.

La forma más fácil de verificar la versión exacta es preguntar ldd, que se envía con la biblioteca C.

En Fedora 20:

> ldd --version
ldd (GNU libc) 2.18

Eso es glibc 2.18.

En Raspbian (puerto Debian 7 para ARMv6 Broadcom SoC):

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

Eso es eglibc 2.13.

Si por alguna razón ha mezclado y emparejado algunas partes o no está seguro ldd, puede consultar la biblioteca C directamente.

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

Ninguno de ellos es ejecutable, pero proporcionan una pista sobre dónde encontrar uno.

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

Sin embargo, no es necesariamente tan fácil, porque la biblioteca C no tiene que residir en algún lugar donde whereispueda encontrarlo.

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

Lamentablemente, la página del manual no proporciona un número de versión. lddsigue siendo útil, ya que cualquier ejecutable funcional y vinculado dinámicamente en el sistema (p. ej., casi todo lo que hay en /usr/bin) se vinculará a la biblioteca 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 Está en la tercera línea.

> /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.
encerrada dorada
fuente
¿Qué hace que un sistema GNU / Linux sea "normal"? ¿Qué pasa con las distribuciones usando musl ?
Elliott Frisch
1
@ElliottFrisch Estaba destinado a aplicarse a GNU / Linux, como en "GNU / Linux normal" (adjetivo, sustantivo), ya que podría haber (hay, estoy seguro) sistemas que no usan (e) glibc pero use el resto de la pila de GNU (bash, binutils, etc.). Consideraría esos sistemas GNU / Linux "inusuales". Pero eliminé lo "normal" y lo cambié a "Los sistemas GNU / Linux generalmente usan ...". Nota: intencionalmente dejé la pregunta abierta sobre los detalles del sistema operativo WRT (no hay Linux, GNU o etiqueta glibc), así que si desea agregar una respuesta con respecto a cualquier sistema apropiado para U&L, hágalo.
Ricitos
1
Después de que lo encontré como lo mostraste y pregunté la versión, ¡también imprimió las extensiones disponibles! (en mi caso, stubs, crypt, libidn, hilos nativos y bind) y se refirió a ABI: libc ABIs: UNIQUE IFUNC.
Debian usa la /lib/`uname -m`*ruta. Así manera portátil sería: find /lib/`uname -m`* /usr/lib* -executable -name "*libc.so*" | xargs --version. Gracias por una buena explicación.
pevik
@pevik: Mal, en armarlo de /lib/arm-linux-gnueabihf/libc.so.6, y no /lib/armv7l/libc.so.6
Dilema
14

Un sistema no está realmente limitado a una biblioteca C. Sin embargo, la mayoría usa principalmente uno, que también será el que usa el compilador predeterminado. Y como está descargando el código fuente para compilar, ese es el que le preocupa.

Comience con un programa trivial:

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

compílelo usando el compilador que usará para el código fuente, luego use lddpara averiguar dónde está la biblioteca 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)

Ahora tiene el camino a la biblioteca C. Puede buscar esto en su administrador de paquetes para encontrar el paquete (por ejemplo, dpkg -S /lib/x86_64-linux-gnu/libc.so.6o rpm -q -f /lib/x86_64-linux-gnu/libc.so.6).

Al menos en el caso de eglibc / glibc, puede ejecutarlo:

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

Finalmente, puede ver si puede obtener pistas objdump -p /lib/x86_64-linux-gnu/libc.so.6, mirando en la sección de definiciones de versió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 

Observe cómo el símbolo GLIBC_2.18 tiene el número de versión más reciente entre los símbolos enumerados, y la versión de la biblioteca es de hecho 2.18. Sin embargo, es eglibc (tiene como objetivo ser compatible con binarios con glibc 2.18, por lo que utiliza las mismas versiones de símbolos).

También podría intentar usar stringspara descubrir algo al respecto. Deberá especificar una longitud mínima más larga ( -n), o usar grep para buscar algo:

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

ambos trabajan para este eglibc.

NOTA: La utilidad del paquete Debian se dpkg-shlibdepsutiliza objdumpdebajo del capó, junto con la información de símbolos almacenados en los paquetes de la biblioteca Debian para determinar las versiones mínimas de dependencias requeridas por los paquetes binarios Debian en el momento de la compilación. Básicamente, analiza los símbolos exportados por el paquete binario de Debian y luego encuentra las versiones mínimas de las bibliotecas que contienen esos símbolos.

derobert
fuente
9

La respuesta obvia, aunque no es la más completa, es verificar su administrador de paquetes, por ej.

rpm -qi glibc
dpkg -l libc6

(Lamentablemente, glibc no tiene un .pcarchivo pkconfig , por pkgconfig --modversion glibclo que no es un corredor). Consulte también la excelente getconfsugerencia de @Gnouc .

El caso más simple, con gcc + glibc, y el que mayormente uso primero es simplemente ejecutar libc.so, como se describe en algunas de las otras respuestas aquí. No es necesario pasar ningún argumento, genera su versión por defecto. Esto funciona hasta glibc-2.1 (glibc-2.0 seg-faults, aunque en ese entonces podría verificar el glibcbugscript (ahora retirado) para confirmar la versión). Este método también funciona con versiones recientes (> 0.9.15) de musl-libc (que acaba de ser 1.0 hoy, 20 de marzo). No funciona con uClibc, se daña por defecto.

Una manera simple de saber exactamente qué gccva a hacer es compilar:

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

(con glibc, que <stdio.h>incluye <features.h>las macros GLIBC relevantes que necesita <gnu/libc-version.h>para las declaraciones de funciones).

Esto detecta casos más complejos (múltiples libc y / o múltiples compiladores), suponiendo que esté utilizando el compilador (y las banderas) correctos, por supuesto. (Sin embargo, sospecho que no distinguirá entre eglibc y glibc propiamente dicho).

Si está seguro de que está usando glibc (o eglibc) ld, también confirmará la versión (lo siento, esto no es correcto).

Si __GNU_LIBRARY__no está definido, obtendrá errores, entonces es hora del plan B.

gcc -dumpmachinepuede ayudar, por ejemplo, para uclibc tiene un -uclibcsufijo, como puede gcc -dumpspecs | grep dynamic-linker. Esto también puede implicar el ABI.

gcc -print-file-name=libc.sole dirá qué archivo utilizará el compilador para " -lc", es casi seguro que es un script vinculador dentro de su instalación de gcc, que puede leer como texto sin formato. Eso mostrará la ruta exacta a libc.so. Esto también funcionará si está pasando banderas como -m32o -m64.

En el caso de que esté usando uclibc (como lo usa OpenWRT y más), define __UCLIBC_MAJOR__, __UCLIBC_MINOR__y __UCLIBC_SUBLEVEL__también __UCLIBC__en <features.h>, por lo que se detecta fácilmente usando una variación menor en el fragmento de código C anterior. En aras de la compatibilidad, uClibc también puede definir las macros GNU / GLIBC como se usa anteriormente, actualmente pretende ser glibc-2.2. Actualmente no implementa las gnu_get_libc_X()funciones, pero implementa lo getconfque también puede inducir a error (sospecho que devuelve una respuesta vacía para getconf GNU_LIBC_VERSION, mi entorno de compilación está de mal humor hoy, así que no puedo confirmar).

En el improbable caso de que esté usando dietlibc , la ejecución diet -vmostrará la versión.

(FWIW, durante varios años con el software que usa autoconf, he tenido más problemas con las funciones gccy g++requisitos no verificados que con las funciones glibc verificadas).

Sr. púrpura
fuente
5

GNU libc (lo que la mayoría de las distribuciones de Linux usan de una forma u otra) hace todo lo posible para mantener una estricta compatibilidad con versiones anteriores. Por lo tanto, debe tener problemas solo si intenta ejecutar un binario demasiado nuevo en una versión anterior (o una distribución "empresarial", normalmente congelan las versiones, particularmente las básicas como la biblioteca C, las correcciones de backport manteniendo la rigurosa compatibilidad binaria) . Creo que es mucho más probable que tenga problemas con otras bibliotecas (C ++ tuvo algunos cambios API / ABI en la memoria reciente, algunas otras bibliotecas simplemente no se preocupan por la compatibilidad con versiones anteriores).

Lamentablemente, la única forma de averiguarlo con certeza es intentarlo.

vonbrand
fuente
De hecho, tienen un gráfico con respecto a la compatibilidad con versiones anteriores y supongo que la única razón por la que no todo es 100% es por el código que explota las extensiones esotéricas de GNU. Sin embargo, no hay tal carta yo sepa cuanto a la compatibilidad hacia adelante , que como se nota más la preocupación real.
Ricitos
5

(Esto es esencialmente lo mismo que la respuesta de Ricitos de Oro pero con algo más de explicación de lo que sucede debajo del capó).

La biblioteca compartida principal para GNU libc, libc.so.6(en Linux; Hurd tiene un SONAME diferente), tiene la propiedad inusual (para bibliotecas compartidas) de que puede invocarla como un ejecutable. Si lo hace, imprime el tipo de cosas que las utilidades de GNU generalmente imprimen cuando se ejecutan --version, de esta manera:

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

Pero, por supuesto, el directorio donde libc.so.6vive no está $PATH, así que debes saber dónde buscarlo. Podría ser en /lib, /lib64, /usr/lib, o algo aún más loca (como en este caso). Convenientemente, lddte diré:

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

Para que eso funcione, por supuesto, debe conocer el nombre de ruta completo de un ejecutable binario vinculado dinámicamente. Se shgarantiza que el ejecutable esté en /bin(porque muchos #!scripts esperan que lo esté), y no puede ser un #!script en sí mismo . Se podría estar vinculado estáticamente, pero no he encontrado un sistema que hizo que en muchos años.

No sé qué haces si estás corriendo con uClibc o musl o algo más exótico.

zwol
fuente
2
Bueno, no tienes que saber la ruta completa a / bin / sh o lo que sea. Siempre puedes $ ldd $(which sh) | grep libc. : D
Matt Nordhoff
5

Otra forma de obtenerlo:

getconf GNU_LIBC_VERSION
Cuonglm
fuente
Agradable, esto debería funcionar de manera confiable desde glibc-2.3.3.
Sr.Spuratic