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

43

Comment savoir avec certitude quelle bibliothèque C utilisateur est utilisée par mon système? Les raisons possibles pour avoir besoin de ces informations incluent:

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

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

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

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

boucle d'or
la source
Pourquoi ne pas essayer et voir. Je ne sais pas si la version vous dit tout; qu'en est-il des patchs? Ou bien les distributions sont-elles prudentes lorsqu’on modifie l’ABI? Le problème n'est-il pas de savoir si les symboles exportés sont résolus ou quelque chose du genre?
Faheem Mitha
De bonnes réponses, mais personne ne dit comment le faire sur un Mac, là où il n'y en a pas ldd. Je ne sais pas si otool --versionpeut être considéré comme donnant les mêmes informations.
dubiousjim
@dubiousjim Quelqu'un pourrait; mais pas moi, car je ne suis pas un utilisateur de Mac. Ici, vous devrez peut-être poser des questions spécifiques à ce sujet - une partie du problème réside peut-être dans le fait que les gens n'utilisent généralement pas beaucoup C en clair sur OSX? Mais je suis sûr qu'il y aura un habitué qui sait. Vous pouvez également poster un lien vers ceci dans le chat et voir ce qui se passe, mais une nouvelle question plus spécifique serait probablement préférable.
goldilocks

Réponses:

50

Les systèmes GNU / Linux utilisent généralement soit glibc (famille Fedora / Redhat, Arch), soit son cousin proche, eglibc (famille Debian / Ubuntu); puisque eglibc est maintenant en train de fusionner de nouveau dans glibc ( voir EGLIBC 2.19 - Branchée sous "Actualités" ), dans un avenir proche, ils seront tous de nouveau glibc.

Le moyen le plus simple de vérifier la version exacte est de demander lddqui est livré avec la bibliothèque C.

Sur Fedora 20:

> ldd --version
ldd (GNU libc) 2.18

C'est glibc 2.18.

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

> 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 mis en correspondance certaines parties ou si vous n’êtes pas sûr de lddvotre choix, vous pouvez interroger directement la bibliothèque C.

> 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 l'endroit 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 forcément si facile, car la bibliothèque C n'a pas besoin de résider quelque part whereispour 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. lddreste pratique, car tout exécutable fonctionnel lié dynamiquement sur le système (par exemple, presque tout dedans /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.
boucle d'or
la source
Qu'est-ce qui rend un système GNU / Linux "normal"? Qu'en est-il des distributions utilisant musl ?
Elliott Frisch
1
@ElliottFrisch Il était destiné à appliquer à GNU / Linux, comme dans « GNU / Linux normal » (adjectif, nom), car il pourrait y avoir (sont, je suis sûr) les systèmes qui n'utilisent (e) glibc , mais faire utilisez le reste de la pile GNU (bash, binutils, etc.). Je considérerais ces systèmes "inhabituels" GNU / Linux. Mais j'ai supprimé le mot "normal" et l'a remplacé par "Les systèmes GNU / Linux utilisent généralement ...". Remarque: j'ai intentionnellement laissé la question ouverte sur les spécificités du système d'exploitation WRT (il n'y a pas de balise linux, GNU ou glibc). Si vous souhaitez ajouter une réponse concernant tout système approprié pour U & L, veuillez le faire.
goldilocks
1
Après l'avoir trouvée comme vous l'avez montré et après avoir interrogé la version, elle a également imprimé les extensions disponibles! (dans mon cas, stubs, crypt, libidn, threads natifs et bind) et renvoyés à ABI: ABI de libc: UNIQUE IFUNC.
Debian utilise le /lib/`uname -m`*chemin. Donc , de manière portable serait: find /lib/`uname -m`* /usr/lib* -executable -name "*libc.so*" | xargs --version. Merci pour la bonne explication.
Pevik
@pevik: Faux, sur le bras c'est /lib/arm-linux-gnueabihf/libc.so.6, et non /lib/armv7l/libc.so.6
Quandary
14

Un système n'est 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 à l'aide du compilateur que vous allez utiliser pour le code source, puis utilisez-le lddpour 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 de la bibliothèque C. Vous pouvez le rechercher dans votre gestionnaire de paquets pour trouver le paquet (par exemple, dpkg -S /lib/x86_64-linux-gnu/libc.so.6ou rpm -q -f /lib/x86_64-linux-gnu/libc.so.6).

Au moins dans le cas de eglibc / glibc, vous pouvez le lancer:

$ /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 objdump -p /lib/x86_64-linux-gnu/libc.so.6en consultant la section des 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 que le symbole GLIBC_2.18 a le numéro de version le plus récent parmi les symboles répertoriés et que la version de la bibliothèque est bien 2.18. C'est eglibc, cependant (il est compatible binaire avec glibc 2.18, il utilise donc les mêmes versions de symboles).

Vous pouvez également essayer d'utiliser stringspour trouver quelque chose à ce sujet. Vous voudrez spécifier une longueur minimale ( -n) plus longue ou utiliser 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 travaillent pour cet eglibc.

REMARQUE: L'utilitaire de paquet Debian dpkg-shlibdepsutilise objdumpsous le capot, ainsi que les informations de symbole 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 binaire Debian, puis recherche les versions minimales des bibliothèques contenant ces symboles.

derobert
la source
9

La réponse évidente, bien que pas la plus complète, consiste à vérifier votre gestionnaire de paquets, par exemple:

rpm -qi glibc
dpkg -l libc6

