8.30.1. Installation de GCC
Si vous construisez sur x86_64, changez le nom du répertoire par
défaut des bibliothèques 64 bits en « lib » :
case $(uname -m) in
x86_64)
sed -e '/m64=/s/lib64/lib/' \
-i.orig gcc/config/i386/t-linux64
;;
esac
La documentation de GCC recommande de construire GCC dans un
répertoire de construction dédié :
mkdir -v build
cd build
Préparez la compilation de GCC :
../configure --prefix=/usr \
LD=ld \
--enable-languages=c,c++ \
--enable-default-pie \
--enable-default-ssp \
--enable-host-pie \
--enable-targets=all \
--disable-multilib \
--disable-bootstrap \
--disable-fixincludes \
--with-system-zlib
We only enable C and C++ here to save the build time as no packages
in LFS and BLFS require GCC to compile other languages. Append
algol68 for Algol 68, fortran for Fortran, go for Go, objc for
Objective C, obj-c++ for Objective
C++, and/or m2 for Modula 2 into the
value of --enable-languages
option if you want to compile programs in one or more of those
languages with GCC.
GCC also supports the Ada, COBOL, and D languages. But that would
require some dependencies which are not available in the base LFS
system and would exceed the scope of this book. Read the
upstream documentation for details.
Voici la signification des nouveaux paramètres de
configuration :
-
LD=ld
-
Ce paramètre permet de s'assurer que le script configure
utilise le ld installé par Binutils, construit plus tôt dans
ce chapitre, au lieu de la version compilée de manière
croisée qui serait autrement utilisée.
-
--disable-bootstrap
-
Par défaut, le système de construction de GCC va le
bootstrapper en trois étapes à moins qu'il ne soit construit
en tant que compilateur croisé ou qu'il soit compilé de
manière croisée. Le processus de bootstrap est requis pour la
robustesse, surtout quand on met à jour GCC vers une nouvelle
version. Dans LFS nous utilisons une méthode différente pour
bootstrapper GCC (comme introduit dans le Remarques
techniques sur la chaîne de compilation), donc nous
n'avons pas besoin du processus de bootstrap fourni par le
système de construction et nous le désactivons ici pour
réduire considérablement le temps de construction. Supprimez
cette option si vous mettez à jour GCC sur un système LFS
complet (au lieu de construire une nouvelle LFS).
-
--disable-fixincludes
-
Par défaut, pendant l'installation de GCC, certains en-têtes
du système seraient « corrigés » pour fonctionner avec
GCC. Ce n'est pas nécessaire sur un système Linux moderne, et
peut être dangereux si un paquet est réinstallé après
l'installation de GCC. Ce paramètre évite que GCC ne
« corrige » les en-têtes.
-
--with-system-zlib
-
Ce paramètre dit à GCC de se lier à la copie de la
bibliothèque Zlib installée sur le système, plutôt qu'à sa
propre copie interne.
-
--enable-targets=all
-
Ce paramètre dit à GCC d'activer la prise en charge de la
génération du code 64 bits même lorsqu'on construit pour
un système 32 bits. Cela est requis pour construire GRUB
pour UEFI 64 bits. Ce paramètre n'a pas d'effet
lorsqu'on construit pour un système 64 bits.
Note
PIE (exécutable indépendant de la position) est une technique
pour produire des programmes binaires qui peuvent être chargés
n'importe où en mémoire. Sans PIE, la fonctionnalité de sécurité
nommée ASLR (randomisation de l'agencement de l'espace
d'adressage) peut être appliquée pour les bibliothèques
partagées, mais pas pour l'exécutable lui-même. Activer PIE
permet l'ASLR des exécutables en plus des bibliothèques partagées
et réduit certaines attaques basées sur des adresses fixes de
code sensible ou de données dans les exécutables.
SSP (protection contre l'écrasement de la pile) est une technique
qui s'assure que la pile des paramètres n'est pas corrompue. La
corruption de pile peut par exemple changer l'adresse de retour
d'une sous-routine, ce qui permettrait de transférer le contrôle
à du code dangereux (qui existerait dans le programme ou les
bibliothèques partagées, ou éventuellement injecté par
l'attaquant) au lieu du code d'origine.
Compilez le paquet :
make
Important
Dans cette section, la suite de tests de GCC est considérée comme
importante, mais elle prend beaucoup de temps. Les novices sont
encouragés à ne pas l'ignorer. La durée des tests peut être
significativement réduite en ajoutant -jx à la commande
make -k check
ci-dessous, où x désigne le nombre de cœurs sur votre système.
GCC peut avoir besoin de plus d'espace en pile pour compiler
certains motifs de code particulièrement complexes. Par précaution,
sur les distributions qui ont une limite de pile réduite,
configurez la limite de taille de pile à l'infini. Sur la plupart
des distributions hôtes (et le système LFS final) la limite stricte
est infinie par défaut, mais il n'y a pas d'inconvénient à
l'indiquer explicitement. Il n'est pas nécessaire de limiter la
limite non stricte car GCC la configurera à une valeur appropriée,
tant que cette valeur ne dépasse pas la limite stricte :
ulimit -s -H unlimited
Testez les résultats en tant qu'utilisateur non privilégié, mais ne
vous arrêtez pas aux erreurs :
chown -R tester .
su tester -c "PATH=$PATH make -k check"
Pour recevoir un résumé des résultats de la suite de tests,
lancez :
../contrib/test_summary -t
Pour n'avoir que les résumés, redirigez la sortie vers
grep -A7 Summ.
Vous pouvez comparer les résultats avec ceux situés dans https://www.linuxfromscratch.org/lfs/build-logs/development/
et https://gcc.gnu.org/ml/gcc-testresults/.
Parmi les tests gcc.target/i386, les
tests nommés auto-init-padding-9.c
builtin-memmove-*.c, mem{cpy,set}-pr120683-*.c, pr111657-1.c, pr115102.c, pr116896.c, pr120881-2a.c et pr122343-4a.c, sont connus pour échouer. Le test
nommé shift-gf2p8affine-2.c est connu
pour échouer si le processeur ne prend pas AVX512 en charge.
Parmi les tests g++.target/i386, les
tests nommés memset-pr108585-1{a,b}.C, mv{,c}-symbols*.C, pr112824-2.C et pr116896-1.C sont connus pour échouer.
De plus, les tests gcc.dg/ipa/pr122458.c, gcc.dg/lto/toplevel-*-asm-* et gcc.dg/plugin/crash-test-nested-*.c sont connus
pour échouer. Le test g++.dg/gomp/deprecate-1.C est connu pour parfois
échouer.
Les auteurs de LFS ont vérifiés ces échecs et confirmé qu'aucun
n'indique de problème critique. La plupart sont causés par le fait
que les auteurs des cas de test n'ont pas prévu l'utilisation de
--enable-default-ssp ou
--enable-default-pie.
Quelques échecs inattendus sont parfois inévitables. Dans certains
cas les échecs des tests dépendent du matériel spécifique du
système. Sauf si les résultats des tests sont très différents de
ceux sur l'adresse ci-dessus, vous pouvez poursuivre en toute
sécurité.
Installez le paquet :
make install
Le répertoire de construction de GCC appartient maintenant à
tester et la propriété du
répertoire des en-têtes installé (et son contenu) sera incorrecte.
Transférez la propriété à l'utilisateur et au groupe root :
chown -v -R root:root $(gcc -print-file-name=include){,-fixed}
Créez un lien symbolique requis par le FHS
pour des raisons « historiques ».
ln -svr /usr/bin/cpp /usr/lib
Beaucoup de paquets utilisent le nom cc pour appeler le compilateur C.
Nous avons déjà créé cc comme un lien symbolique dans
gcc-pass2, créez également sa
page de manuel avec un lien symbolique :
ln -sv gcc.1 /usr/share/man/man1/cc.1
Ajoutez un lien symbolique de compatibilité pour permettre la
compilation de programmes avec l'optimisation à l'édition des liens
(LTO) :
ln -sfvr $(gcc -print-prog-name=liblto_plugin.so) /usr/lib/bfd-plugins/
Maintenant que notre chaîne d'outils est en place, il est important
de s'assurer à nouveau que la compilation et l'édition de liens
fonctionneront comme prévu. Vous devez alors effectuer plusieurs
contrôles d'intégrité :
echo 'int main(){}' | cc -x c - -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'
Il ne devrait pas y avoir d'erreurs et la sortie de la dernière
commande aura cette forme (en permettant au nom de l'éditeur des
liens de différer en fonction de la plateforme) :
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
Maintenant, assurez-vous que vous êtes prêt à utiliser les bons
fichiers :
grep -E -o '/usr/lib.*/S?crt[1in].*succeeded' dummy.log
La sortie de la dernière commande devrait être :
/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.0/../../../../lib/Scrt1.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.0/../../../../lib/crti.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.0/../../../../lib/crtn.o succeeded
Selon l'architecture de votre machine, le message ci-dessus peut
légèrement différer. La différence porte sur le nom du répertoire
après /usr/lib/gcc. Il est important
de vérifier que gcc a
trouvé les trois fichiers crt*.o sous
le répertoire /usr/lib.
Vérifiez que le compilateur recherche les bons fichiers
d'en-têtes :
grep -B4 '^ /usr/include' dummy.log
Cette commande devrait renvoyer la sortie suivante :
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.0/include
/usr/local/include
/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.0/include-fixed
/usr/include
À nouveau, le répertoire nommé selon votre triplet cible peut être
différent de celui ci-dessus, selon l'architecture de votre
système.
Ensuite, vérifiez que le nouvel éditeur de liens est utilisé avec
les bons chemins de recherche :
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
Les références au chemins qui ont des composantes comme
« -linux-gnu » devraient être ignorés, mais sinon la
sortie de la dernière commande devrait être :
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64")
SEARCH_DIR("/usr/local/lib64")
SEARCH_DIR("/lib64")
SEARCH_DIR("/usr/lib64")
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");
Un système 32 bits peut voir quelques répertoires
différemment. Par exemple, voici la sortie d'une machine
i686 :
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib32")
SEARCH_DIR("/usr/local/lib32")
SEARCH_DIR("/lib32")
SEARCH_DIR("/usr/lib32")
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");
Ensuite assurez-vous que vous utilisez la bonne libc :
grep "/lib.*/libc.so.6 " dummy.log
La sortie de la dernière commande devrait être :
attempt to open /usr/lib/libc.so.6 succeeded
Assurez-vous que GCC utilise le bon éditeur dynamique :
grep found dummy.log
La sortie de la dernière commande devrait être (avec éventuellement
des différences spécifiques à votre plateforme dans le nom de
l'éditeur dynamique) :
found ld-linux-x86-64.so.2 at /usr/lib/ld-linux-x86-64.so.2
Si la sortie ne ressemble pas à celle montrée ci-dessus ou si elle
n'est pas disponible du tout, cela signifie que quelque chose s'est
vraiment mal passé. Enquêtez et répétez les étapes pour trouver où
les problèmes se trouvent et corrigez-les. Tout problème doit être
résolu avant de continuer le processus.
Une fois que tout fonctionne correctement, nettoyez les fichiers de
test :
rm -v a.out dummy.log
Enfin, déplacez un fichier mal placé :
mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib