web-dev-qa-db-fra.com

Quelle version de bibliothèque C mon système utilise-t-il?

Comment savoir avec certitude quelle bibliothèque Userland C mon système utilise? Les raisons possibles d'avoir besoin de ces informations comprennent:

  • Il y a un gigantesque paquet source que j'envisage de télécharger et qui, j'en suis sûr, fera les vérifications appropriées et répertorie une version de bibliothèque mininum, mais je préférerais me sauver d'un problème potentiel en vérifiant d'abord si cela fonctionnera.

  • Je suis préoccupé par compatibilité ABI avec certains binaires tiers que je veux essayer d'installer en dehors du système de gestion des packages du système.

  • J'ai un package source dont la documentation mentionne la nécessité d'une version minimale de la bibliothèque de mon système, mais le processus de génération n'effectue aucune vérification.

  • Je construis un compilateur croisé ciblant un système spécifique et je ne veux pas risquer compatibilité ascendante problèmes.

44
goldilocks

Les systèmes GNU/Linux utilisent généralement soit glibc (famille Fedora/Redhat, Arch) ou son cousin proche, eglibc (famille Debian/Ubuntu); étant donné qu'eglibc est à présent fusionné dans la glibc ( voir Création de la branche EGLIBC 2.19 sous "News" ), dans un avenir proche, ils seront tous à nouveau glibc.

La façon la plus simple de vérifier la version exacte est de demander à ldd, qui est fourni avec la bibliothèque C.

Sur Fedora 20:

> ldd --version
ldd (GNU libc) 2.18

C'est la glibc 2.18.

Sur Raspbian (port Debian 7 pour SoC Broadcom ARMv6):

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

C'est eglibc 2.13.

Si, pour une raison quelconque, vous avez mélangé et assorti certaines parties ou si vous n'êtes pas sûr de ldd, vous pouvez interroger la bibliothèque C directement.

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

Aucun de ceux-ci n'est exécutable mais ils fournissent un indice sur où en trouver un.

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

Cependant, ce n'est pas nécessairement si facile, car la bibliothèque C n'a pas à résider quelque part whereis peut la trouver.

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

Malheureusement, la page de manuel ne fournit pas de numéro de version. ldd est toujours utile, car tout exécutable fonctionnel et lié dynamiquement sur le système (par exemple, presque tout dans /usr/bin) sera lié à la bibliothèque 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 sur la troisième ligne.

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

Un système n'est en fait pas limité à une seule bibliothèque C. La plupart, cependant, n'utilisent principalement qu'un seul, qui sera également celui utilisé par le compilateur par défaut. Et puisque vous téléchargez le code source à compiler, c'est celui qui vous intéresse.

Commencez avec un programme trivial:

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

compilez-le en utilisant le compilateur que vous allez utiliser pour le code source, puis utilisez ldd pour savoir où se trouve la bibliothèque 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)

Vous avez maintenant le chemin vers la bibliothèque C. Vous pouvez rechercher cela dans votre gestionnaire de packages pour trouver le package (par exemple, dpkg -S /lib/x86_64-linux-gnu/libc.so.6 ou rpm -q -f /lib/x86_64-linux-gnu/libc.so.6).

Au moins dans le cas d'eglibc/glibc, vous pouvez l'exécuter:

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

Enfin, vous pouvez voir si vous pouvez obtenir des indices de objdump -p /lib/x86_64-linux-gnu/libc.so.6, en regardant dans la section définitions de version:

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 

Notez comment le symbole GLIBC_2.18 a le numéro de version le plus récent parmi les symboles répertoriés, et la version de la bibliothèque est en effet 2.18. C'est eglibc, cependant (il vise à être compatible binaire avec glibc 2.18, donc il utilise les mêmes versions de symboles).

Vous pouvez également essayer d'utiliser strings pour en savoir plus. Vous souhaiterez spécifier une longueur minimale plus longue (-n), ou utilisez grep pour rechercher quelque chose:

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

les deux fonctionnent pour cette eglibc.

REMARQUE: l'utilitaire de package Debian dpkg-shlibdeps utilise objdump sous le capot, ainsi que les informations de symboles stockées dans les paquets de la bibliothèque Debian pour déterminer les versions minimales des dépendances requises par les paquets binaires Debian au moment de la construction. Fondamentalement, il examine les symboles exportés par le paquet Debian binaire, puis trouve les versions minimales des bibliothèques qui contiennent ces symboles.

14
derobert

La réponse évidente, mais pas la plus complète, est de vérifier votre gestionnaire de paquets, par exemple

rpm -qi glibc
dpkg -l libc6

(Malheureusement, la glibc n'a pas de fichier pkconfig .pc, Donc pkgconfig --modversion glibc N'est pas un runner.) Voir aussi l'excellente suggestion de @ Gnouc getconf.

