
                             GCC HOWTO pour Linux

par Daniel Barlow <dan@detached.demon.co.uk>

   v1.17, 28 fvrier 1996
     _________________________________________________________________

   _(Adaptation franaise par Eric Dumas <dumas@freenix.fr>, 8 Avril
   1996). Ce document prsente la manire de configurer le compilateur
   GNU C et les bibliothques de dveloppement sous Linux. Il donne un
   aperu de la compilation, de l'dition de liens, de l'excution et du
   dbogage de programmes sous Linux. Bon nombre de passages de ce
   document sont emprunts  la FAQ GCC rdige par Mitch D'Souza's et au
   HowTo ELF. Ceci est la premire version publique (en dpit du numro
   de version : en fait, a vient de RCS). N'hsitez pas  me joindre
   pour toute remarque._
     _________________________________________________________________

1. Prliminaires

1.1 ELF et a.out

   Le dveloppement de Linux est actuellement dans une phase de
   transition. En rsum, il existe deux formats de binaires que Linux
   reconnat et excute, et cela dpend de la manire dont votre systme
   est configur : vous pouvez avoir les deux, l'un ou l'autre. En lisant
   ce document, vous pourrez savoir quels binaires votre systme est
   capable de grer.

   Comment le savoir ? Utilisez la commande file (par exemple, file
   /bin/bash). Pour un programme ELF, cette commande va vous rpondre
   quelque chose dans lequel se trouve le mot ELF. Dans le cas d'un
   programme en a.out, il vous indiquera quelque chose comme Linux/i386.

   Les diffrences entre ELF et a.out sont dtailles plus tard dans ce
   document. ELF est le nouveau format et il est considr comme tant
   meilleur.

1.2 Du ct du copyright

   Le copyright et autres informations lgales peuvent tre trouvs  la
   _fin_ de ce document, avec les avertissements conventionnels concernant
   la manire de poser des questions sur Usenet pour viter d'avoir 
   rvler votre ignorance du langage C en annonant des bogues qui n'en
   sont pas, etc.

1.3 Typographie

   Si vous lisez ce document au format Postscript, dvi, ou HTML, vous
   pouvez voir quelques diffrence entre les styles d'criture alors que
   les gens qui consultent ce document au format texte pur ne verront
   aucune diffrence. En particulier, les noms de fichiers, le nom des
   commandes, les messages donns par les programmes et les codes sources
   seront crits avec le style suivant : style d'criture, alors que les
   noms de variables entre autres choses seront en _italique_.

   Vous aurez galement un index. Avec les formats dvi ou postscript, les
   chiffres dans l'index correspondent au numros de paragraphes. Au
   format HTML, il s'agit d'une numrotation squentielle pour que vous
   puissiez cliquer dessus. Avec le format texte, ce ne sont que des
   nombres. Il vous est donc conseill de prendre un autre format que le
   format texte !

   L'interprteur de commande (_shell_) utilis dans les exemples sera la
   Bourne shell (plutt que le C-Shell). Les utilisateurs du C-Shell
   utiliseront plutt :

% setenv soif JD

   l o j'ai crit

$ soif=JD; export soif

   Si l'invite (_prompt_ dans la langue de Shakespeare) est # plutt que
   $, la commande ne fonctionnera que si elle est excute au nom de
   Root. Bien sur, je dcline toute responsabilit de ce qui peut se
   produire sur votre systme lors de l'excution de ces exemples. Bonne
   chance :-)

2. O rcuprer de la documentation et les programmes ?

2.1 Ce document

   Ce document fait partie de la srie des HOWTO pour Linux, et il est
   donc disponible ainsi que ces collgues dans les rpertoires HowTo
   pour Linux, comme sur http://sunsite.unc.edu/pub/linux/docs/HOWTO/. La
   version HTML peut galement tre consulte sur
   http://ftp.linux.org.uk/~barlow/howto/gcc-howto.html.

   Note du traducteur : vous pouvez obtenir tous les HowTos en langue
   anglaise et franaise sur ftp.ibp.fr:/pub/linux. Les versions
   franaises se trouvent dans le rpertoire /pub/linux/french/HOWTO.

2.2 Autres documentation

   La documentation officielle pour gcc se trouve dans les sources de la
   distribution (voir plus bas) sous la forme de fichiers texinfo et de
   fichiers .info. Si vous possdez une connexion rapide, un CD-ROM ou
   une certaine patience, vous pouvez dsarchiver la documentation et
   l'installer dans le rpertoire /usr/info. Sinon, vous pouvez toujours
   les trouver sur tsx-11, mais ce n'est pas ncessairement toujours la
   dernire version.

   Il existe deux sources de documentation pour la libc. La libc GNU est
   fournie avec des fichiers info qui dcrivent assez prcisment la libc
   Linux sauf pour la partie des entres-sorties. Vous pouvez galement
   trouver sur sunsite des documents crits pour Linux ainsi que la
   description de certaines appels systmes (section 2) et certaines
   fonctions de la libc (section 3).

   Note du traducteur : un bmol concernant cette partie... La libc Linux
   n'est pas GNU et tend  tre relativement diffrente sur certains
   points.

2.3 GCC

   Il existe deux types de rponses

   (a) La distribution officielle de GCC pour Linux peut toujours tre
   rcupre sous la forme de binaires (dj compile) sur
   ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/. Vous pouvez la trouver
   sur le miroir franais ftp://ftp.ibp.fr:/pub/linux/packages/GCC/. A
   l'heure o j'cris ces lignes, la dernire version est gcc 2.7.2
   (gcc-2.7.2.bin.tar.gz).

   (b) La dernire distribution des sources de GCC de la _Free Software
   Foundation_ peut-tre rcupre sur prep.ai.mit.edu ou ftp.ibp.fr. Ce
   n'est pas toujours la mme version que celle prsente ci-dessus. Les
   mainteneurs de GCC pour Linux ont rendu la compilation de GCC plus
   facile grce  l'utilisation du script configure qui effectue la
   configuration d'une manire automatique. Regardez dans tsx-11 ou
   ftp.ibp.fr pour rcuprer d'ventuels patches.

   Quelle que soit la complexit de votre programme, vous aurez galement
   besoin de la _libc_.

2.4 Les fichiers d'en-tte et la bibliothque C

   Ce que vous allez trouver dans ce paragraphe dpend
     * de votre systme (ELF ou a.out) ;
     * du type de binaire que vous dsirez gnrer.

   Si vous tes en train de mettre  jour votre libc 4 en libc 5, vous
   devriez consulter le ELF HowTo qui se trouve au mme endroit que ce
   document.

   Les libc sont disponibles sur tsx-11 ou ftp.ibp.fr. Voici une
   description des fichiers situs dans ce rpertoire :

   _libc-5.2.18.bin.tar.gz_
          --- bibliothques dynamiques et statiques ELF plus les fichiers
          d'en-tte pour la bibliothque C et la bibliothque
          mathmatique.

   _libc-5.2.18.tar.gz_
          --- Code source pour la bibliothque ci-dessus. Vous aurez
          galement besoin du paquetage .bin. pour avoir les fichiers
          d'en-tte. Si vous hsitez entre compiler la bibliothque C
          vous-mme et utiliser les binaires, la bonne rponse est dans
          la majorit des cas est d'utiliser les binaires. Toutefois, si
          vous dsirer utiliser NYS (NdT : NYS != NIS) ou bien les mots
          de passe _shadow_, vous devrez recompiler la libc par
          vous-mme.

   _libc-4.7.5.bin.tar.gz_
          --- bibliothques dynamiques et statiques a.out pour la version
          4.7.5 de la libc. Cette bibliothque a t conue pour pouvoir
          coexister avec le paquetage de la libc 5 dcrit ci-dessus, mais
          c'est uniquement ncessaire si vous dsirez utiliser ou
          dvelopper des programmes au format a.out.

2.5 Outils associs (as, ld, ar, strings, etc.)

   Ces outils se trouvent comme les bibliothques dans le rpertoire
   tsx-11, et ftp.ibp.fr. La version actuelle est
   binutils-2.6.0.2.bin.tar.gz.

   Il est utile de remarquer que ces outils ne sont disponibles qu'au
   format ELF, que la libc actuelle est ELF et que la libc a.out ne pose
   pas de problme lorsqu'elle est utilise avec la libc ELF. Le
   dveloppement de la libc est relativement rapide et  moins que n'ayez
   de bonnes raisons pour utiliser le format a.out, vous tes encourags
    suivre le mouvement.

3. Installation et configuration de GCC

3.1 Les versions de GCC

   Vous pouvez savoir quelle est la version de GCC que vous possdez en
   tapant gcc -v lors de l'invite. C'est galement une bonne technique
   pour savoir si votre configuration est ELF ou a.out. Sur mon systme,
   cela donne ceci :