(Malheureusement, glibc n'a pas de .pcfichier pkconfig , il en pkgconfig --modversion glibcva de même pour les non-coureurs.) Voir aussi l'excellente getconfsuggestion de @Gnouc .

Le cas le plus simple, avec gcc + glibc, et celui que j’utilise le plus souvent en premier lieu, consiste simplement à exécuter libc.so, comme indiqué dans certaines des autres réponses données ici. Il n'est pas nécessaire de passer des arguments, il affiche sa version par défaut. Cela fonctionne aussi loin que glibc-2.1 (les défauts de segmentation de glibc-2.0, bien que vous ayez déjà pu vérifier le glibcbugscript (maintenant abandonné) 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, le 20 mars). Cela ne fonctionne pas avec uClibc, il segfaults.

Un moyen simple de dire exactement ce que vous gccallez 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>comprend <features.h>qui définit les macros GLIBC pertinentes, vous avez besoin <gnu/libc-version.h>pour les déclarations de fonction.)

Cela intercepte des cas plus complexes (plusieurs bibliothèques et / ou plusieurs compilateurs), en supposant que vous utilisiez le bon compilateur (et les bons indicateurs) bien sûr. (Je suppose que cela ne fera pas la distinction entre eglibc et glibc proprement dit.)

Si vous êtes certain d’utiliser glibc (ou eglibc), ldla version sera également confirmée (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 -dumpmachinepeut aider, par exemple pour uclibc, il a un -uclibcsuffixe, comme vous le pouvez gcc -dumpspecs | grep dynamic-linker. Cela peut aussi impliquer l’ABI.

gcc -print-file-name=libc.sovous dira quel fichier le compilateur utilisera pour " -lc", il s'agit certainement d'un script d'éditeur de liens au sein de votre installation gcc, que vous pouvez lire en texte brut. Cela montrera le chemin exact pour libc.so. Cela fonctionnera également si vous passez des drapeaux tels que -m32ou -m64.

Dans le cas où vous utilisez uclibc (tel qu'il est utilisé par OpenWRT et plus), il définit __UCLIBC_MAJOR__, __UCLIBC_MINOR__et __UCLIBC_SUBLEVEL__ainsi que __UCLIBC__dans <features.h>, il est donc facile à détecter en utilisant une variation mineure sur l'extrait de code ci - dessus C. 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 ne met pas en œuvre actuellement les gnu_get_libc_X()fonctions, mais il ne mettre en œuvre ce getconfqui peut aussi induire en erreur (je soupçonne qu'il renvoie une réponse vide pour getconf GNU_LIBC_VERSIONma construction env boude aujourd'hui , donc je ne peux pas confirmer.)

Dans le cas peu probable où vous utiliseriez dietlibc , l'exécution diet -vaffichera la version.

(FWIW, depuis plusieurs années avec le logiciel en utilisant autoconf j'ai eu plus de problèmes avec décochée-pour gccet les g++exigences qu'avec le check-pour les fonctions de la glibc.)

mr.spuratic
la source
5

GNU libc (ce que la plupart des distributions Linux utilisent sous une forme ou une autre) fait tout son possible pour maintenir une compatibilité ascendante stricte. Vous ne devriez donc rencontrer de problèmes que si vous essayez de lancer 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 considérable) . Je pense que vous êtes beaucoup plus susceptible de rencontrer des problèmes avec d'autres bibliothèques (C ++ avait quelques modifications d'API / ABI dans la mémoire récente, d'autres bibliothèques ne se soucient tout simplement pas de la compatibilité avec les versions antérieures).

Malheureusement, le seul moyen de le savoir est d'essayer.

vonbrand
la source
+1 En fait, ils ont un tableau concernant la compatibilité ascendante et je suppose que la seule raison pour laquelle ce n'est pas tout à 100% est à cause du code qui exploite les extensions GNU ésotériques. Cependant, à ma connaissance, il n’existe pas de tableau de ce type concernant la compatibilité ascendante , ce qui, comme vous le constatez, est la véritable préoccupation.
goldilocks
5

(Ceci est essentiellement la même chose que la réponse de goldilocks mais avec quelques explications supplémentaires sur ce qui se passe sous le capot.)

La bibliothèque principale partagée pour GNU libc libc.so.6(sous Linux; Hurd a un nom différent de SONAME) a ​​la propriété inhabituelle (pour les bibliothèques partagées) que vous pouvez appeler en tant qu'exécutable. Si vous le faites, il affiche le type de choses que les utilitaires GNU impriment généralement lorsqu’ils sont exécutés --version, comme ceci:

$ /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.6vit n'est pas $PATH, vous devez donc savoir où le chercher. Il pourrait être /lib, /lib64, /usr/libou quelque chose d' encore farfelue (comme dans ce cas). Commodément, lddvous dira:

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

Pour que cela fonctionne, vous devez bien sûr connaître le chemin complet d'un exécutable binaire lié dynamiquement. L’ shexécutable est garanti /bin(car de nombreux #!scripts l’attendent) et ne peut pas être lui-même un #!script. Cela 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.

zwol
la source
2
Eh bien, vous n’avez pas besoin de connaître le chemin complet vers / bin / sh ou quoi que ce soit. Tu peux toujours $ ldd $(which sh) | grep libc. : D
Matt Nordhoff
5

Une autre façon de l'obtenir:

getconf GNU_LIBC_VERSION
cuonglm
la source
Bien gentil, cela devrait fonctionner de manière fiable depuis la glibc-2.3.3.
mr.spuratic