Le cas le plus simple, avec gcc + glibc, et celui que j'utilise principalement en premier est d'exécuter simplement libc.so, Comme indiqué dans certaines des autres réponses ici. Il n'est pas nécessaire de passer d'arguments, il affiche sa version par défaut. Cela fonctionne aussi loin que glibc-2.1 (glibc-2.0 seg-faults, bien que vous puissiez alors vérifier le script (maintenant retiré) glibcbug pour confirmer la version). Cette méthode fonctionne également avec les versions récentes (> 0.9.15) de musl-libc (qui vient de passer à 1.0 aujourd'hui, 20 mars). Cela ne fonctionne pas avec uClibc, il segfaults.

Une façon simple de dire exactement ce que votre gcc va faire est de compiler:

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

(avec glibc, <stdio.h> inclut <features.h> qui définit les macros GLIBC pertinentes, vous avez besoin de <gnu/libc-version.h> pour les déclarations de fonction.)

Cela intercepte des cas plus complexes (plusieurs libc et/ou plusieurs compilateurs), en supposant bien sûr que vous utilisez le bon compilateur (et drapeaux). (Je soupçonne que cela ne fera pas de distinction entre eglibc et glibc proprement dit.)

Si vous êtes certain que vous utilisez glibc (ou eglibc), ld confirmera également la version (désolé, ce n'est pas correct).

Si __GNU_LIBRARY__ N'est pas défini, vous obtiendrez des erreurs, alors il est temps pour le plan B.

gcc -dumpmachine Peut aider, par exemple pour uclibc, il a le suffixe -uclibc, tout comme gcc -dumpspecs | grep dynamic-linker. Cela peut également impliquer l'ABI.

gcc -print-file-name=libc.so Vous dira quel fichier le compilateur utilisera pour "-lc", C'est presque certainement un linker-script dans votre installation gcc, que vous pouvez le lire en texte brut. Cela montrera le chemin exact vers libc.so. Cela fonctionnera également si vous passez des drapeaux comme -m32 Ou -m64.

Dans le cas où vous utilisez clibc (tel qu'utilisé par OpenWRT et plus), il définit __UCLIBC_MAJOR__, __UCLIBC_MINOR__ Et __UCLIBC_SUBLEVEL__ Ainsi que __UCLIBC__ Dans <features.h>, Il est donc facilement détectable en utilisant une variante mineure de l'extrait de code C ci-dessus. Dans un souci de compatibilité, uClibc peut également définir les macros GNU/GLIBC telles qu'utilisées ci-dessus, il prétend actuellement être glibc-2.2. Il n'implémente pas actuellement les fonctions gnu_get_libc_X(), mais il implémente getconf qui peut également induire en erreur (je soupçonne il renvoie une réponse vide pour getconf GNU_LIBC_VERSION, ma build env boude aujourd'hui donc je ne peux pas confirmer.)

Dans le cas peu probable où vous utilisez dietlibc , l'exécution de diet -v Affichera la version.

(FWIW, sur plusieurs années avec des logiciels utilisant autoconf, j'ai eu plus de problèmes avec les exigences gcc et g++ Non vérifiées qu'avec les fonctionnalités glibc vérifiées.)

10
mr.spuratic

Une autre façon de l'obtenir:

getconf GNU_LIBC_VERSION
5
cuonglm

GNU libc (ce que la plupart des distributions Linux utilisent sous une forme ou une autre) va très loin pour garder une compatibilité descendante stricte. Vous ne devriez donc rencontrer des problèmes que si vous essayez d'exécuter un binaire trop nouveau sur une ancienne version (ou une distribution "entreprise", ils gèlent normalement les versions, en particulier celles de base comme la bibliothèque C, rétroportant les correctifs tout en conservant une compatibilité binaire rigure) . Je crois que vous êtes beaucoup plus susceptible de rencontrer des problèmes avec d'autres bibliothèques (C++ a eu quelques changements API/ABI dans la mémoire récente, certaines autres bibliothèques juste ne pas se soucient de la compatibilité descendante).

Malheureusement, la seule façon de le savoir est d’essayer.

5
vonbrand

(C'est essentiellement la même chose que la réponse de goldilocks mais avec plus d'explications sur ce qui se passe sous le capot.)

La bibliothèque partagée de base pour GNU libc, libc.so.6 (sous Linux; Hurd a un SONAME différent), a la propriété inhabituelle (pour les bibliothèques partagées) que vous pouvez l'invoquer en tant qu'exécutable. Si vous le faites, il affiche le genre de chose GNU s'impriment généralement lorsqu'ils sont exécutés avec --version, comme ça:

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

Mais bien sûr, le répertoire où libc.so.6 la vie n'est pas en $PATH, vous devez donc savoir où le chercher. Ce pourrait être dans /lib, /lib64, /usr/lib, ou quelque chose de plus farfelu (comme dans ce cas). Idéalement, ldd vous dira:

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

Pour que cela fonctionne, bien sûr, vous devez connaître le chemin d'accès complet d'un exécutable binaire lié dynamiquement. L'exécutable sh est garanti dans /bin (parce que tant de #! les scripts s'attendent à ce que ce soit le cas) et ne peut pas être lui-même un #! script. Il pourrait être lié statiquement, mais je n'ai pas rencontré de système qui le fasse depuis de nombreuses années.

Je ne sais pas ce que vous faites si vous utilisez uClibc ou musl ou quelque chose de plus exotique.

5
zwol