$ gcc -v
Reading specs from /usr/lib/gcc-lib/i486-zorglub-linux/2.7.2/specs
gcc version 2.7.2

   Les mots-clefs  remarquer
     * i486. Cela vous indique que la version de gcc que vous utilisez a
       t compile pour tre utilise sur un processeur 486 --- mais
       vous pouvez avoir un autre processeur comme un 386 ou un Pentium
       (586). Tous ces processeurs peuvent excuter le code compil avec
       n'importe quel processeur. La seule diffrence rside dans le fait
       que le code 486 rajoute un peu de code  certains endroits pour
       aller plus vite sur un 486. Cela n'a pas d'effet nfaste ct
       performance sur un 386 mais cela rend les excutables un peu plus
       importants.
     * zorglub. Ce n'est pas rellement important, et il s'agit
       gnralement d'un commentaire (comme slackware or debian) ou mme,
       cela peut-tre vide (lorsque vous avez comme nom de rpertoire
       i486-linux). Si vous construisez votre propre gcc, vous pouvez
       fixer ce paramtre selon vos dsirs, comme je l'ai fait. :-)
     * linux. Cela peut tre  la place linuxelf ou linuxaout et en fait,
       la signification varie en fonction de la version que vous
       possdez.
          + linux signifie ELF si la version est 2.7.0 ou suprieure,
            sinon, c'est du a.out.
          + linuxaout signifie a.out. Cela a t introduit comme cible
            lorsque le format des binaires a chang de a.out vers ELF
            dans _Linux_. Normalement, vous ne verrez plus de linuxaout
            avec une version de gcc suprieure  2.7.0.
          + linuxelf est dpass. Il s'agit gnralement de gcc version
            2.6.3 configur pour gnrer des excutables ELF. Notez que
            gcc 2.6.3 est connu pour gnrer de nombreuses erreurs
            lorsqu'il produit du code ELF --- une mise  jour est trs
            fortement recommande.
     * 2.7.2 est le numro de la version de GCC.

   Donc, en rsum, nous possdons gcc 2.7.2 qui gnre du code ELF.
   _Quelle surprise_ (NdT: En franais dans le texte) !

3.2 A quel endroit s'installe GCC ?

   Si vous avez install gcc sans regarder, ou bien si vous l'avez eu 
   partir d'une distribution, vous pouvez avoir envie de savoir o il se
   trouve dans votre arborescence. Les mots clefs permettant cela sont

     * /usr/lib/gcc-lib/_machine-cible_/_version_/ (et ses
       sous-rpertoires) est gnralement l'endroit o se trouve le plus
       souvent le compilateur. Ceci inclut les excutables qui ralisent
       la compilation ainsi que certaines bibliothques et quelques
       fichiers d'en-tte.
     * /usr/bin/gcc est le lanceur du compilateur --- c'est en fait le
       programme que vous lancez. Il peut tre utilis avec plusieurs
       versions de gcc lorsque vous possdez plusieurs rpertoires
       installs (voir plus bas). Pour trouver la version par dfaut
       utilise, lancez gcc -v. Pour forcer l'utilisation d'une autre
       version, lancez gcc -V _version_. Par exemple,

