Lorsque je compile quelque chose sur mon PC Ubuntu Lucid 10.04, il est lié à la glibc. Lucid utilise la version 2.11 de la glibc. Lorsque j'exécute ce binaire sur un autre PC avec une ancienne glibc, la commande échoue en disant qu'il n'y a pas de glibc 2.11 ...
Autant que je sache, la glibc utilise la gestion des versions de symboles. Puis-je forcer gcc à se lier à une version de symbole spécifique?
Dans mon utilisation concrète, j'essaye de compiler une chaîne d'outils croisée gcc pour ARM.
Réponses:
Vous avez raison de dire que la glibc utilise la gestion des versions des symboles. Si vous êtes curieux, l'implémentation de la gestion des versions des symboles introduite dans la glibc 2.1 est décrite ici et est une extension du schéma de gestion des versions des symboles de Sun décrit ici .
Une option consiste à lier statiquement votre binaire. C'est probablement l'option la plus simple.
Vous pouvez également construire votre binaire dans un environnement de construction chroot, ou en utilisant un compilateur croisé glibc- new => glibc- old .
Selon l' article de blog http://www.trevorpounds.com Linking to Older Versioned Symbols (glibc) , il est possible de forcer n'importe quel symbole à être lié à un ancien tant qu'il est valide en utilisant le même
.symver
pseudo -op qui est utilisé pour définir les symboles versionnés en premier lieu. L'exemple suivant est extrait du billet de blog .L'exemple suivant utilise le chemin réel de la glibc, mais s'assure qu'il est lié à une ancienne version 2.2.5.
la source
libc.a
continue d'exister, la glibc le supporte dans certains cas, bien que ce ne soit pas recommandé (Drepper) . Vous aurez des problèmes avec les programmes non triviaux, en particulier tout ce qui utilise NSS (solution de contournement dans la FAQ ).Lien avec -static . Lorsque vous créez un lien avec -static, l'éditeur de liens incorpore la bibliothèque dans l'exécutable, donc l'exécutable sera plus gros, mais il peut être exécuté sur un système avec une ancienne version de la glibc car le programme utilisera sa propre bibliothèque au lieu de celle du système .
la source
Configuration 1: compilez votre propre glibc sans GCC dédié et utilisez-la
Puisqu'il semble impossible de faire uniquement avec des hacks de version de symboles, allons un peu plus loin et compilons la glibc nous-mêmes.
Cette configuration peut fonctionner et est rapide car elle ne recompile pas l'ensemble de la chaîne d'outils GCC, juste la glibc.
Mais il n'est pas fiable car il utilise des objets d' exécution hôte C tels que
crt1.o
,crti.o
etcrtn.o
fourni par la glibc. Ceci est mentionné à: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Ces objets font une configuration précoce sur laquelle la glibc s'appuie, donc je ne serais pas surpris si les choses se bloquaient de manière merveilleuse et des manières incroyablement subtiles.Pour une configuration plus fiable, voir Configuration 2 ci-dessous.
Construisez la glibc et installez localement:
Configuration 1: vérifier la construction
test_glibc.c
Compilez et exécutez avec
test_glibc.sh
:Le programme produit les résultats attendus:
Commande adaptée de https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location mais l'a
--sysroot
fait échouer avec:alors je l'ai enlevé.
ldd
La sortie confirme que lesldd
bibliothèques et que nous venons de créer sont en fait utilisées comme prévu:La
gcc
sortie de débogage de compilation montre que mes objets d'exécution hôte ont été utilisés, ce qui est mauvais comme mentionné précédemment, mais je ne sais pas comment contourner cela, par exemple, il contient:Configuration 1: modifier la glibc
Modifions maintenant la glibc avec:
Ensuite, recompilez et réinstallez la glibc, puis recompilez et réexécutez notre programme:
et nous voyons
hacked
imprimé quelques fois comme prévu.Cela confirme en outre que nous avons effectivement utilisé la glibc que nous avons compilée et non l'hôte.
Testé sur Ubuntu 18.04.
Configuration 2: configuration vierge du crosstool-NG
Ceci est une alternative à la configuration 1, et il est le plus correct configuration que j'ai accompli jusqu'à présent: tout est correct pour autant que je peux observer, y compris l'exécution de C des objets tels que
crt1.o
,crti.o
etcrtn.o
.Dans cette configuration, nous compilerons une chaîne d'outils GCC dédiée complète qui utilise la glibc que nous voulons.
Le seul inconvénient de cette méthode est que la construction prendra plus de temps. Mais je ne risquerais pas une configuration de production avec rien de moins.
crosstool-NG est un ensemble de scripts qui télécharge et compile tout à partir de la source pour nous, y compris GCC, glibc et binutils.
Oui, le système de construction de GCC est si mauvais que nous avons besoin d'un projet séparé pour cela.
Cette configuration n'est tout simplement pas parfaite car crosstool-NG ne prend pas en charge la construction des exécutables sans
-Wl
drapeaux supplémentaires , ce qui semble étrange depuis que nous avons construit GCC lui-même. Mais tout semble fonctionner, donc ce n'est qu'un inconvénient.Obtenez crosstool-NG et configurez-le:
La seule option obligatoire que je peux voir, c'est de faire correspondre la version de votre noyau hôte pour utiliser les en-têtes de noyau corrects. Trouvez la version de votre noyau hôte avec:
ce qui me montre:
donc dans
menuconfig
je fais:Operating System
Version of linux
donc je sélectionne:
qui est la première version égale ou antérieure. Il doit être plus ancien car le noyau est rétrocompatible.
Vous pouvez maintenant construire avec:
et attendez maintenant environ trente minutes à deux heures pour la compilation.
Configuration 2: configurations optionnelles
Le
.config
que nous avons généré avec./ct-ng x86_64-unknown-linux-gnu
a:Pour changer cela,
menuconfig
faites:C-library
Version of glibc
enregistrez le
.config
, et poursuivez la construction.Ou, si vous souhaitez utiliser votre propre source glibc, par exemple pour utiliser glibc à partir du dernier git, procédez comme suit :
Paths and misc options
Try features marked as EXPERIMENTAL
: défini sur trueC-library
Source of glibc
Custom location
: dis ouiCustom location
Custom source location
: pointez sur un répertoire contenant votre source glibcoù la glibc a été clonée comme:
Configuration 2: testez-le
Une fois que vous avez construit la chaîne d'outils que vous souhaitez, testez-la avec:
Tout semble fonctionner comme dans la configuration 1, sauf que maintenant les objets d'exécution corrects ont été utilisés:
Configuration 2: échec de la tentative de recompilation efficace de la glibc
Cela ne semble pas possible avec le crosstool-NG, comme expliqué ci-dessous.
Si vous venez de reconstruire;
alors vos modifications apportées à l'emplacement de la source glibc personnalisée sont prises en compte, mais il construit tout à partir de zéro, le rendant inutilisable pour le développement itératif.
Si nous faisons:
cela donne un bon aperçu des étapes de construction:
par conséquent, nous voyons qu'il y a des étapes de la glibc entrelacées avec plusieurs étapes GCC, notamment
libc_start_files
vient avantcc_core_pass_2
, ce qui est probablement l'étape la plus coûteuse aveccc_core_pass_1
.Afin de ne construire qu'une seule étape, vous devez d'abord définir l'
.config
option "Enregistrer les étapes intermédiaires" dans l' option pour la construction initiale:Paths and misc options
Debug crosstool-NG
Save intermediate steps
et ensuite vous pouvez essayer:
mais malheureusement, le
+
requis comme mentionné à: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536et rend fondamentalement encore la reconstruction trop lente pour être faisable pour le développement, et je ne vois pas comment surmonter cela sans patcher crosstool-NG.
De plus, à partir de l'
libc
étape ne semblait pas recopier la sourceCustom source location
, ce qui rendait cette méthode inutilisable.Bonus: stdlibc ++
Un bonus si vous êtes également intéressé par la bibliothèque standard C ++: Comment éditer et reconstruire la source de la bibliothèque standard C ++ libstdc ++ de GCC?
la source
musl-libc
est une autre option en ce qui concerne le runtime C.À mon avis, la solution la plus paresseuse (surtout si vous ne comptez pas sur les dernières fonctionnalités C / C ++ de pointe ou les dernières fonctionnalités du compilateur) n'a pas encore été mentionnée, alors la voici:
Construisez simplement sur le système avec le plus ancien GLIBC que vous souhaitez toujours prendre en charge.
C'est en fait assez facile à faire de nos jours avec des technologies comme chroot, ou KVM / Virtualbox, ou docker, même si vous ne voulez pas vraiment utiliser une telle vieille distribution directement sur n'importe quel PC. En détail, pour créer un binaire portable maximum de votre logiciel, je recommande de suivre ces étapes:
Choisissez simplement votre poison de sandbox / virtualisation / ... peu importe, et utilisez-le pour vous procurer un Ubuntu LTS virtuel plus ancien et compilez avec le gcc / g ++ qu'il contient par défaut. Cela limite automatiquement votre GLIBC à celui disponible dans cet environnement.
Évitez de dépendre des bibliothèques externes en dehors des bibliothèques fondamentales: comme, vous devriez relier dynamiquement des éléments système au niveau du sol comme la glibc, la libGL, la libxcb / X11 / wayland Things, libasound / libpulseaudio, éventuellement GTK + si vous l'utilisez, mais sinon de préférence, reliez statiquement externe libs / envoyez-les si vous le pouvez. Surtout les bibliothèques autonomes comme les chargeurs d'images, les décodeurs multimédias, etc. peuvent causer moins de casse sur d'autres distributions (une casse peut être causée par exemple si elles ne sont présentes que quelque part dans une version majeure différente) si vous les expédiez de manière statique.
Avec cette approche, vous obtenez un binaire compatible avec l'ancien GLIBC sans aucune modification manuelle des symboles, sans faire un binaire entièrement statique (qui peut casser pour des programmes plus complexes car la glibc déteste cela, et qui peut causer des problèmes de licence pour vous), et sans réglage n'importe quelle chaîne d'outils personnalisée, n'importe quelle copie de glibc personnalisée, ou autre.
la source