# gcc -v
Reading specs from /usr/lib/gcc-lib/i486-zorglub-linux/2.7.2/specs
gcc version 2.7.2
# gcc -V 2.6.3 -v
Reading specs from /usr/lib/gcc-lib/i486-zorglub-linux/2.6.3/specs
gcc driver version 2.7.2 executing gcc version 2.6.3

     * /usr/_machine-cible_/(bin|lib|include)/. Si vous avez install
       plusieurs cibles possibles (par exemple a.out et elf, ou bien un
       compilateur crois, les bibliothques, les binutils (as, ld, etc.)
       et les fichiers d'en-tte pour les cibles diffrente de celle par
       dfaut peuvent tre trouvs  cet endroit. Mme si vous n'avez
       qu'une seule version de gcc installe, vous devriez toutefois
       trouver  cet endroit un certain nombre de fichiers. Si ce n'est
       pas la cas, regardez dans /usr/(bin|lib|include).
     * /lib/, /usr/lib et autres sont les rpertoires pour les
       bibliothques pour le systme initial. Vous aurez galement besoin
       du programme /lib/cpp pour un grand nombre d'applications (X
       l'utilise beaucoup) --- soit vous le copiez  partir de
       /usr/lib/gcc-lib/_machine-cible_/_version_/, soit vous faites
       pointer un lien symbolique dessus.

3.3 O se trouvent les fichiers d'en-tte ?

   Si l'on excepte les fichier fichiers d'en-tte que vous installez dans
   le rpertoire /usr/local/include, il y a en fait trois types de
   fichiers d'en-tte :

     * La grande majorit des fichiers situs dans le rpertoire
       /usr/include/ et dans ses sous-rpertoires proviennent du
       paquetage de la libc dont s'occupe H.J. Lu. Je dis bien la "grande
       majorit" car vous pouvez avoir galement certains fichiers
       provenant d'autres sources (par exemple des bibliothques curses
       et dbm), ceci est d'autant plus vrai si vous possdez une
       distribution de la libc rcente (o les bibliothques curses et
       dbm ne sont pas intgres).
     * Les rpertoires /usr/include/linux et /usr/include/asm (pour les
       fichiers <linux/*.h> et <asm/*.h>) doivent tre des liens
       symboliques vers les rpertoires linux/include/linux et
       linux/include/asm situs dans les sources du noyau. Vous devrez
       installer ces sources si vous dsirez pouvoir dvelopper : ces
       sources ne sont pas utiliss uniquement pour compiler le noyau. Il
       est probable que vous ayez besoin de lancer la commande suivante
       make config dans le rpertoire des sources du noyau aprs les
       avoir installs. Beaucoup de fichiers ont besoin du fichier
       d'en-tte <linux/autoconf.h> qui n'existe pas sans cette commande.
       Il est  noter que dans certaines versions du noyau, le rpertoire
       asm est en fait un lien symbolique qui n'est cr qu'avec
       l'excution de make config. Donc, si vous installez les sources du
       noyau dans le rpertoire /usr/src/linux, il suffit de faire :

$ cd /usr/src/linux
$ su
# make config
[repondez aux questions. A moins que vous ne recompiliez votre
noyau, les reponses importent peu]
# cd /usr/include
# ln -s ../src/linux/include/linux .
# ln -s ../src/linux/include/asm .

     * Les fichiers tels que <float.h>, <limits.h>, <varargs.h>,
       <stdarg.h> et <stddef.h> changent en fonction de la version du
       compilateur, et peuvent tre trouvs dans le rpertoire
       /usr/lib/gcc-lib/i486-box-linux/2.7.2/include/ pour la version
       2.7.2.

3.4 Construire un compilateur crois

  Linux comme plate-forme de destination

   Nous supposons que vous avez rcupr les sources de gcc, et
   normalement, il vous suffit de suivre les instructions donnes dans le
   fichier INSTALL situ dans les sources de gcc. Ensuite, il suffit de
   lancer configure --target=i486-linux --host=XXX sur une plateforme
   XXX, puit un make devrait compiler gcc correctement. Il est  noter
   que vous aurez besoin des fichiers d'en-tte de Linux, ainsi que les
   sources de l'assembleur et du l'diteur de liens croiss que vous
   pouvez trouver sur ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ ou
   ftp://ftp.ibp.fr/pub/linux/GCC/.

  Linux comme plate-forme origine et MSDOS comme destination

   Arggg. Apparemment, cela est possible en utilisant le paquetage  emx
    ou l'extension  go . Regardez
   ftp://sunsite.unc.edu/pub/Linux/devel/msdos pour plus d'informations.

   Je n'ai pas test cela et je ne pense pas le faire !

4. Portage et compilation

4.1 Symboles dfinis automatiquement

   Vous pouvez trouver quels symboles votre version de gcc dfinit
   automatiquement en le lanant avec l'option -v. Par exemple cela donne
   a chez moi :

$ echo 'main(){printf("Bonjour !\n");}' | gcc -E -v -
Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs
gcc version 2.7.2
 /usr/lib/gcc-lib/i486-box-linux/2.7.2/cpp -lang-c -v -undef
-D__GNUC__=2 -D__GNUC_MINOR__=7 -D__ELF__ -Dunix -Di386 -Dlinux
-D__ELF__ -D__unix__ -D__i386__ -D__linux__ -D__unix -D__i386
-D__linux -Asystem(unix) -Asystem(posix) -Acpu(i386)
-Amachine(i386) -D__i486__ -

   Si vous crivez du code qui utilise des spcificits Linux, il est
   souhaitable d'implmenter le code non portable de la manire suivante

#ifdef __linux__
/* ... code linux ... */
#endif /* linux */

   Utilisez __linux__ pour cela, et _pas_ linux. Bien que cette macro
   soit dfinie, ce n'est pas une spcification POSIX.

4.2 Options de compilation

   La documentation des options de compilation se trouve dans les pages
   _info_ de gcc (sous Emacs, utilisez C-h i puis slectionnez l'option
   `gcc'). Votre distribution peut ne pas avoir install la documentation
   ou bien vous pouvez en avoir une ancienne. Dans ce cas, la meilleure
   chose  faire est de rcuprer les sources de gcc depuis
   ftp://prep.ai.mit.edu/pub/gnu ou l'un des ses nombreux miroirs dont
   ftp://ftp.ibp.fr/pub/gnu.

   La page de manuel gcc (gcc.1) est en principe, compltement dpasse.
   Cela vous met en garde si vous dsirez la consulter.

  Options de compilation

   gcc peut raliser un certain nombre d'optimisations sur le code gnr
   en ajoutant l'option -O_n_  la ligne de commandes, o _n_ est un
   chiffre. La valeur de _n_, et son effet exact, dpend de la version de
   gcc, mais s'chelonne normalement entre 0 (aucune optimisation) et 2
   (un certain nombre) ou 3 (toutes les optimisations possibles).

   En interne, gcc interprte les options telles que -f et -m. Vous
   pouvez voir exactement ce qu'effectue le niveau spcifi dans l'option
   -O en lanant gcc avec l'option -v et l'option (non documente) -Q.
   Par exemple, l'option -O2, effectue les oprations suivantes sur ma
   machine :

enabled: -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks
-fexpensive-optimizations
         -fthread-jumps -fpeephole -fforce-mem -ffunction-cse -finline
         -fcaller-saves -fpcc-struct-return -frerun-cse-after-loop
         -fcommon -fgnu-linker -m80387 -mhard-float -mno-soft-float
         -mno-386 -m486 -mieee-fp -mfp-ret-in-387

   Utiliser un niveau d'optimisation suprieur  celui que le compilateur
   supporte (par exemple -O6) aura le mme effet qu'utiliser le plus haut
   niveau gr. Distribuer du code o la compilation est configure de
   cette manire est une trs mauvaise ide -- si d'autres optimisations
   sont incorpores dans de versions futures, vous (ou d'autres
   utilisateurs) pouvez vous apercevoir que cela ne compile plus, ou bien
   que le code gnr ne fait pas les actions dsires.

   Les utilisateurs de gcc 2.7.0  2.7.2 devraient noter qu'il y a un
   bogue dans l'option -O2. Plus prcisment, la _strength reduction_ ne
   fonctionne pas. Un patch a t implment pour rsoudre ce problme,
   mais vous devez alors recompiler gcc. Sinon, vous devrez toujours
   compiler avec l'option -fno-strength-reduce.

  Spcification du processeur

   Il existe d'autres options -m qui ne sont pas positionnes lors de
   l'utilisation de -O mais qui sont nanmoins utiles dans certains cas.
   C'est le cas pour les options -m386 et -m486, qui indiquent  gcc de
   gnrer un code plus ou moins optimis pour l'un ou l'autre type de
   processeur. Le code continuera  fonctionner sur les deux processeurs.
   Bien que le code pour 486 soit plus important, il ne ralentit pas
   l'excution du programme sur 386.

   Il n'existe pas actuellement de -mpentium ou -m586. Linus a suggr
   l'utilisation des options -m486 -malign-loops=2 -malign-jumps=2
   -malign-functions=2, pour exploiter les optimisations du 486 tout en
   perdant de la place due aux problmes d'alignements (dont le Pentium
   n'a que faire). Michael Meissner (de Cygnus) nous dit :

      Mon avis est que l'option -mno-strength-reduce permet d'obtenir
     un code plus rapide sur un x86 (nota : je ne parle pas du bogue
     _strength reduction_, qui est un autre problme). Cela s'explique en
     raison du peu de registres dont disposent ces processeurs (et la
     mthode de GCC qui consiste  grouper les registres dans l'ordre
     inverse au lieu d'utiliser d'autres registres n'arrange rien). La
     _strength reduction_ consiste en fait  rajouter des registres pour
     remplacer les multiplications par des additions. Je suspecte
     galement -fcaller-saves de ne pas arranger la situation. 

     Une autre ide est que -fomit-frame-pointer n'est pas
     obligatoirement une bonne ide. D'un ct, cela peut signifier
     qu'un autre registre est disponible pour une allocation. D'un autre
     ct, vue la manire dont les processeurs x86 codent leur jeu
     d'instruction, cela peut signifier que la pile des adresses
     relatives prend plus de place que les adresses de fentres
     relatives, ce qui signifie en clair que moins de cache est
     disponible pour l'excution du processus. Il faut prciser que
     l'option -fomit-frame-pointer, signifie que le compilateur doit
     constamment ajuster le pointeur de pile aprs les appels, alors
     qu'avec une fentre, il peut laisser plusieurs appels dans la pile.

   Le mot final sur le sujet provient de Linus :

     Remarquez que si vous voulez des performances maximales, ne me
     croyez pas : testez ! Il existe tellement d'options de gcc, et il
     est possible que cela ne soit une relle optimisation que pour
     vous.

  Internal compiler error: cc1 got fatal signal 11

   Signal 11 correspond au signal SIGSEGV, ou bien _segmentation
   violation_. Normalement, cela signifie que le programme s'est mlang
   les pointeurs et a essay d'crire l o il n'en a pas le droit. Donc,
   cela pourrait tre un bug de gcc.

   Toutefois, gcc est un logiciel assez test et assez remarquable de ce
   ct. Il utilise un grand nombre de structures de donnes complexes,
   et un nombre impressionnant de pointeurs. En rsum, c'est le plus
   pointilleux des testeurs de mmoire existants. Si vous _n'arrivez pas
    reproduire le bogue_ --- si cela ne s'arrte pas au mme endroit
   lorsque vous retentez la compilation --- c'est plutt un problme avec
   votre machine (processeur, mmoire, carte mre ou bien cache).
   _N'annoncez pas_ la dcouverte d'un nouveau bogue si votre ordinateur
   traverse tous les tests du BIOS, ou s'il fonctionne correctement sous
   Windows ou autre : ces tests ne valent rien. Il en va de mme si le
   noyau s'arrte lors du `make zImage' ! `make zImage' doit compiler
   plus de 200 fichiers, et il en faut bien moins pour arriver  faire
   chouer une compilation.

   Si vous arrivez  reproduire le bogue et (mieux encore)  crire un
   petit programme qui permet de mettre en vidence cette erreur, alors
   vous pouvez envoyer le code soit  la FSF, soit dans la liste
   linux-gcc. Consultez la documentation de gcc pour plus de dtails
   concernant les informations ncessaires.

4.3 Portabilit

   Cette phrase a t dite un jour : si quelque chose n'a pas t port
   vers Linux alors ce n'est pas important de l'avoir :-).

   Plus srieusement, en gnral seules quelques modifications mineures
   sont ncessaires car Linux rpond  100% aux spcifications POSIX. Il
   est gnralement sympathique d'envoyer  l'auteur du programme les
   modifications effectues pour que le programme fonctionne sur Linux,
   pour que lors d'une future version, un `make' suffise pour gnrer
   l'excutable.

  Spcificits BSD (notamment bsd_ioctl, daemon et<sgtty.h>)

   Vous pouvez compiler votre programme avec l'option -I/usr/include/bsd
   et faire l'dition de liens avec -lbsd (en ajoutant -I/usr/include/bsd
    la ligne CFLAGS et -lbsd  la ligne LDFLAGS dans votre fichier
   Makefile). Il est galement ncessaire de ne _pas_ ajouter
   -D__USE_BSD_SIGNAL si vous voulez que les signaux BSD fonctionnent car
   vous les avez inclus automatiquement avec la ligne -I/usr/include/bsd
   et en incluant le fichier d'en-tte <signal.h>.

  Signaux _manquants_ (SIGBUS, SIGEMT, SIGIOT, SIGTRAP, SIGSYS, etc.)

   Linux respecte les spcifications POSIX. Ces signaux n'en font pas
   partie (cf. ISO/IEC 9945-1:1990 - IEEE Std 1003.1-1990, paragraphe
   B.3.3.1.1) :

      Les signaux SIGBUS, SIGEMT, SIGIOT, SIGTRAP, et SIGSYS ont t
     omis de la norme POSIX.1 car leur comportement est dpendant de
     l'implmentation et donc ne peut tre rpertori d'une manire
     satisfaisante. Certaines implmentations peuvent fournir ces
     signaux mais doivent documenter leur effet 

   La manire la plus lgante de rgler ce problme est de redfinir ces
   signaux  SIGUNUSED. La manire _normale_ de procder est d'entourer
   le code avec les #ifdef appropris :

#ifdef SIGSYS
/* ... code utilisant les signaux non posix  .... */
#endif

  Code K & R

   GCC est un compilateur ANSI, or il existe beaucoup de code qui ne soit
   pas ANSI.

   Il n'y a pas grand chose  faire, sauf rajouter l'option -traditional
   lors de la compilation. Il effectue certaines vrifications
   supplmentaires. Consultez les pages info gcc.

   Notez que l'option -traditional a pour unique effet de changer la
   forme du langage accept par gcc. Par exemple, elle active l'option
   -fwritable-strings, qui dplace toutes les chanes de caractres vers
   l'espace de donnes (depuis l'espace de texte, o elle ne peuvent pas
   tre modifies). Ceci augmente la taille de la mmoire occupe par le
   programme.

  Les symboles du prprocesseur produisent un conflit avecles prototypes du
  code

   Un des problmes frquents se produit lorsque certaines fonctions
   standards sont dfinies comme macros dans les fichiers d'en-tte de
   Linux et le prprocesseur refusera de traiter des prototypes
   identiques. Par exemple, cela peut arriver avec atoi() et atol().

  sprintf()

   Parfois, soyez prudent lorsque vous effectuez un portage  partir des
   sources de programmes fonctionnant sous SunOs, surtout avec la
   fonction sprintf(string, fmt, ...) car elle renvoie un pointeur sur la
   chane de caractres alors que Linux (suivant la norme ANSI) retourne
   le nombre de caractres recopis dans la chane de caractres.

  fcntl et ses copains. O se trouve la dfinition de FD_* et compagnie ?

   Dans <sys/time.h>. Si vous utilisez fcntl vous voudrez probablement
   inclure <unistd.h> galement, pour avoir le prototype de la fonction.

   D'une manire gnrale, la page de manuel pour une fonction donne la
   liste des fichiers d'en-tte  inclure.

  Le timeout de select(). Les programmescommencent dans un tat d'attente
  active

   A une certaine poque, le paramtre timeout de la fonction select()
   tait utilis en lecture seule. C'est pourquoi la page de manuel
   comporte une mise en garde :

     select() devrait retourner normalement le temps coul depuis le
     timeout initial, s'il s'est dclench, en modifiant la valeur
     pointe par le paramtre time. Cela sera peut-tre implment dans
     les versions ultrieures du systme. Donc, il n'est pas vraiment
     prudent de supposer que les donnes pointes ne seront pas
     modifies lors de l'appel  select().

   Mais tout arrive avec le temps ! Lors d'un retour de select(),
   l'argument timeout recevra le temps coul depuis la dernire
   rception de donnes. Si aucune donne n'est arrive, la valeur sera
   nulle, et les futurs appels  cette fonction utilisant le mme timeout
   auront pour rsultat un retour immdiat.

   Pour rsoudre le problme, il suffit de mettre la valeur timeout dans
   la structure  chaque appel de select(). Le code initial tait

      struct timeval timeout;
      timeout.tv_sec = 1;
      timeout.tv_usec = 0;
      while (some_condition)
            select(n,readfds,writefds,exceptfds,&timeout);

   et doit devenir :

      struct timeval timeout;
      while (some_condition)
      {
            timeout.tv_sec = 1;
            timeout.tv_usec = 0;
            select(n,readfds,writefds,exceptfds,&timeout);
      }

   Certaines versions de Mosaic taient connues  une certaine poque
   pour avoir ce problme.

   La vitesse de rotation du globe terrestre tait inversement
   proportionnelle  la vitesse de transfert des donnes !

  Appels systmes interrompus

  Symptomes :

   Lorsqu'un processus est arrt avec un Ctrl-Z et relanc - ou bien
   lorsqu'un autre signal est dclench dans une situation diffrente :
   par exemple avec un Ctrl-C, la terminaison d'un processus, etc, on dit
   qu'il y a  interruption d'un appel systme  , ou bien  write :
   erreur inconnue  ou des trucs de ce genre.

  Problmes :

   Les systmes POSIX vrifient les signaux plus souvent que d'autres
   Unix plus anciens. Linux peux lancer les gestionnaires de signaux :
     * d'une manire asynchrone (sur un top d'horloge)
     * lors d'un retour de n'importe quel appel systme
     * pendant l'excution des appels systmes suivants : select(),
       pause(), connect(), accept(), read() sur des terminaux, des
       sockets, des pipes ou des fichiers situs dans /proc, write() sur
       des terminaux, des sockets, des pipes ou des imprimantes, open()
       sur des FIFOs, des lignes PTYs ou sries, ioctl() sur des
       terminaux, fcntl() avec la commande F_SETLKW, wait4(), syslog(),
       et toute opration d'ordre TCP ou NFS.

   Sur d'autres systmes d'exploitation, il est possible que vous ayez 
   inclure dans cette catgorie les appels systmes suivants : creat(),
   close(), getmsg(), putmsg(), msgrcv(), msgsnd(), recv(), send(),
   wait(), waitpid(), wait3(), tcdrain(), sigpause(), semop().

   Si un signal (que le programme dsire traiter) est lanc pendant
   l'excution d'un appel systme, le gestionnaire est lanc. Lorsque le
   gestionnaire du signal se termine, l'appel systme dtecte qu'il a t
   interrompu et se termine avec la valeur -1 et errno = EINTR. Le
   programme n'est pas forcment au courant de ce qui s'est pass et donc
   s'arrte.

   Vous pouvez choisir deux solutions pour rsoudre ce problme.

   (1)Dans tout gestionnaire de signaux que vous mettez en place, ajoutez
   l'option SA_RESTART au niveau de _sigaction_. Par exemple, modifiez

  signal (signal_id, mon_gestionnaire_de_signaux);

   en

  signal (signal_id, mon_gestionnaire_de_signaux);
  {
        struct sigaction sa;
        sigaction (signal_id, (struct sigaction *)0, &sa);
#ifdef SA_RESTART
        sa.sa_flags |= SA_RESTART;
#endif
#ifdef SA_INTERRUPT
        sa.sa_flags &= ~ SA_INTERRUPT;
#endif
        sigaction (signal_id, &sa, (struct sigaction *)0);
  }

   Notez que lors de certains appels systmes vous devrez souvent
   regarder si errno n'a pas t positionne  EINTR par vous mme comme
   avec read(), write(), ioctl(), select(), pause() et connect().

   (2) A la recherche de EINTR :

   Voici deux exemples avec read() et ioctl(),

   Voici le code original utilisant read()

int result;
while (len > 0)
{
  result = read(fd,buffer,len);
  if (result < 0)
        break;
  buffer += result;
  len -= result;
}

   et le nouveau code

int result;
while (len > 0)
{
  result = read(fd,buffer,len);
  if (result < 0)
  {
        if (errno != EINTR)
                break;
  }
  else
  {
        buffer += result;
        len -= result;
  }
}

   Voici un code utilisant ioctl()

int result;
result = ioctl(fd,cmd,addr);

   et cela devient

int result;
do
{
   result = ioctl(fd,cmd,addr);
}
while ((result == -1) && (errno == EINTR));

   Il faut remarquer que dans certaines versions d'Unix de type BSD on a
   l'habitude de relancer l'appel systme. Pour rcuprer les
   interruptions d'appels systmes, vous devez utiliser les options
   SV_INTERRUPT ou SA_INTERRUPT.

  Les chanes et leurs accs en critures (ou les programmes qui provoquent
  des segmentation fault  d'une manire alatoire)

   GCC a une vue optimiste en ce qui concerne ses utilisateurs, en
   croyant qu'ils respectent le fait qu'une chane dite constante l'est
   rellement. Donc, il les range dans la zone _texte(code)_ du
   programme, o elles peuvent tre charges puis dcharges  partir de
   l'image binaire de l'excutable situe sur disque (ce qui vite
   d'occuper de l'espace disque). Donc, toute tentative d'criture dans
   cette chane provoque un  segmentation fault .

   Cela peut poser certains problmes avec d'anciens codes, par exemple
   ceux qui utilisent la fonction mktemp() avec une chane constante
   comme argument. mktemp() essaye d'crire dans la chane passe en
   argument.

   Pour rsoudre ce problme,
    1. compilez avec l'option -fwritable-strings pour indiquer  gcc de
       mettre les chanes constantes dans l'espace de donnes
    2. rcrire les diffrentes parties du code pour allouer une chane
       non constante puis effectuer un strcpy des donnes dedans avant
       d'effectuer l'appel.

  Pourquoi l'appel  execl() choue ?

   Tout simplement parce que vous l'utilisez mal. Le premier argument
   d'execl est le programme que vous dsirez excuter. Le second et ainsi
   de suite sont en fait le lments du tableau argv que vous appelez.
   Souvenez-vous que argv[0] est traditionnellement fix mme si un
   programme est lanc sans argument. Vous devriez donc crire :

execl("/bin/ls","ls",NULL);

   et pas

execl("/bin/ls", NULL);

   Lancer le programme sans argument est considr comme tant une
   demande d'affichage des bibliothques dynamiques associes au
   programme, si vous utilisez le format a.out. ELF fonctionne d'une
   manire diffrente.

   (Si vous dsirez ces informations, il existe des outils plus simples;
   consultez la section sur le chargement dynamique, ou la page de manuel
   de ldd).

5. Dboguer et optimiser

5.1 Etude prventive du code (lint)

   Il n'existe pas de lint qui soit rellement utilisable, tout
   simplement parce que la grande majorit des dveloppeurs sont
   satisfaits des messages d'avertissement de gcc. Il est probable que
   l'option la plus utile est l'option -Wall --- qui a pour effet
   d'afficher tous les avertissements possibles.

   Il existe une version du domaine public du programme lint que vous
   pouvez trouver  l'adresse suivante :
   ftp://larch.lcs.mit.edu/pub/Larch/lclint. Je ne sais pas ce qu'elle
   vaut.

5.2 Dboguer

  Comment rendre dbogable un programme ?

   Vous devez compiler et effectuer l'dition de liens avec l'option -g,
   et sans l'option -fomit-frame-pointer. En fait, vous ne devez compiler
   que les modules que vous avez besoin de dboguer.

   Si vous possdez un systme a.out, les bibliothques dynamiques sont
   compiles avec l'option -fomit-frame-pointer, que gcc ne peut pas
   grer. Lorsque vous compilez avec l'option -g, alors par dfaut vous
   effectuez une dition de liens statique, ce qui permet de rsoudre le
   problme.

   Si l'diteur de liens choue avec un message disant qu'il n'arrive pas
    trouver la bibliothque libg.a, c'est que vous ne possdez pas la
   bibliothque /usr/lib/libg.a, qui est la bibliothque C standard
   permettant le dbogage. Cette bibliothque est fournie dans le
   paquetage des binaires de la libc., ou (dans les nouvelles versions)
   vous aurez besoin de rcuprer le source et de le compiler vous-mme.
   Vous n'avez pas rellement besoin de cela en fait, vous pouvez faire
   un lien logique vers /usr/lib/libc.a

  Comment rduire la taille des excutables ?

   Bon nombre de produits GNU sont fournis pour compiler avec l'option
   -g, ce qui gnre des excutables d'une taille trs importante (et
   souvent l'dition de liens s'effectue d'une manire statique). Ce
   n'est pas une ide lumineuse...

   Si le programme possde le script configure gnr par autoconf, vous
   pouvez modifier les options de dbogage en effectuant un ./configure
   CFLAGS= ou ./configure CFLAGS=-O2. Sinon, vous pouvez aller modifier
   le Makefile. Bien sr, si vous utilisez le format ELF, l'dition de
   liens sera effectue de manire dynamique mme avec l'option -g. Dans
   ce cas, vous pouvez effectuer un strip sur l'excutable.

  Programmes disponibles

   Beaucoup de gens utilisent _gdb_, que vous pouvez rcuprer sur le
   site prep.ai.mit.edu, sous une forme binaire sur tsx-11 ou sur
   sunsite. _xxgdb_ est une surcouche X de gdb (c.a.d. que vous avez
   besoin de gdb pour utiliser xxgdb). Les sources peuvent tre rcuprs
   sur ftp://ftp.x.org/contrib/xxgdb-1.08.tar.gz

   Il existe galement le dbogueur _UPS_ qui a t port par Rick
   Sladkey. Il fonctionne sous X galement, mais  la diffrence d'xxgdb,
   ce n'est qu'une surcouche X pour un dbogueur en mode en texte. Il
   possde certaines caractristiques trs intressantes et si vous
   utilisez beaucoup ce genre d'outils, vous l'essayerez srement. Les
   patches ainsi que des versions prcompiles pour Linux peuvent tre
   trouves sur ftp://sunsite.unc.edu/pub/Linux/devel/debuggers/, et les
   sources peuvent tre rcuprs sur
   ftp://ftp.x.org/contrib/ups-2.45.2.tar.Z.

   Un autre outil que vous pouvez trouver utile pour dboguer est 
   _strace_  , qui affiche les appels systmes que le processus lance. Il
   possde d'autres caractristiques telles que donner les chemins
   d'accs o ont t compils les binaires, donner les temps passs dans
   chacun des appels systmes, et il vous permet galement de connatre
   les rsultats des appels. La dernire version de strace (actuellement
   la version 3.0.8) peut tre trouve sur ftp://ftp.std.com/pub/jrs/.

  Programmes en tche de fond (dmon)

   Les dmons lancent typiquement un fork() ds leur lancement et
   terminent donc le pre. Cela fait une session de dboguage trs
   courte.

   La manire la plus simple de rsoudre ce problme est de poser un
   point d'arrt sur fork, et lorsque le programme s'arrte, forcer le
   retour  0.

(gdb) list
1       #include <stdio.h>
2
3       main()
4       {
5         if(fork()==0) printf("child\n");
6         else printf("parent\n");
7       }
(gdb) break fork
Breakpoint 1 at 0x80003b8
(gdb) run
Starting program: /home/dan/src/hello/./fork
Breakpoint 1 at 0x400177c4

Breakpoint 1, 0x400177c4 in fork ()
(gdb) return 0
Make selected stack frame return now? (y or n) y
#0  0x80004a8 in main ()
    at fork.c:5
5         if(fork()==0) printf("child\n");
(gdb) next
Single stepping until exit from function fork,
which has no line number information.
child
7       }

  Fichiers core

   Lorsque Linux se lance, il n'est gnralement pas configur pour
   produire des fichiers core. Si vous les voulez vous devez utiliser
   votre shell pour a en faisant sous csh (ou tcsh) :

% limit core unlimited

   avec sh, bash, zsh, pdksh, utilisez

$ ulimit -c unlimited

   Si vous voulez pousser le vice  nommer votre fichier core (par
   exemple si vous utilisez un dbogueur bogu... ce qui est un comble)
   vous pouvez simplement modifier le noyau. Editez les fichiers
   fs/binfmt_aout.c et fs/binfmt_elf.c (dans les nouveaux noyaux, vous
   devrez chercher ailleurs) :

        memcpy(corefile,"core.",5);
#if 0
        memcpy(corefile+5,current->comm,sizeof(current->comm));
#else
        corefile[4] = '\0';
#endif

   et changez les 0 par des 1.

5.3 Caractristiques du programme

   Il est possible d'examiner un peu le programme pour savoir quels sont
   les appels de fonctions qui sont effectus le plus souvent ou bien qui
   prennent du temps. C'est une bonne manire d'optimiser le code en
   dterminant l o l'on passe le plus de temps. Vous devez compiler
   tous les objets avec l'option -p, et pour mettre en forme la sortie
   cran, vous aurez besoin du programme gprof (situ dans les binutils).
   Consultez les pages de manuel gprof pour plus de dtails.

6. Edition de liens

   Entre les deux formats de binaires incompatibles, bibliothques
   statiques et dynamiques, on peut comparer l'opration d'dition de
   lien en fait  un jeu ou l'on se demanderait qu'est-ce qui se passe
   lorsque je lance le programme ? Cette section n'est pas vraiment
   simple...

   Pour dissiper la confusion qui rgne, nous allons nous baser sur ce
   qui se passe lors d'excution d'un programme, avec le chargement
   dynamique. Vous verrez galement la description de l'dition de liens
   dynamiques, mais plus tard. Cette section est ddie  l'dition de
   liens qui intervient  la fin de la compilation.

6.1 Bibliothques partages contre bibliothques statiques

   La dernire phase de construction d'un programme est de raliser
   l'dition de liens, ce qui consiste  assembler tous les morceaux du
   programme et de chercher ceux qui sont manquants. Bien videment,
   beaucoup de programmes ralisent les mmes oprations comme ouvrir des
   fichiers par exemple, et ces pices qui ralisent ce genre
   d'oprations sont fournies sous la forme de bibliothques. Sous Linux,
   ces bibliothques peuvent tre trouves dans les rpertoires /lib
   et/usr/lib/ entre autres.

   Lorsque vous utilisez une bibliothque statique, l'diteur de liens
   cherche le code dont votre programme a besoin et en effectue une copie
   dans le programme physique gnr. Pour les bibliothques partages,
   c'est le contraire : l'diteur de liens laisse du code qui lors du
   lancement du programme chargera automatiquement la bibliothque. Il
   est vident que ces bibliothques permettent d'obtenir un excutable
   plus petit; elles permettent galement d'utiliser moins de mmoire et
   moins de place disque. Linux effectue par dfaut une dition de liens
   dynamique s'il peut trouver les bibliothques de ce type sinon, il
   effectue une dition de liens statique. Si vous obtenez des binaires
   statiques alors que vous les voulez dynamiques vrifiez que les
   bibliothques existent (*.sa pour le format a.out, et *.so pour le
   format ELF) et que vous possdez les droits suffisants pour y accder
   (lecture).

   Sous Linux, les bibliothques statiques ont pour nom libnom.a, alors
   que les bibliothques dynamiques sont appeles libnnom.so.x.y.z o
   x.y.z reprsente le numro de version. Les bibliothques dynamiques
   ont souvent des liens logiques qui pointent dessus, et qui sont trs
   importants. Normalement, les bibliothques standards sont livres sous
   la double forme dynamique et statique.

   Vous pouvez savoir de quelles bibliothques dynamiques un programme a
   besoin en utilisant la commande ldd (_List Dynamic Dependencies_)

$ ldd /usr/bin/lynx
        libncurses.so.1 => /usr/lib/libncurses.so.1.9.6
        libc.so.5 => /lib/libc.so.5.2.18

   Cela indique sur mon systme que l'outil lynx (outil WWW) a besoin des
   bibliothques dynamiques libc.so.5 (la bibliothque C) et de
   libncurses.so.1 (ncessaire pour le contrle du terminal). Si un
   programme ne possde pas de dpendances, ldd indiquera `_statically
   linked_' (dition de liens statique).

6.2 A la recherche des fonctions... ou dans quelle bibliothque se trouve la
fonction sin() ?')

   nm _nomdebibliothque_ vous donne tous les symboles rfrencs dans la
   bibliothque. Cela fonctionne que cela soit du code statique ou
   dynamique. Supposez que vous vouliez savoir o se trouve dfinie la
   fonction tcgetattr() :

$ nm libncurses.so.1 |grep tcget
         U tcgetattr

   La lettre U vous indique que c'est indfini (_Undefined_) --- cela
   indique que la bibliothque ncurses l'utilise mais ne la dfinit pas.
   Vous pouvez galement faire :

$ nm libc.so.5 | grep tcget
00010fe8 T __tcgetattr
00010fe8 W tcgetattr
00068718 T tcgetpgrp

   La lettre `W' indique que le symbole est dfini mais de telle manire
   qu'il peut tre surcharg par une autre dfinition de la fonction dans
   une autre bibliothque (W pour _weak_ : faible). Une dfinition
   normale est marque par la lettre `T' (comme pour tcgetpgrp).

   La rponse  la question situe dans le titre est libm.(so|a). Toutes
   les fonctions dfinies dans le fichier d'en-tte <math.h> sont
   implmentes dans la bibliothque mathmatique donc vous devrez
   effectuer l'dition de liens grce  -lm.

6.3 Trouver les fichiers

   Supposons que vous ayez le message d'erreur suivant de la part de
   l'diteur de liens :

   ld: Output file requires shared library `libfoo.so.1`

   La stratgie de recherche de fichiers de ld ou de ses copains diffre
   de la version utilise, mais vous pouvez tre sr que les fichiers
   situs dans le rpertoire /usr/lib seront trouvs. Si vous dsirez que
   des fichiers situs  un endroit diffrent soient trouvs, il est
   prfrable d'ajouter l'option -L  gcc ou ld.

   Si cela ne vous aide pas clairement, vrifiez que vous avez le bon
   fichier  l'endroit spcifi. Pour un systme a.out, effectuer
   l'dition de liens avec -ltruc implique que ld recherche les
   bibliothques libtruc.sa (bibliothques partages), et si elle
   n'existe pas, il recherche libtruc.a (statique). Pour le format ELF,
   il cherche libtruc.so puis libtruc.a. libtruc.so est gnralement un
   lien symbolique vers libtruc.so.x.

6.4 Compiler votre propre bibliothque

  Numro de la version

   Comme tout programme, les bibliothques ont tendance  avoir quelques
   bogues qui sont corrigs au fur et  mesure. De nouvelles
   fonctionnalits sont ajoutes et qui peuvent changer l'effet de celles
   qui existent ou bien certaines anciennes peuvent tres supprimes.
   Cela peut tre un problme pour les programmes qui les utilisent.

   Donc, nous introduisons la notion de numro de version. Nous
   rpertorions les modifications effectues dans la bibliothques comme
   tant soit mineures soit majeures. Cela signifie qu'une modification
   mineure ne peut pas modifier le fonctionnement d'un programme (en
   bref, il continue  fonctionner comme avant). Vous pouvez identifier
   le numro de la version de la bibliothque en regardant son nom (en
   fait c'est un mensonge pour les bibliothques ELF... mais continuez 
   faire comme si !) : libtruc.so.1.2 a pour version majeure 1 et mineure
   2. Le numro de version mineur peut tre plus ou moins lev --- la
   bibliothque C met un numro de patch, ce qui produit un nom tel que
   libc.so.5.2.18, et c'est galement courant d'y trouver des lettres ou
   des blancs souligns ou tout autre caractre ASCII affichable.

   Une des principales diffrences entre les formats ELF et a.out se
   trouve dans la manire de construire la bibliothque partage. Nous
   traiterons les bibliothques partages en premier car c'est plus
   simple.

  ELF, qu'est-ce que c'est ?

   ELF (_Executable and Linking Format_) est format de binaire
   initialement conu et dvelopp par USL (_UNIX System Laboratories_)
   et utilis dans les systmes Solaris et System R4. En raison de sa
   facilit d'utilisation par rapport  l'ancien format dit a.out
   qu'utilisait Linux, les dveloppeurs de GCC et de la bibliothque C
   ont dcid l'anne dernire de basculer tout le systme sous le format
   ELF. ELF est dsormais le format binaire standard sous Linux.

  ELF, le retour !

   Ce paragraphe provient du groupe '/news-archives/comp.sys.sun.misc'.

     ELF (_Executable Linking Format_) est le  nouveau et plus
     performant  format de fichier introduit dans SVR4. ELF est
     beaucoup plus puissant que le sacro-saint format COFF, dans le sens
     o il est extensible. ELF voit un fichier objet comme une longue
     liste de sections (plutt qu'un tableau de taille fixe d'lments).
     Ces sections,  la diffrence de COFF ne se trouvent pas  un
     endroit constant et ne sont pas dans un ordre particulier, etc. Les
     utilisateurs peuvent ajouter une nouvelle section  ces fichiers
     objets s'il dsirent y mettre de nouvelles donnes. ELS possde un
     format de dbogage plus puissant appel DWARF (_Debugging With
     Attribute Record Format_) - par encore entirement gr par Linux
     (mais on y travaille !). Une liste chane de  DWARF DIEs  (ou
     _Debugging Information Entries_ - NdT... le lecteur aura srement
     not le jeu de mot assez noir : dwarf = nain; dies = morts) forment
     la section _.debug_ dans ELF. Au lieu d'avoir une liste de petits
     enregistrements d'information de taille fixes, les DWARF DIEs
     contiennent chacun une longue liste complexe d'attributs et sont
     crits sous la forme d'un arbre de donnes. Les DIEs peuvent
     contenir une plus grande quantit d'information que la section
     _.debug_ du format COFF ne le pouvait (un peu comme les graphes
     d'hritages du C++).

     Les fichiers ELF sont accessibles grce  la bibliothque d'accs
     de SVR4 (Solaris 2.0 peut-tre ?), qui fournit une interface simple
     et rapide aux parties les plus complexes d'ELF. Une des aubaines
     que permet la bibliothque d'accs ELF est que vous n'avez jamais
     besoin de connatre les mandres du format ELF. Pour accder  un
     fichier Unix, on utilise un Elf *, retourn par un appel 
     elf_open(). Ensuite, vous effectuez des appels  elf_foobar() pour
     obtenir les diffrents composants au lieu d'avoir  triturer le
     fichier physique sur le disque (chose que beaucoup d'utilisateurs
     de COFF ont fait...).

   Les arguments pour ou contre ELF, et les problmes lis  la mise 
   jour d'un systme a.out vers un systme ELF sont dcrits dans le
   ELF-HOWTO et je ne veux pas effectuer de copier coller ici (NdT: ce
   HowTo est galement traduit en franais). Ce HowTo se trouve au mme
   endroit que les autres.

  Les bibliothque partages ELF

   Pour construire libtruc.so comme une bibliothque dynamique, il suffit
   de suivre les tapes suivantes :

$ gcc -fPIC -c *.c
$ gcc -shared -Wl,-soname,libtruc.so.1 -o libtruc.so.1.0 *.o
$ ln -s libtruc.so.1.0 libtruc.so.1
$ ln -s libtruc.so.1 libtruc.so
$ LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH ; export LD_LIBRARY_PATH

   Cela va gnrer une bibliothque partage appele libtruc.so.1.0, les
   liens appropris pour ld (libtruc.so) et le chargeur dynamique
   (libtruc.so.1) pour le trouver. Pour tester, nous ajoutons le
   rpertoire actuel  la variable d'environnement LD_LIBRARY_PATH.

   Lorsque vous tes satisfait et que la bibliothque fonctionne, vous
   n'avez plus qu' la dplacer dans le rpertoire par exemple,
   /usr/local/lib, et de recrer les liens appropris. Le lien de
   libtruc.so.1 sur libtruc.so.1.0 est enregistr par ldconfig, qui sur
   bon nombre de systmes est lanc lors du processus d'amorage. Le lien
   libfoo.so doit tre mis  jour  la main. Si vous faites attention
   lors de la mise  jour de la bibliothque la chose la plus simple 
   raliser est de crer le lien libfoo.so -> libfoo.so.1, pour que
   ldconfig conserve les liens actuels. Si vous ne faites pas cela, vous
   aurez des problmes plus tard. Ne me dites pas que l'on ne vous a pas
   prvenu !

$ /bin/su
# cp libtruc.so.1.0 /usr/local/lib
# /sbin/ldconfig
# ( cd /usr/local/lib ; ln -s libtruc.so.1 libtruc.so )

  Les numros de version, les noms et les liens

   Chaque bibliothque possde un nom propre (_soname_). Lorsque
   l'diteur de liens en trouve un qui correspond  un nom cherch, il
   enregistre le nom de la bibliothque dans le code binaire au lieu d'y
   mettre le nom du fichier de la bibliothque. Lors de l'excution, le
   chargeur dynamique va alors chercher un fichier ayant pour nom le nom
   propre de la bibliothque, et pas le nom du fichier de la
   bibliothque. Par exemple, une bibliothque ayant pour nom libtruc.so
   peut avoir comme nom propre libbar.so, et tous les programmes lis
   avec vont alors chercher libbar.so lors de leur excution.

   Cela semble tre une nuance un peu pointilleuse mais c'est la clef de
   la comprhension de la coexistence de plusieurs versions diffrentes
   de la mme bibliothque sur le mme systme. On a pour habitude sous
   Linux d'appeler une bibliothque libtruc.so.1.2 par exemple, et de lui
   donner comme nom propre libtruc.so.1. Si cette bibliothque est
   rajoute dans un rpertoire standard (par exemple dans /usr/lib), le
   programme ldconfig va crer un lien symbolique entre libtruc.so.1 ->
   libtruc.so.1.2 pour que l'image approprie soit trouve lors de
   l'excution. Vous aurez galement besoin d'un lien symbolique
   libtruc.so -> libtruc.so.1 pour que ld trouve le nom propre lors de
   l'dition de liens.

   Donc, lorsque vous corrigez des erreurs dans la bibliothque ou bien
   lorsque vous ajoutez de nouvelles fonctions (en fait, pour toute
   modification qui n'affecte pas l'excution des programmes dj
   existants), vous reconstruisez la bibliothque, conservez le nom
   propre tel qu'il tait et changez le nom du fichier. Lorsque vous
   effectuez des modifications que peuvent modifier le droulement des
   programmes existants, vous pouvez tout simplement incrmenter le
   nombre situ dans le nom propre --- dans ce cas, appelez la nouvelle
   version de la bibliothque libtruc.so.2.0, et donnez-lui comme nom
   propre libtruc.so.2. Maintenant, faites pointer le lien de libfoo.so
   vers la nouvelle version et tout est bien dans le meilleur des mondes
   !

   Il est utile de remarquer que vous n'tes pas oblig de nommer les
   bibliothques de cette manire, mais c'est une bonne convention. Elf
   vous donne une certaine libert pour nommer des bibliothques tant et
   si bien que cela peut perturber certains utilisateurs, mais cela ne
   veut pas dire que vous tes oblig de le faire.

   Rsum : supposons que choisissiez d'adopter la mthode traditionnelle
   avec les mises  jour majeures qui peuvent ne pas tre compatibles
   avec les versions prcdentes et les mises  jour mineures qui ne
   posent pas ce problme. Il suffit de crer la bibliothque de cette
   manire :

gcc -shared -Wl,-soname,libtruc.so.majeur -o libtruc.so.majeur.mineur

   et tout devrait tre parfait !

  a.out. Le bon vieux format

   La facilit de construire des bibliothque partages est la raison
   principale de passer  ELF. Ceci dit, il est toujours possible de
   crer des bibliothques dynamiques au format a.out. Rcuprez le
   fichier archive
   ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.17.tar.gz et
   lisez les 20 pages de documentation que vous trouverez dedans aprs
   l'avoir dsarchiv. Je n'aime pas avoir l'air d'tre aussi partisan,
   mais il est clair que je n'ai jamais aim ce format :-).

  ZMAGIC contre QMAGIC

   QMAGIC est le format des excutables qui ressemble un peu aux vieux
   binaires a.out (galement connu comme ZMAGIC), mais qui laisse la
   premire page libre. Cela permet plus facilement de rcuprer les
   adresses non affectes (comme NULL) dans l'intervalle 0-4096 (NdT :
   Linux utilise des pages de 4Ko).

   Les diteurs de liens dsuets ne grent que le format ZMAGIC, ceux un
   peu moins rustiques grent les deux, et les plus rcents uniquement le
   QMAGIC. Cela importe peu car le noyau gre les deux types.

   La commande file est capable d'identifier si un programme est de type
   QMAGIC.

  Gestion des fichiers

   Une bibliothque dynamique a.out (DLL) est compose de deux fichiers
   et d'un lien symbolique. Supposons que l'on utilise la bibliothque
   _truc_, les fichiers seraient les suivants : libtruc.sa et
   libtruc.so.1.2; et le lien symbolique aurait pour nom libtruc.so.1 et
   pointerait sur le dernier des fichiers. Mais  quoi servent-ils ?

   Lors de la compilation, ld cherche libtruc.sa. C'est le fichier de
   description de la bibliothque : il contient toutes les donnes
   exportes et les pointeurs vers les fonctions ncessaires pour
   l'dition de liens.

   Lors de l'excution, le chargeur dynamique cherche libtruc.so.1. C'est
   un lien symbolique plutt qu'un rel fichier pour que les
   bibliothques puissent tre mise  jour sans avoir  casser les
   applications qui utilisent la bibliothque. Aprs la mise  jour,
   disons que l'on est pass  la version libfoo.so.1.3, le lancement de
   ldconfig va positionner le lien. Comme cette opration est atomique,
   aucune application fonctionnant n'aura de problme.

   Les bibliothques DLL (Je sais que c'est une tautologie... mais pardon
   !) semblent tre trs souvent plus importantes que leur quivalent
   statique. En fait, c'est qu'elles rservent de la place pour les
   extensions ultrieures sous la simple forme de trous qui sont fait de
   telle manire qu'ils n'occupent pas de place disque (NdT : un peu
   comme les fichiers core). Toutefois, un simple appel  cp ou 
   makehole les remplira... Vous pouvez effectuer une opration de strip
   aprs la construction de la bibliothque, comme les adresses sont 
   des endroits fixes. _Ne faites pas la mme opration avec les
   bibliothques ELF !_

   libc-lite  ?

   Une  libc-lite  (contraction de _libc_ et _little_) est une version
   pure et rduite de la bibliothque libc construite de telle manire
   qu'elle puisse tenir sur une disquette avec un certain nombre d'outil
   Unix. Elle n'inclut pas curses, dbm, termcap, ... Si votre
   /lib/libc.so.4 est lie avec une bibliothque de ce genre il est trs
   fortement conseill de la remplacer avec une version complte.

  Edition de liens : problme courants

   Envoyez-les moi !

   _Des programmes statiques lorsque vous les voulez partags_
          Vrifiez que vous avez les bons liens pour que ld puisse
          trouver les bibliothques partages. Pour ELF cela veut dire
          que libtruc.so est un lien symbolique sur son image, pour a.out
          un fichier libtruc.sa. Beaucoup de personnes ont eu ce problme
          aprs tre passs des outils ELF 2.5  2.6 (binutils) --- la
          dernire version effectue une recherche plus intelligente pour
          les bibliothques dynamiques et donc ils n'avaient pas cr
          tous les liens symboliques ncessaires. Cette caractristique
          avait t supprime pour des raisons de compatibilit avec
          d'autres architectures et parce qu'assez souvent cela ne
          marchait pas bien. En bref, cela posait plus de problmes
          qu'autre chose.

   _Le programme `mkimage' n'arrive pas  trouver libgcc_
          Comme libc.so.4.5.x et suivantes, libgcc n'est pas une
          bibliothque partage. Vous devez remplacer les `-lgcc' sur la
          ligne de commande par `gcc -print-libgcc-file-name` (entre
          quotes)

          Egalement, dtruisez tous les fichiers situs dans
          /usr/lib/libgcc*. C'est important.

   _Le message __NEEDS_SHRLIB_libc_4 multiply defined_
          Sont une consquence du mme problme.

   _Le message ``Assertion failure'' apparat lorsque vous reconstruisez
          une DLL_
          Ce message nigmatique signifie qu'un lment de votre table
          _jump_ a dpass la table car trop peu de place tait rserve
          dans le fichier jump.vars file. Vous pouvez trouver le(s)
          coupable(s) en lanant la commande getsize fournie dans le
          paquetage tools-2.17.tar.gz. La seule solution est de passer 
          une nouvelle version majeure, mme si elle sera incompatible
          avec les prcdentes.

   _ld: output file needs shared library libc.so.4 _
          Cela arrive lorsque vous effectuez l'dition de liens avec des
          bibliothques diffrentes de la libc (comme les bibliothques
          X) et que vous utilisez l'option -g sans utiliser l'option
          -static.

          Les fichiers .sa pour les bibliothques dynamiques ont un
          symbole non rsolu _NEEDS_SHRLIB_libc_4 qui est dfini dans
          libc.sa. Or, lorsque vous utilisez -g vous faites l'dition de
          liens avec libg.a ou libc.a et donc ce symbole n'est jamais
          dfini.

          Donc, pour rsoudre le problme, ajoutez l'option -static
          lorsque vous compilez avec l'option -g, ou n'utilisez pas -g
          lors de l'dition de liens !

7. Chargement dynamique

   _Ce paragraphe est en fait un peu court : il sera tendu dans une
   version ultrieure ds que j'aurai rcupr le HowTo ELF_

7.1 Concepts

   Linux possde des bibliothques dynamiques, comme on vous le rpte
   depuis le dbut de ce document ! Or, il existe un systme pour
   reporter le travail d'association des noms des symboles et de leur
   adresse dans la bibliothque, qui est normalement effectu lors de
   l'dition de liens en l'effectuant lors du chargement du programme.

7.2 Messages d'erreur

   Envoyez moi vos erreurs ! Je n'en fait pas grand chose sauf les
   insrer dans ce paragraphe...

   _can't load library: /lib/libxxx.so, Incompatible version_
          (seulement a.out) Cela signifie que vous n'avez pas la version
          correcte de la bibliothque (numro dit majeur). Non, il n'est
          pas possible d'effectuer un lien symbolique sur la bibliothque
          que vous possdez : si vous avez de la chance, vous obtiendrez
          un _segmentation fault_. Rcuprez la nouvelle version. Un
          message un peu quivalent existe galement sur les systmes ELF
          :

ftp: can't load library 'libreadline.so.2'

   _warning using incompatible library version xxx_
          (seulement a.out) Vous avez un numro de version de
          bibliothque (mineur) infrieur  la version avec laquelle a
          t compil le programme. Le programme fonctionnera srement.
          Une mise  jour est toutefois conseille.

7.3 Contrler l'opration de chargement dynamique

   Il existe certaines variables d'environnements que le chargeur
   dynamique utilise. Beaucoup sont exploites par le programme ldd
   lorsqu'il s'agit de particularits de l'environnement de
   l'utilisateur, ce qui peuvent tre positionnes pour lancer ldd avec
   des options particulires. Voici une description des diffrentes
   variables d'environnement que vous pouvez rencontrer :

     * LD_BIND_NOW --- normalement, les fonctions ne sont pas cherches
       dans les bibliothques avant leur appel. En positionnant cette
       option, vous vrifiez que toutes les fonctions employes dans
       votre programmes se trouvent bien dans la bibliothque lors de son
       chargement, ce qui ralentit le lancement du programme. C'est utile
       lorsque vous voulez tester que l'dition de liens s'est
       parfaitement droule et que tous les symboles sont bien associs.
     * LD_PRELOAD peut tre dfini avec un nom de fichier qui contient
       des fonctions surchargeant des fonctions dj existantes. Par
       exemple, si vous testez une stratgie d'allocation mmoire, et que
       vous voulez remplacer le malloc de la bibliothque C par le vtre
       situ dans un module ayant pour nom malloc.o, il vous suffit de
       faire :

$ export LD_PRELOAD=malloc.o
$ test_mon_malloc

       LD_ELF_PRELOAD et LD_AOUT_PRELOAD sont similaires, mais leur
       utilisation est spcifique au type de binaire utilis. Si
       LD__TypeBinaire__PRELOAD et LD_PRELOAD sont positionns, celui
       correspondant le mieux  la machine est utilis.
     * LD_LIBRARY_PATH contient une liste de rpertoires contenant les
       bibliothques dynamiques. Cela n'affecte pas l'dition de liens :
       cela n'a qu'un effet lors de l'excution. Il faut noter qu'elle
       est dsactive pour des programmes qui s'excutent avec un setuid
       ou un setgid. Enfin, LD_ELF_LIBRARY_PATH et LD_AOUT_LIBRARY_PATH
       peuvent tre utiliss pour orienter le mode de compilation du
       binaire. LD_LIBRARY_PATH ne devrait pas tre ncessaire en
       principe : ajoutez les rpertoires dans le fichier
       /etc/ld.so.conf/ et relancez ldconfig.
     * LD_NOWARN s'applique au format a.out uniquement. Lorsqu'elle est
       positionne (c.a.d si elle existe par exemple avec LD_NOWARN=true;
       export LD_NOWARN) cela arrte le chargeur du programme mme sur
       des avertissements insignifiants (tels que des messages
       d'incompatibilits de numros mineurs de version).
     * LD_WARN s'applique  ELF uniquement. Lorsqu'elle est positionne,
       on transforme le message habituellement fatal _Can't find library_
       en un avertissement. Ce n'est pas positionn par dfaut mais c'est
       important pour un programme comme ldd.
     * LD_TRACE_LOADED_OBJECTS s'applique  ELF uniquement, et permet de
       simuler l'excution des programmes comme s'ils l'taient par ldd :

$ LD_TRACE_LOADED_OBJECTS=true /usr/bin/lynx
        libncurses.so.1 => /usr/lib/libncurses.so.1.9.6
        libc.so.5 => /lib/libc.so.5.2.18

7.4 Ecrire des programmes en utilisant le chargement dynamique

   Cela ressemble normment au systme de chargement dynamique utilis
   sous Solaris 2.x. Ce systme est dcrit d'une manire prcise dans le
   document expliquant la programmation avec ELF crit par H J Lu et dans
   la page de manuel dlopen(3), qui se trouve dans le paquetage ld.so.
   Voici un exemple simple : pensez  faire l'dition de liens avec -ldl

#include <dlfcn.h>
#include <stdio.h>

main()
{
  void *libc;
  void (*printf_call)();

  if(libc=dlopen("/lib/libc.so.5",RTLD_LAZY))
  {
    printf_call = dlsym(libc,"printf");
    (*printf_call)("Bonjour ! Ha ben ca marche pil poil sous Linux !\n");
  }

}

8. Contacter les dveloppeurs

8.1 Annoncer des bogues

   Commencez par mettre en doute le problme. Est-ce spcifique  Linux
   ou bien cela arrive avec gcc mais sur d'autres plates-formes ? Est-ce
   spcifique  la version du noyau ? A la version de la bibliothque C ?
   Est-ce que ce problme disparat lorsque vous effectuez une dition de
   liens statique ? Pouvez-vous produire un code trs court mettant en
   vidence le problme ?

   Aprs avoir rpondu aprs ces quelques questions, vous saurez quel
   programme est  l'origine du problme. Pour un problme direct avec
   GCC, le mieux est de consulter le fichier d'information livr avec :
   la procdure pour rapporter un bogue y est dtaill. Pour un problme
   avec ld.so, la bibliothque C ou mathmatique, envoyez un courrier
   lectronique  linux-gcc@vger.rutgers.edu. Si possible, donnez un
   court exemple mettant en vidence le problme ainsi qu'une courte
   description indiquant ce que le programme aurait normalement d faire,
   et ce qu'il fait en ralit.

8.2 Participer au dveloppement

   Si vous dsirez participer au dveloppement de GCC ou de la
   bibliothque C, la premire chose  faire est de rejoindre la liste de
   diffusion linux-gcc@vger.rutgers.edu. Si vous dsirez uniquement
   savoir de quoi a parle, il existe des archives  l'adresse
   http://homer.ncm.com/linux-gcc/. Tout dpend de ce que vous dsirez
   faire ou apporter  ce projet !

9. Divers

9.1 Ce document

   Ce HowTo est bas sur la FAQ de Mitchum DSouza's. Bon nombre des
   informations en proviennent. D'une manire gnrale, il est frquent
   de dire une phrase du genre  je n'ai pas tout test et donc ne me
   blmez pas si vous cassez votre disque, votre systme ou si vous
   rompez avec votre pouse .

   Le nom des contributeurs  ce document sont donns par ordre
   alphabtique : Andrew Tefft, Axel Boldt, Bill Metzenthen, Bruce Evans,
   Bruno Haible, Daniel Barlow, Daniel Quinlan, David Engel, Dirk
   Hohndel, Eric Youngdale, Fergus Henderson, H.J. Lu, Jens Schweikhardt,
   Kai Petzke, Michael Meissner, Mitchum DSouza, Olaf Flebbe, Paul
   Gortmaker, Rik Faith, Steven S. Dick, Tuomas J Lukka, et bien sr
   Linus Torvalds, sans qui ce genre d'exercice aurait t difficile,
   voir impossible :-)

   Ne soyez pas offens si votre nom n'apparat pas dans la liste et que
   vous ayez contribu  ce document (sous la forme d'un HowTo ou d'une
   FAQ). Envoyez-moi un courrier lectronique et j'effectuerai la
   correction.

9.2 Traduction

   A l'heure ou j'cris ces lignes, je ne connais pas de traduction de ce
   document. Si vous en ralisez une, s'il vous plat dites-le moi. Je
   suis disponible pour toute aide concernant l'explication du texte, je
   serai trs content d'y rpondre.

   Note du traducteur : _Cocorico !_ La version franaise est la premire
   traduction de ce document.

9.3 Contacts

   Tout contact est le bienvenu. Envoyez-moi un courrier lectronique 
   l'adresse suivante : dan@detached.demon.co.uk. Ma clef publique PGP
   (ID 5F263625) est disponible sur mes pages WWW, Si vous souhaitez
   rendre confidentiel certains messages.

9.4 Copyright

   Toutes les remarques appartiennent  leurs auteurs respectifs.

   Ce document est copyright (C) 1996 Daniel Barlow
   <dan@detached.demon.co.uk>. Il peut tre reproduit et distribu en
   partie ou entirement, sur tout support physique ou lectronique, du
   moment o ce copyright se trouve sur toute les copies. La
   redistribution commerciale est autorise et encourage. Toutefois
   l'auteur de ce document doit tre mis au courant de ce genre de
   distributions.

   Toute traduction, adaptation, ou bien tout travail incorporant tout
   document HowTo Linux doit possder ce copyright. De cette manire,
   vous ne pouvez pas imposer de restriction  la distribution de ce
   document. Des exceptions peuvent tre ventuellement accordes sous
   certaines conditions : contactez le coordinateur des HowTo's Linux 
   l'adresse donne ci-dessous.

   En rsum, nous souhaitons voir diffuser l'information de la manire
   la plus large qui soit. Toutefois, nous souhaitons garder la matrise
   de ces documents et nous aimerions tre consults avant toute
   diffusion des HowTo's.

   Si vous avez des questions, vous pouvez contacter Greg Hankins, le
   coordinateur des HowTo Linux HOWTO  l'adresse lectronique suivante :
   gregh@sunsite.unc.edu

10. Index

   Les entres de cet index sont tries dans l'ordre alphabtique.

     * -fwritable-strings 39, 56
     * /lib/cpp 16
     * a.out 1
     * ar 10
     * as 8
     * <asm/*.h> 19
     * atoi() 40
     * atol() 41
     * excutables trop gros 63, 65, 77
     * chewing gum 3
     * cos() 68
     * deboguer 59
     * divers 72
     * dlopen() 82
     * dlsym() 83
     * documentation 4
     * EINTR 52
     * elf 0, 71
     * execl() 57
     * fcntl 47
     * FD_CLR 44
     * FD_ISSET 45
     * FD_SET 43
     * FD_ZERO 46
     * fichier 2
     * <float.h> 20
     * gcc 6
     * gcc -fomit-frame-pointer 61
     * gcc -g 60
     * gcc -v 14
     * gcc, bogues 15, 28, 29, 84
     * gcc, options de compilation 13, 25, 26
     * gdb 64
     * fichiers d'en-tte 17
     * appels systmes interrompus 51
     * ld 9
     * LD_* : variables d'environnement 80
     * ldd 81
     * libc 7
     * libg.a 62
     * libgcc 79
     * <limits.h> 21
     * lint 58
     * <linux/*.h> 18
     * <math.h> 70
     * maths 69
     * mktemp() 55
     * numro de version 12, 74
     * optimisation 27
     * pages de manuel 5
     * QMAGIC 76
     * segmentation fault 30, 54
     * segmentation fault, in GCC 33
     * select() 50
     * SIGBUS 34
     * SIGEMT 35
     * SIGIOT 36
     * SIGSEGV 31, 53
     * SIGSEGV, in gcc 32
     * SIGSYS 38
     * SIGTRAP 37
     * sin() 67
     * soname 73
     * sprintf() 42
     * binaires links statiquement 66, 78
     * <stdarg.h> 23
     * <stddef.h> 24
     * strings 11
     * <sys/time.h> 48
     * <unistd.h> 49
     * <varargs.h> 22
     * ZMAGIC 75
