  GCC HOWTO pour Linux
  par Daniel Barlow <dan@detached.demon.co.uk>
  v1.17, 28 fevrier 1996

  (Adaptation  francaise  par  Eric  Dumas  <dumas@freenix.fr>,  8 Avril
  1996).  Ce document presente la maniere de configurer  le  compilateur
  GNU  C  et  les bibliotheques de developpement sous Linux. Il donne un
  apercu de la compilation, de l'edition de liens, de l'execution et  du
  debogage  de programmes sous Linux. Bon nombre de passages de ce docu-
  ment sont empruntes a la FAQ GCC redigee par  Mitch  D'Souza's  et  au
  HowTo  ELF.  Ceci est la premiere version publique (en depit du numero
  de version : en fait, ca vient de RCS). N'hesitez  pas  a  me  joindre
  pour toute remarque.

  11..  PPrreelliimmiinnaaiirreess

  11..11..

  EELLFF eett aa..oouutt

  Le   developpement  de  Linux  est  actuellement  dans  une  phase  de
  transition.  En resume, il existe deux formats de binaires  que  Linux
  reconnait  et execute, et cela depend de la maniere dont votre systeme
  est configure : vous pouvez avoir les deux, l'un ou l'autre. En lisant
  ce  document,  vous  pourrez  savoir  quels binaires votre systeme est
  capable de gerer.

  Comment le savoir ? Utilisez  la  commande  file  (par  exemple,  file
  /bin/bash).  Pour  un  programme  ELF, cette commande va vous repondre
  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 differences entre ELF et a.out sont detaillees plus tard  dans  ce
  document.  ELF  est  le nouveau format et il est considere comme etant
  meilleur.

  11..22..

  DDuu ccoottee dduu ccooppyyrriigghhtt

  Le copyright et autres informations legales peuvent etre trouves a  la
  _f_i_n  de ce document, avec les avertissements conventionnels concernant
  la maniere de poser des questions sur Usenet  pour  eviter  d'avoir  a
  reveler  votre ignorance du langage C en annoncant des bogues qui n'en
  sont pas, etc.

  11..33..  TTyyppooggrraapphhiiee

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

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

  L'interpreteur  de  commande (_s_h_e_l_l) utilise dans les exemples sera la
  Bourne shell (plutot que le  C-Shell).  Les  utilisateurs  du  C-Shell
  utiliseront plutot :

       % setenv soif JD

  la ou j'ai ecrit

       $ soif=JD; export soif

  Si  l'invite  (_p_r_o_m_p_t dans la langue de Shakespeare) est  # plutot que
  $, la commande ne fonctionnera que si elle  est  executee  au  nom  de
  Root.  Bien  sur,  je  decline  toute responsabilite de ce qui peut se
  produire sur votre systeme lors de l'execution de ces exemples.  Bonne
  chance :-)

  22..  OOuu rreeccuuppeerreerr ddee llaa ddooccuummeennttaattiioonn eett lleess pprrooggrraammmmeess ??

  22..11..  CCee ddooccuummeenntt

  Ce  document  fait  partie de la serie des HOWTO pour Linux, et il est
  donc disponible ainsi que ces collegues  dans  les  repertoires  HowTo
  pour Linux, comme sur  <http://sunsite.unc.edu/pub/linux/docs/HOWTO/>.
  La    version    HTML    peut    egalement    etre    consultee    sur
  <http://ftp.linux.org.uk/~barlow/howto/gcc-howto.html>.

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

  22..22..

  AAuuttrreess ddooccuummeennttaattiioonn

  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 possedez une connexion rapide, un CD-ROM ou
  une certaine patience, vous pouvez  desarchiver  la  documentation  et
  l'installer dans le repertoire /usr/info.  Sinon, vous pouvez toujours
  les                 trouver                 sur                 tsx-11
  <ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/>,  mais  ce  n'est  pas
  necessairement toujours la derniere version.

  Il existe deux sources de documentation pour la libc. La libc GNU  est
  fournie avec des fichiers info qui decrivent assez precisement la libc
  Linux sauf pour la partie des entrees-sorties.  Vous pouvez  egalement
  trouver   sur   sunsite   <ftp://sunsite.unc.edu/pub/Linux/docs/>  des
  documents ecrits pour Linux ainsi  que  la  description  de  certaines
  appels systemes (section 2) et certaines fonctions de la libc (section
  3).
  Note du traducteur : un bemol concernant cette partie... La libc Linux
  n'est  pas  GNU  et  tend  a etre relativement differente sur certains
  points.

  22..33..  GGCCCC

  Il existe deux types de reponses

  (a) La distribution officielle de GCC pour Linux  peut  toujours  etre
  recuperee   sous   la   forme   de   binaires   (deja   compilee)  sur
  <ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/>.   Vous   pouvez    la
  trouver           sur           le           miroir           francais
  <ftp://ftp.ibp.fr:/pub/linux/packages/GCC/>.  A l'heure ou j'ecris ces
  lignes, la derniere version est gcc 2.7.2 (gcc-2.7.2.bin.tar.gz).

  (b)  La  derniere  distribution des sources de GCC de la _F_r_e_e _S_o_f_t_w_a_r_e
  _F_o_u_n_d_a_t_i_o_n      peut-etre      recuperee      sur      prep.ai.mit.edu
  <ftp://prep.ai.mit.edu/pub/gnu/>             ou             ftp.ibp.fr
  <ftp://ftp.ibp.fr/pub/gnu/>.  Ce n'est pas toujours  la  meme  version
  que  celle presentee ci-dessus.  Les mainteneurs de GCC pour Linux ont
  rendu la compilation de GCC  plus  facile  grace  a  l'utilisation  du
  script   configure   qui   effectue  la  configuration  d'une  maniere
  automatique.              Regardez             dans             tsx-11
  <ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/>      ou     ftp.ibp.fr
  <ftp://ftp.ibp.fr:/pub/linux/packages/GCC/> pour recuperer d'eventuels
  patches.

  Quelle que soit la complexite de votre programme, vous aurez egalement
  besoin de la _l_i_b_c.

  22..44..

  LLeess ffiicchhiieerrss dd''eenn--tteettee eett llaa bbiibblliiootthheeqquuee CC

  Ce que vous allez trouver dans ce paragraphe depend

  +o  de votre systeme (ELF ou a.out) ;

  +o  du type de binaire que vous desirez generer.

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

  Les       libc        sont        disponibles        sur        tsx-11
  <ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/>      ou     ftp.ibp.fr
  <ftp://ftp.ibp.fr:/pub/linux/packages/GCC/>. Voici une description des
  fichiers situes dans ce repertoire :

     lliibbcc--55..22..1188..bbiinn..ttaarr..ggzz
        ---  bibliotheques dynamiques et statiques ELF plus les fichiers
        d'en-tete  pour   la   bibliotheque   C   et   la   bibliotheque
        mathematique.

     lliibbcc--55..22..1188..ttaarr..ggzz
        ---  Code  source  pour  la  bibliotheque ci-dessus.  Vous aurez
        egalement besoin du paquetage  .bin.  pour  avoir  les  fichiers
        d'en-tete.  Si  vous  hesitez  entre  compiler la bibliotheque C
        vous-meme et utiliser les binaires, la bonne reponse est dans la
        majorite des cas est d'utiliser les binaires. Toutefois, si vous
        desirer utiliser NYS (NdT : NYS != NIS)  ou  bien  les  mots  de
        passe _s_h_a_d_o_w, vous devrez recompiler la libc par vous-meme.

     lliibbcc--44..77..55..bbiinn..ttaarr..ggzz
        ---  bibliotheques dynamiques et statiques a.out pour la version
        4.7.5 de la libc.  Cette bibliotheque a ete concue pour  pouvoir
        coexister  avec le paquetage de la libc 5 decrit ci-dessus, mais
        c'est  uniquement  necessaire  si  vous  desirez   utiliser   ou
        developper des programmes au format a.out.

  22..55..

  OOuuttiillss aassssoocciieess ((aass,, lldd,, aarr,, ssttrriinnggss,, eettcc..))

  Ces  outils  se  trouvent  comme  les bibliotheques dans le repertoire
  tsx-11 <ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/>, et  ftp.ibp.fr
  <ftp://ftp.ibp.fr:/pub/linux/packages/GCC/>.   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 probleme  lorsqu'elle  est  utilisee  avec  la  libc  ELF.   Le
  developpement de la libc est relativement rapide et a moins que n'ayez
  de bonnes raisons pour utiliser le format a.out, vous etes  encourages
  a suivre le mouvement.

  33..  IInnssttaallllaattiioonn eett ccoonnffiigguurraattiioonn ddee GGCCCC

  33..11..

  LLeess vveerrssiioonnss ddee GGCCCC

  Vous  pouvez  savoir quelle est la version de GCC que vous possedez en
  tapant gcc -v lors de l'invite. C'est egalement  une  bonne  technique
  pour savoir si votre configuration est ELF ou a.out.  Sur mon systeme,
  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 a remarquer

  +o  i486.  Cela vous indique que la version de gcc que vous utilisez  a
     ete compilee pour etre utilisee sur un processeur 486 --- mais vous
     pouvez avoir un autre processeur comme un 386 ou un Pentium  (586).
     Tous   ces  processeurs  peuvent  executer  le  code  compile  avec
     n'importe quel processeur. La seule difference reside dans le  fait
     que  le  code  486 rajoute  un peu de code a certains endroits pour
     aller plus vite sur un 486.  Cela  n'a  pas  d'effet  nefaste  cote
     performance  sur  un 386 mais cela rend les executables un peu plus
     importants.
  +o  zorglub.   Ce  n'est  pas  reellement  important,  et   il   s'agit
     generalement  d'un commentaire (comme slackware or debian) ou meme,
     cela peut-etre vide (lorsque vous  avez  comme  nom  de  repertoire
     i486-linux).   Si  vous  construisez  votre propre gcc, vous pouvez
     fixer ce parametre selon vos desirs, comme je l'ai fait.  :-)

  +o  linux.  Cela peut etre a la place linuxelf ou linuxaout et en fait,
     la signification varie en fonction de la version que vous possedez.

  +o  linux signifie ELF si la version est 2.7.0  ou  superieure,  sinon,
     c'est du a.out.

  +o  linuxaout signifie a.out.  Cela a ete introduit comme cible lorsque
     le format des binaires a change  de  a.out  vers  ELF  dans  LLiinnuuxx.
     Normalement,  vous  ne verrez plus de linuxaout avec une version de
     gcc superieure a 2.7.0.

  +o  linuxelf est depasse. Il s'agit generalement de gcc  version  2.6.3
     configure pour generer des executables ELF. Notez que gcc 2.6.3 est
     connu pour generer de nombreuses erreurs lorsqu'il produit du  code
     ELF --- une mise a jour est tres fortement recommandee.

  +o  2.7.2 est le numero de la version de GCC.

  Donc,  en  resume,  nous  possedons  gcc 2.7.2 qui genere du code ELF.
  _Q_u_e_l_l_e _s_u_r_p_r_i_s_e (NdT: En francais dans le texte) !

  33..22..  AA qquueell eennddrrooiitt ss''iinnssttaallllee GGCCCC ??

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

  +o  /usr/lib/gcc-lib/_m_a_c_h_i_n_e_-_c_i_b_l_e/_v_e_r_s_i_o_n/ (et  ses  sous-repertoires)
     est  generalement  l'endroit  ou  se  trouve  le  plus  souvent  le
     compilateur.   Ceci  inclut  les  executables  qui   realisent   la
     compilation  ainsi que certaines bibliotheques et quelques fichiers
     d'en-tete.

  +o  /usr/bin/gcc est le lanceur du compilateur ---  c'est  en  fait  le
     programme  que  vous  lancez.   Il peut etre utilise avec plusieurs
     versions  de  gcc  lorsque  vous  possedez  plusieurs   repertoires
     installes  (voir  plus  bas).  Pour  trouver  la version par defaut
     utilisee, lancez gcc -v.  Pour  forcer  l'utilisation  d'une  autre
     version, lancez gcc -V _v_e_r_s_i_o_n. 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

  +o  /usr/_m_a_c_h_i_n_e_-_c_i_b_l_e/(bin|lib|include)/.    Si   vous  avez  installe
     plusieurs cibles possibles (par exemple a.out et elf,  ou  bien  un
     compilateur  croise, les bibliotheques, les binutils (as, ld, etc.)
     et les fichiers d'en-tete  pour les cibles differente de celle  par
     defaut  peuvent  etre  trouves  a cet endroit.  Meme si vous n'avez
     qu'une seule version  de  gcc  installee,  vous  devriez  toutefois
     trouver  a  cet  endroit un certain nombre de fichiers. Si ce n'est
     pas la cas, regardez dans /usr/(bin|lib|include).

  +o  /lib/,  /usr/lib  et  autres  sont   les   repertoires   pour   les
     bibliotheques  pour le systeme initial. Vous aurez egalement besoin
     du programme  /lib/cpp  pour  un  grand  nombre  d'applications  (X
     l'utilise   beaucoup)   ---   soit  vous  le  copiez  a  partir  de
     /usr/lib/gcc-lib/_m_a_c_h_i_n_e_-_c_i_b_l_e/_v_e_r_s_i_o_n/, soit vous faites   pointer
     un lien symbolique dessus.

  33..33..

  OOuu ssee ttrroouuvveenntt lleess ffiicchhiieerrss dd''eenn--tteettee ??

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

  +o  La   grande   majorite  des  fichiers  situes  dans  le  repertoire
     /usr/include/ et dans ses sous-repertoires proviennent du paquetage
     de la libc dont s'occupe H.J. Lu. Je dis bien la "grande  majorite"
     car  vous  pouvez  avoir  egalement  certains  fichiers   provenant
     d'autres  sources  (par  exemple  des bibliotheques curses et dbm),
     ceci est d'autant plus vrai si vous possedez une distribution de la
     libc  recente  (ou  les  bibliotheques  curses  et  dbm ne sont pas
     integrees).

  +o  Les repertoires /usr/include/linux et  /usr/include/asm  (pour  les
     fichiers   <linux/*.h>   et   <asm/*.h>)  doivent  etre  des  liens
     symboliques   vers   les   repertoires    linux/include/linux    et
     linux/include/asm  situes  dans  les  sources du noyau. Vous devrez
     installer ces sources si vous  desirez  pouvoir  developper  :  ces
     sources ne sont pas utilises uniquement pour compiler le noyau.

     Il est probable que vous ayez besoin de lancer la commande suivante
     make config dans le repertoire des sources du noyau apres les avoir
     installes.  Beaucoup  de  fichiers  ont besoin du fichier d'en-tete
     <linux/autoconf.h> qui n'existe pas sans cette commande. Il  est  a
     noter  que  dans certaines versions du noyau, le repertoire asm est
     en fait un lien symbolique qui n'est cree  qu'avec  l'execution  de
     make config.

     Donc,  si  vous  installez  les sources du noyau dans le repertoire
     /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 .

  +o  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   etre   trouves   dans   le   repertoire
     /usr/lib/gcc-lib/i486-box-linux/2.7.2/include/   pour   la  version
     2.7.2.

  33..44..  CCoonnssttrruuiirree uunn ccoommppiillaatteeuurr ccrrooiissee

  33..44..11..  LLiinnuuxx ccoommmmee ppllaattee--ffoorrmmee ddee ddeessttiinnaattiioonn

  Nous  supposons  que  vous  avez  recupere  les  sources  de  gcc,  et
  normalement, il vous suffit de suivre les instructions donnees dans le
  fichier INSTALL situe 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  a  noter
  que  vous  aurez besoin des fichiers d'en-tete de Linux, ainsi que les
  sources de l'assembleur et du l'editeur  de  liens  croises  que  vous
  pouvez  trouver sur  <ftp://tsx-11.mit.edu/pub/linux/packages/GCC/> ou
  <ftp://ftp.ibp.fr/pub/linux/GCC/>.

  33..44..22..  LLiinnuuxx ccoommmmee ppllaattee--ffoorrmmee oorriiggiinnee eett MMSSDDOOSS ccoommmmee ddeessttiinnaattiioonn

  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 teste cela et je ne pense pas le faire !

  44..  PPoorrttaaggee eett ccoommppiillaattiioonn

  44..11..

  SSyymmbboolleess ddeeffiinniiss aauuttoommaattiiqquueemmeenntt

  Vous pouvez trouver  quels  symboles  votre  version  de  gcc  definit
  automatiquement  en  le  lancant  avec  l'option -v.  Par exemple cela
  donne ca 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 ecrivez du code qui utilise des  specificites  Linux,  il  est
  souhaitable d'implementer le code non portable de la maniere suivante

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

  Utilisez __linux__ pour cela, et _p_a_s linux.  Bien que cette macro soit
  definie, ce n'est pas une specification POSIX.

  44..22..  OOppttiioonnss ddee ccoommppiillaattiioonn

  La documentation des options de compilation se trouve dans  les  pages
  _i_n_f_o  de  gcc  (sous  Emacs, utilisez C-h i puis selectionnez l'option
  `gcc').   Votre  distribution  peut   ne   pas   avoir   installe   la
  documentation  ou bien vous pouvez en avoir une ancienne. Dans ce cas,
  la meilleure chose a faire est de recuperer 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, completement  depassee.
  Cela vous met en garde si vous desirez la consulter.

  44..22..11..

  OOppttiioonnss ddee ccoommppiillaattiioonn

  gcc peut realiser un certain nombre d'optimisations sur le code genere
  en ajoutant l'option -O_n a la ligne de commandes, ou _n est un chiffre.
  La  valeur de _n, et son effet exact, depend de la version de gcc, mais
  s'echelonne normalement entre 0 (aucune optimisation) et 2 (un certain
  nombre) ou 3 (toutes les optimisations possibles).

  En  interne,  gcc  interprete  les  options telles que -f et -m.  Vous
  pouvez voir exactement ce qu'effectue le niveau specifie dans l'option
  -O  en  lancant  gcc avec l'option -v et l'option (non documentee) -Q.
  Par exemple, l'option -O2, effectue les operations  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 superieur a celui que le compilateur
  supporte (par exemple -O6) aura le meme effet qu'utiliser le plus haut
  niveau  gere.  Distribuer  du code ou la compilation est configuree de
  cette maniere est une tres mauvaise idee -- si d'autres  optimisations
  sont   incorporees   dans  de  versions  futures,  vous  (ou  d'autres
  utilisateurs) pouvez vous apercevoir que cela ne compile plus, ou bien
  que le code genere ne fait pas les actions desirees.

  Les  utilisateurs  de  gcc  2.7.0 a 2.7.2 devraient noter qu'il y a un
  bogue dans l'option -O2. Plus precisement, la  _s_t_r_e_n_g_t_h  _r_e_d_u_c_t_i_o_n  ne
  fonctionne  pas.  Un patch a ete implemente pour resoudre ce probleme,
  mais vous devez alors recompiler  gcc.  Sinon,  vous  devrez  toujours
  compiler avec l'option -fno-strength-reduce.

  44..22..11..11..  SSppeecciiffiiccaattiioonn dduu pprroocceesssseeuurr

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

  Il  n'existe  pas actuellement de -mpentium ou -m586.  Linus a suggere
  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 problemes 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 _s_t_r_e_n_g_t_h _r_e_d_u_c_t_i_o_n, qui est un autre probleme).
       Cela s'explique en raison du peu de registres dont disposent
       ces processeurs (et la methode de GCC qui consiste a grouper
       les  registres  dans  l'ordre  inverse  au  lieu  d'utiliser
       d'autres  registres  n'arrange rien).  La _s_t_r_e_n_g_t_h _r_e_d_u_c_t_i_o_n
       consiste en fait a rajouter des registres pour remplacer les
       multiplications  par  des  additions.  Je suspecte egalement
       -fcaller-saves de ne pas arranger la situation. "

       Une autre idee est que -fomit-frame-pointer n'est pas  obli-
       gatoirement  une bonne idee.  D'un cote, cela peut signifier
       qu'un autre registre est  disponible  pour  une  allocation.
       D'un  autre  cote,  vue  la maniere 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 fenetres relatives, ce qui signifie en clair que
       moins de cache est disponible pour l'execution du processus.
       Il faut preciser que l'option -fomit-frame-pointer, signifie
       que  le  compilateur doit constamment ajuster le pointeur de
       pile apres les appels, alors qu'avec une  fenetre,  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 reelle optimi-
       sation que pour vous.

  44..22..22..

  IInntteerrnnaall ccoommppiilleerr eerrrroorr:: cccc11 ggoott ffaattaall ssiiggnnaall 1111

  Signal  11  correspond  au  signal  SIGSEGV,  ou   bien   _s_e_g_m_e_n_t_a_t_i_o_n
  _v_i_o_l_a_t_i_o_n.  Normalement,  cela signifie que le programme s'est melange
  les pointeurs et a essaye d'ecrire la ou il n'en a pas le droit. Donc,
  cela pourrait etre un bug de gcc.

  Toutefois,  gcc est un logiciel assez teste et assez remarquable de ce
  cote.  Il utilise un grand nombre de structures de donnees  complexes,
  et  un  nombre  impressionnant  de pointeurs. En resume, c'est le plus
  pointilleux des testeurs de memoire existants. Si vous _n_'_a_r_r_i_v_e_z _p_a_s _a
  _r_e_p_r_o_d_u_i_r_e  _l_e  _b_o_g_u_e  ---  si  cela  ne  s'arrete pas au meme endroit
  lorsque vous retentez la compilation --- c'est plutot un probleme avec
  votre  machine  (processeur,  memoire,  carte  mere  ou  bien  cache).
  NN''aannnnoonncceezz ppaass la decouverte 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  meme  si  le
  noyau  s'arrete  lors  du `make zImage' !  `make zImage' doit compiler
  plus de 200 fichiers, et il en faut bien moins pour  arriver  a  faire
  echouer une compilation.

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

  44..33..  PPoorrttaabbiilliittee

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

  Plus serieusement, en general seules quelques  modifications  mineures
  sont necessaires car Linux repond a 100% aux specifications POSIX.  Il
  est generalement sympathique d'envoyer a  l'auteur  du  programme  les
  modifications  effectuees  pour que le programme fonctionne sur Linux,
  pour que lors d'une future version, un  `make'  suffise  pour  generer
  l'executable.

  44..33..11..  <<ssggttttyy..hh>>) Specificites BSD (notamment bsd_ioctl, daemon et

  Vous  pouvez compiler votre programme avec l'option -I/usr/include/bsd
  et faire l'edition de liens avec -lbsd (en ajoutant -I/usr/include/bsd
  a  la  ligne  CFLAGS  et  -lbsd  a la ligne LDFLAGS dans votre fichier
  Makefile).  Il  est   egalement   necessaire   de   ne   ppaass   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-tete <signal.h>.

  44..33..22..

  SSiiggnnaauuxx _m_a_n_q_u_a_n_t_s ((SSIIGGBBUUSS, SIGEMT, SIGIOT, SIGTRAP, SIGSYS, etc.)

  Linux respecte les specifications 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
       ete  omis  de  la  norme  POSIX.1  car leur comportement est
       dependant de l'implementation et donc ne peut etre  reperto-
       rie  d'une maniere satisfaisante.  Certaines implementations
  peuvent fournir ces signaux  mais  doivent  documenter  leur
  effet "

  La maniere la plus elegante de regler ce probleme est de redefinir ces
  signaux a SIGUNUSED.  La maniere _n_o_r_m_a_l_e de proceder est d'entourer le
  code avec les #ifdef appropries :

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

  44..33..33..

  CCooddee KK && RR

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

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

  Notez que l'option -traditional a pour  unique  effet  de  changer  la
  forme  du  langage  accepte par gcc. Par exemple, elle active l'option
  -fwritable-strings, qui deplace toutes les chaines de caracteres  vers
  l'espace  de donnees (depuis l'espace de texte, ou elle ne peuvent pas
  etre modifiees). Ceci augmente la taille de la memoire occupee par  le
  programme.

  44..33..44..  lleess pprroottoottyyppeess dduu ccooddee

  LLeess ssyymmbboolleess dduu pprreepprroocceesssseeuurr pprroodduuiisseenntt uunn ccoonnfflliitt aavveecc

  Un des problemes frequents  se  produit  lorsque  certaines  fonctions
  standards  sont  definies  comme macros dans les fichiers d'en-tete de
  Linux  et  le  preprocesseur  refusera  de  traiter   des   prototypes
  identiques. Par exemple, cela peut arriver avec atoi() et atol().

  44..33..55..

  sspprriinnttff(())

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

  44..33..66..

  ffccnnttll et ses copains.  Ou se trouve la definition de FD_* et compagnie
  ?

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

  D'une  maniere  generale, la page de manuel pour une fonction donne la
  liste des fichiers d'en-tete a inclure.

  44..33..77..  ccoommmmeenncceenntt ddaannss uunn eettaatt dd''aatttteennttee aaccttiivvee

  LLee ttiimmeeoouutt ddee sseelleecctt(()). Les programmes

  A une certaine epoque, le parametre timeout de  la  fonction  select()
  etait  utilise  en  lecture  seule.   C'est pourquoi la page de manuel
  comporte une mise en garde :

       select()  devrait  retourner  normalement  le  temps  ecoule
       depuis  le timeout initial, s'il s'est declenche, en modifi-
       ant la valeur pointee par le parametre time. Cela sera peut-
       etre  implemente  dans  les versions ulterieures du systeme.
       Donc, il n'est pas vraiment prudent de supposer que les don-
       nees  pointees  ne  seront  pas  modifiees lors de l'appel a
       select().

  Mais tout arrive avec  le  temps  !  Lors  d'un  retour  de  select(),
  l'argument   timeout  recevra  le  temps  ecoule  depuis  la  derniere
  reception de donnees. Si aucune donnee n'est arrivee, la  valeur  sera
  nulle, et les futurs appels a cette fonction utilisant le meme timeout
  auront pour resultat un retour immediat.

  Pour resoudre le probleme, il suffit de mettre la valeur timeout  dans
  la structure a chaque appel de select().  Le code initial etait

             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  etaient connues a une certaine epoque
  pour avoir ce probleme.

  La  vitesse  de  rotation  du  globe   terrestre   etait   inversement
  proportionnelle a la vitesse de transfert des donnees !
  44..33..88..

  AAppppeellss ssyysstteemmeess iinntteerrrroommppuuss

  44..33..88..11..  SSyymmppttoommeess ::

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

  44..33..88..22..  PPrroobblleemmeess ::

  Les  systemes  POSIX  verifient  les signaux plus souvent que d'autres
  Unix plus anciens. Linux peux lancer les gestionnaires de signaux :

  +o  d'une maniere asynchrone (sur un top d'horloge)

  +o  lors d'un retour de n'importe quel appel systeme

  +o  pendant  l'execution  des  appels  systemes  suivants  :  select(),
     pause(),   connect(),  accept(),  read()  sur  des  terminaux,  des
     sockets, des pipes ou des fichiers situes dans /proc,  write()  sur
     des  terminaux,  des  sockets, des pipes ou des imprimantes, open()
     sur  des  FIFOs,  des  lignes  PTYs  ou  series,  ioctl()  sur  des
     terminaux, fcntl() avec la commande F_SETLKW, wait4(), syslog(), et
     toute operation d'ordre TCP ou NFS.

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

  Si  un  signal  (que  le  programme  desire traiter) est lance pendant
  l'execution d'un appel systeme, le gestionnaire est lance. Lorsque  le
  gestionnaire du signal se termine, l'appel systeme detecte qu'il a ete
  interrompu et se termine avec la valeur  -1  et  errno  =  EINTR.   Le
  programme n'est pas forcement au courant de ce qui s'est passe et donc
  s'arrete.

  Vous pouvez choisir deux solutions pour resoudre ce probleme.

  (1)Dans tout gestionnaire de signaux que vous mettez en place, ajoutez
  l'option SA_RESTART au niveau de _s_i_g_a_c_t_i_o_n. 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  systemes  vous  devrez souvent
  regarder si errno n'a pas ete positionnee a EINTR par vous meme  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   systeme.   Pour   recuperer   les
  interruptions  d'appels  systemes,  vous  devez  utiliser  les options
  SV_INTERRUPT ou SA_INTERRUPT.

  44..33..99..  "" sseeggmmeennttaattiioonn ffaauulltt "" dd''uunnee mmaanniieerree aalleeaattooiirree))

  LLeess cchhaaiinneess eett lleeuurrss aacccceess eenn eeccrriittuurreess ((oouu lleess pprrooggrraammmmeess qquuii  pprroovvoo--
  qquueenntt ddeess

  GCC a une vue optimiste  en  ce  qui  concerne  ses  utilisateurs,  en
  croyant  qu'ils  respectent le fait qu'une chaine dite constante l'est
  reellement. Donc, il les range  dans la zone _t_e_x_t_e_(_c_o_d_e_) du programme,
  ou  elles  peuvent  etre  chargees puis dechargees a partir de l'image
  binaire de l'executable situee sur disque (ce qui evite  d'occuper  de
  l'espace  disque).  Donc, toute tentative d'ecriture dans cette chaine
  provoque un " segmentation fault ".

  Cela peut poser certains problemes avec d'anciens codes,  par  exemple
  ceux  qui  utilisent  la  fonction  mktemp() avec une chaine constante
  comme argument.  mktemp() essaye d'ecrire dans  la  chaine  passee  en
  argument.

  Pour resoudre ce probleme,

  1. compilez  avec  l'option  -fwritable-strings pour indiquer a gcc de
     mettre les chaines constantes dans l'espace de donnees

  2. reecrire les differentes parties du code pour  allouer  une  chaine
     non  constante  puis  effectuer  un strcpy des donnees dedans avant
     d'effectuer l'appel.

  44..33..1100..

  PPoouurrqquuooii ll''aappppeell aa eexxeeccll(()) echoue ?

  Tout simplement parce que vous l'utilisez  mal.  Le  premier  argument
  d'execl est le programme que vous desirez executer. Le second et ainsi
  de suite sont en fait le elements du tableau argv  que  vous  appelez.
  Souvenez-vous  que  argv[0]  est  traditionnellement  fixe  meme si un
  programme est lance sans argument. Vous devriez donc ecrire :

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

  et pas

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

  Lancer le programme  sans  argument  est  considere  comme  etant  une
  demande   d'affichage   des   bibliotheques  dynamiques  associees  au
  programme, si vous utilisez le  format  a.out.  ELF  fonctionne  d'une
  maniere differente.

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

  55..  DDeebboogguueerr eett ooppttiimmiisseerr

  55..11..

  EEttuuddee pprreevveennttiivvee dduu ccooddee ((lliinntt))

  Il   n'existe  pas  de  lint  qui  soit  reellement  utilisable,  tout
  simplement  parce  que  la  grande  majorite  des  developpeurs   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       a        l'adresse        suivante        :
  <ftp://larch.lcs.mit.edu/pub/Larch/lclint>.  Je ne sais pas ce qu'elle
  vaut.

  55..22..

  DDeebboogguueerr

  55..22..11..

  CCoommmmeenntt rreennddrree ddeebbooggaabbllee uunn pprrooggrraammmmee ??

  Vous devez compiler et effectuer l'edition 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 deboguer.

  Si vous possedez un systeme a.out, les bibliotheques  dynamiques  sont
  compilees  avec  l'option  -fomit-frame-pointer,  que  gcc ne peut pas
  gerer. Lorsque vous compilez avec l'option -g, alors par  defaut  vous
  effectuez  une edition de liens statique, ce qui permet de resoudre le
  probleme.

  Si l'editeur de liens echoue avec un message disant qu'il n'arrive pas
  a  trouver  la  bibliotheque libg.a, c'est que vous ne possedez pas la
  bibliotheque /usr/lib/libg.a,  qui  est  la  bibliotheque  C  standard
  permettant  le  debogage.  Cette  bibliotheque  est  fournie  dans  le
  paquetage des binaires de la libc., ou (dans les  nouvelles  versions)
  vous  aurez besoin de recuperer le source et de le compiler vous-meme.
  Vous n'avez pas reellement besoin de cela en fait, vous  pouvez  faire
  un lien logique vers /usr/lib/libc.a

  55..22..11..11..

  CCoommmmeenntt rreedduuiirree llaa ttaaiillllee ddeess eexxeeccuuttaabblleess ??

  Bon  nombre  de  produits GNU sont fournis pour compiler avec l'option
  -g, ce qui genere des executables d'une  taille  tres  importante  (et
  souvent  l'edition  de  liens  s'effectue d'une maniere statique).  Ce
  n'est pas une idee lumineuse...

  Si le programme possede le script configure genere par autoconf,  vous
  pouvez  modifier  les options de debogage en effectuant un vous pouvez
  aller modifier le Makefile. Bien sur, si vous utilisez le format  ELF,
  l'edition  de  liens  sera  effectuee  de  maniere dynamique meme avec
  l'option  -g.  Dans  ce  cas,  vous  pouvez  effectuer  un  strip  sur
  l'executable.

  55..22..22..

  PPrrooggrraammmmeess ddiissppoonniibblleess

  Beaucoup  de gens utilisent ggddbb, que vous pouvez recuperer sur le site
  prep.ai.mit.edu  <ftp://prep.ai.mit.edu/pub/gnu>,   sous   une   forme
  binaire  sur  tsx-11  <ftp://tsx-11.mit.edu/pub/linux/packages/GCC> ou
  sur sunsite.  xxxxggddbb est une surcouche X de gdb (c.a.d. que  vous  avez
  besoin de gdb pour utiliser xxgdb). Les sources peuvent etre recuperes
  sur  <ftp://ftp.x.org/contrib/xxgdb-1.08.tar.gz>

  Il existe egalement le debogueur UUPPSS qui a ete porte par Rick Sladkey.
  Il fonctionne sous X egalement, mais a la difference d'xxgdb, ce n'est
  qu'une surcouche X pour un debogueur en  mode  en  texte.  Il  possede
  certaines  caracteristiques  tres  interessantes  et  si vous utilisez
  beaucoup ce genre d'outils, vous  l'essayerez  surement.  Les  patches
  ainsi  que  des versions precompilees pour Linux peuvent etre trouvees
  sur <ftp://sunsite.unc.edu/pub/Linux/devel/debuggers/>, et les sources
  peuvent                etre                recuperes               sur
  <ftp://ftp.x.org/contrib/ups-2.45.2.tar.Z>.

  Un autre outil que vous pouvez  trouver  utile  pour  deboguer  est  "
  ssttrraaccee  " , qui affiche les appels systemes que le processus lance. Il
  possede  d'autres  caracteristiques  telles  que  donner  les  chemins
  d'acces ou ont ete compiles les binaires, donner les temps passes dans
  chacun des appels systemes, et il vous permet egalement  de  connaitre
  les  resultats des appels. La derniere version de strace (actuellement
  la version 3.0.8) peut etre trouvee sur  <ftp://ftp.std.com/pub/jrs/>.

  55..22..33..  PPrrooggrraammmmeess eenn ttaacchhee ddee ffoonndd ((ddeemmoonn))

  Les  demons  lancent  typiquement  un  fork()  des  leur  lancement et
  terminent donc le pere.  Cela  fait  une  session  de  deboguage  tres
  courte.

  La  maniere  la  plus  simple  de resoudre ce probleme est de poser un
  point d'arret sur fork, et lorsque le programme  s'arrete,  forcer  le
  retour a 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       }

  55..22..44..  FFiicchhiieerrss ccoorree

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

       % limit core unlimited

  avec sh, bash, zsh, pdksh, utilisez

       $ ulimit -c unlimited

  Si  vous  voulez  pousser  le  vice  a  nommer votre fichier core (par
  exemple si vous utilisez un debogueur bogue... 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.

  55..33..  CCaarraacctteerriissttiiqquueess dduu pprrooggrraammmmee

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

  66..  EEddiittiioonn ddee lliieennss

  Entre  les  deux  formats  de  binaires  incompatibles,  bibliotheques
  statiques et dynamiques, on peut  comparer  l'operation  d'edition  de
  lien  en  fait  a 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 regne, nous allons nous baser sur ce
  qui se passe lors  d'execution  d'un  programme,  avec  le  chargement
  dynamique.  Vous verrez egalement la description de l'edition de liens
  dynamiques, mais plus tard. Cette section est dediee  a  l'edition  de
  liens qui intervient a la fin de la compilation.

  66..11..  BBiibblliiootthheeqquueess ppaarrttaaggeeeess ccoonnttrree bbiibblliiootthheeqquueess ssttaattiiqquueess

  La derniere phase de  construction  d'un  programme  est  de  realiser
  l'edition  de  liens, ce qui consiste a assembler tous les morceaux du
  programme et de chercher ceux  qui  sont  manquants.  Bien  evidement,
  beaucoup de programmes realisent les memes operations comme ouvrir des
  fichiers  par  exemple,  et  ces  pieces  qui   realisent   ce   genre
  d'operations sont fournies sous la forme de bibliotheques. Sous Linux,
  ces bibliotheques peuvent etre  trouvees  dans  les  repertoires  /lib
  et/usr/lib/ entre autres.

  Lorsque  vous  utilisez  une bibliotheque statique, l'editeur de liens
  cherche le code dont votre programme a besoin et en effectue une copie
  dans  le  programme physique genere. Pour les bibliotheques partagees,
  c'est le contraire : l'editeur de liens laisse du  code  qui  lors  du
  lancement  du  programme  chargera automatiquement la bibliotheque. Il
  est evident que ces bibliotheques permettent d'obtenir  un  executable
  plus  petit; elles permettent egalement d'utiliser moins de memoire et
  moins de place disque. Linux effectue par defaut une edition de  liens
  dynamique  s'il  peut  trouver  les bibliotheques de ce type sinon, il
  effectue une edition de liens statique. Si vous obtenez  des  binaires
  statiques  alors  que  vous  les  voulez  dynamiques  verifiez que les
  bibliotheques existent (*.sa pour le format a.out,  et  *.so  pour  le
  format  ELF) et que vous possedez les droits suffisants pour y acceder
  (lecture).

  Sous Linux, les bibliotheques statiques ont pour nom  libnom.a,  alors
  que  les  bibliotheques  dynamiques  sont appelees libnnom.so.x.y.z ou
  x.y.z represente le numero de version.  Les  bibliotheques  dynamiques
  ont  souvent  des liens logiques qui pointent dessus, et qui sont tres
  importants. Normalement, les bibliotheques standards sont livrees sous
  la double forme dynamique et statique.

  Vous  pouvez savoir de quelles bibliotheques dynamiques un programme a
  besoin en utilisant la commande ldd (_L_i_s_t _D_y_n_a_m_i_c _D_e_p_e_n_d_e_n_c_i_e_s)

       $ 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 systeme que l'outil lynx (outil WWW) a besoin des
  bibliotheques   dynamiques   libc.so.5   (la  bibliotheque  C)  et  de
  libncurses.so.1 (necessaire pour le  controle  du  terminal).   Si  un
  programme  ne  possede  pas  de dependances, ldd indiquera `_s_t_a_t_i_c_a_l_l_y
  _l_i_n_k_e_d' (edition de liens statique).

  66..22..

  AA llaa rreecchheerrcchhee ddeess ffoonnccttiioonnss...... oouu ddaannss qquueellllee bbiibblliiootthheeqquuee ssee  ttrroouuvvee
  llaa ffoonnccttiioonn ssiinn(()) ?')

  nm _n_o_m_d_e_b_i_b_l_i_o_t_h_e_q_u_e vous donne tous les symboles references  dans  la
  bibliotheque.  Cela  fonctionne  que  cela  soit  du  code statique ou
  dynamique.  Supposez que vous vouliez savoir ou se trouve  definie  la
  fonction tcgetattr() :

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

  La  lettre  U  vous  indique  que  c'est indefini (_U_n_d_e_f_i_n_e_d) --- cela
  indique que la bibliotheque ncurses l'utilise mais ne la definit  pas.
  Vous pouvez egalement faire :

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

  La  lettre `W' indique que le symbole est defini mais de telle maniere
  qu'il peut etre surcharge par une autre definition de la fonction dans
  une autre bibliotheque (W pour _w_e_a_k : faible).  Une definition normale
  est marquee par la lettre `T' (comme pour tcgetpgrp).

  La reponse a la question situee dans le titre est libm.(so|a).  Toutes
  les  fonctions  definies  dans  le  fichier  d'en-tete  <math.h>  sont
  implementees  dans  la  bibliotheque  mathematique  donc  vous  devrez
  effectuer l'edition de liens grace a -lm.

  66..33..  TTrroouuvveerr lleess ffiicchhiieerrss

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

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

  La strategie de recherche de fichiers de ld ou de ses copains  differe
  de  la  version  utilisee,  mais vous pouvez etre sur que les fichiers
  situes dans le repertoire /usr/lib seront trouves. Si vous desirez que
  des  fichiers  situes  a  un  endroit different soient trouves, il est
  preferable d'ajouter l'option -L a gcc ou ld.

  Si cela ne vous aide pas clairement, verifiez que  vous  avez  le  bon
  fichier  a  l'endroit  specifie.  Pour  un  systeme  a.out,  effectuer
  l'edition  de  liens  avec  -ltruc  implique  que  ld  recherche   les
  bibliotheques    libtruc.sa  (bibliotheques  partagees),  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 generalement un
  lien symbolique vers libtruc.so.x.

  66..44..  CCoommppiilleerr vvoottrree pprroopprree bbiibblliiootthheeqquuee

  66..44..11..  NNuummeerroo ddee llaa vveerrssiioonn

  Comme tout programme, les bibliotheques ont tendance a avoir  quelques
  bogues   qui   sont   corriges  au  fur  et  a  mesure.  De  nouvelles
  fonctionnalites sont ajoutees et qui peuvent changer l'effet de celles
  qui  existent  ou  bien  certaines anciennes peuvent etres supprimees.
  Cela peut etre un probleme pour les programmes qui les utilisent.

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

  Une  des  principales  differences  entre  les formats ELF et a.out se
  trouve dans la maniere de construire la bibliotheque  partagee.   Nous
  traiterons  les  bibliotheques  partagees  en  premier  car c'est plus
  simple.

  66..44..22..

  EELLFF,, qquu''eesstt--ccee qquuee cc''eesstt ??

  ELF (_E_x_e_c_u_t_a_b_l_e _a_n_d _L_i_n_k_i_n_g _F_o_r_m_a_t) est format de binaire initialement
  concu  et developpe par USL (_U_N_I_X _S_y_s_t_e_m _L_a_b_o_r_a_t_o_r_i_e_s) et utilise dans
  les  systemes  Solaris  et  System  R4.  En  raison  de  sa   facilite
  d'utilisation  par  rapport  a  l'ancien format dit a.out qu'utilisait
  Linux, les developpeurs de GCC et de  la  bibliotheque  C  ont  decide
  l'annee  derniere  de basculer tout le systeme sous le format ELF. ELF
  est desormais le format binaire standard sous Linux.

  66..44..22..11..  EELLFF,, llee rreettoouurr !!

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

       ELF (_E_x_e_c_u_t_a_b_l_e _L_i_n_k_i_n_g _F_o_r_m_a_t) 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  ou  il  est  extensible. ELF voit un fichier objet
       comme une longue liste de sections (plutot qu'un tableau  de
       taille  fixe  d'elements).  Ces sections, a la difference de
       COFF ne se trouvent pas a un endroit constant et ne sont pas
       dans  un  ordre  particulier,  etc. Les utilisateurs peuvent
       ajouter une nouvelle section  a  ces  fichiers  objets  s'il
       desirent  y mettre de nouvelles donnees. ELS possede un for-
       mat de debogage plus puissant appele DWARF  (_D_e_b_u_g_g_i_n_g  _W_i_t_h
       _A_t_t_r_i_b_u_t_e  _R_e_c_o_r_d  _F_o_r_m_a_t) - par encore entierement gere par
       Linux (mais on y travaille !).  Une liste chainee de " DWARF
       DIEs " (ou _D_e_b_u_g_g_i_n_g _I_n_f_o_r_m_a_t_i_o_n _E_n_t_r_i_e_s - NdT... le lecteur
       aura surement note le jeu de mot assez noir : dwarf =  nain;
       dies  =  morts)  forment la section _._d_e_b_u_g 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  ecrits  sous  la
       forme  d'un arbre de donnees.  Les DIEs peuvent contenir une
       plus grande quantite d'information que la section _._d_e_b_u_g  du
       format  COFF  ne le pouvait (un peu comme les graphes d'her-
       itages du C++).

       Les fichiers ELF sont accessibles grace  a  la  bibliotheque
       d'acces  de  SVR4 (Solaris 2.0 peut-etre ?), qui fournit une
       interface simple et rapide aux parties  les  plus  complexes
       d'ELF.  Une  des aubaines que permet la bibliotheque d'acces
       ELF est que vous n'avez jamais besoin de connaitre les mean-
       dres  du  format  ELF.  Pour  acceder  a un fichier Unix, on
       utilise un Elf  *,  retourne  par  un  appel  a  elf_open().
       Ensuite,  vous  effectuez  des  appels  a  elf_foobar() pour
       obtenir les differents composants au lieu d'avoir a triturer
       le  fichier  physique  sur  le  disque  (chose  que beaucoup
       d'utilisateurs de COFF ont fait...).

  Les arguments pour ou contre ELF, et les problemes lies a  la  mise  a
  jour  d'un systeme a.out vers un systeme ELF sont decrits dans le ELF-
  HOWTO et je ne veux pas effectuer de copier coller ici (NdT: ce  HowTo
  est  egalement  traduit  en  francais).   Ce  HowTo  se trouve au meme
  endroit que les autres.

  66..44..22..22..  LLeess bbiibblliiootthheeqquuee ppaarrttaaggeeeess EELLFF

  Pour construire libtruc.so comme une bibliotheque dynamique, il suffit
  de suivre les etapes 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 generer une bibliotheque partagee appelee libtruc.so.1.0, les
  liens  appropries  pour  ld  (libtruc.so)  et  le  chargeur  dynamique
  (libtruc.so.1)  pour  le  trouver.   Pour  tester,  nous  ajoutons  le
  repertoire actuel a la variable d'environnement LD_LIBRARY_PATH.

  Lorsque vous etes satisfait et que la  bibliotheque  fonctionne,  vous
  n'avez   plus  qu'a  la  deplacer  dans  le  repertoire  par  exemple,
  /usr/local/lib, et  de  recreer  les  liens  appropries.  Le  lien  de
  libtruc.so.1  sur  libtruc.so.1.0 est enregistre par ldconfig, qui sur
  bon nombre de systemes est lance lors du processus d'amorcage. Le lien
  libfoo.so  doit  etre  mis  a jour a la main. Si vous faites attention
  lors de la mise a jour de la bibliotheque la chose la  plus  simple  a
  realiser  est  de  creer  le  lien  libfoo.so -> libfoo.so.1, pour que
  ldconfig conserve les liens actuels. Si vous ne faites pas cela,  vous
  aurez  des problemes plus tard. Ne me dites pas que l'on ne vous a pas
  prevenu !

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

  66..44..22..33..

  LLeess nnuummeerrooss ddee vveerrssiioonn,, lleess nnoommss eett lleess lliieennss

  Chaque bibliotheque possede un nom propre (_s_o_n_a_m_e).  Lorsque l'editeur
  de  liens  en trouve un qui correspond a un nom cherche, il enregistre
  le nom de la bibliotheque dans le code binaire au lieu d'y  mettre  le
  nom  du  fichier  de la bibliotheque. Lors de l'execution, le chargeur
  dynamique va alors chercher un fichier ayant pour nom le nom propre de
  la  bibliotheque,  et  pas  le  nom du fichier de la bibliotheque. Par
  exemple, une bibliotheque ayant pour nom libtruc.so peut  avoir  comme
  nom  propre  libbar.so,  et  tous  les programmes lies avec vont alors
  chercher libbar.so lors de leur execution.

  Cela semble etre une nuance un peu pointilleuse mais c'est la clef  de
  la  comprehension  de la coexistence de plusieurs versions differentes
  de la meme bibliotheque sur le meme systeme.  On a pour habitude  sous
  Linux d'appeler une bibliotheque libtruc.so.1.2 par exemple, et de lui
  donner comme nom  propre  libtruc.so.1.   Si  cette  bibliotheque  est
  rajoutee  dans  un repertoire standard (par exemple dans /usr/lib), le
  programme ldconfig va creer un lien symbolique entre  libtruc.so.1  ->
  libtruc.so.1.2  pour  que  l'image  appropriee  soit  trouvee  lors de
  l'execution.  Vous  aurez  egalement  besoin  d'un   lien   symbolique
  libtruc.so  ->  libtruc.so.1  pour que ld trouve le nom propre lors de
  l'edition de liens.
  Donc, lorsque vous corrigez des erreurs dans la bibliotheque  ou  bien
  lorsque  vous  ajoutez  de  nouvelles  fonctions  (en fait, pour toute
  modification  qui  n'affecte  pas  l'execution  des  programmes   deja
  existants),  vous  reconstruisez  la  bibliotheque,  conservez  le nom
  propre tel qu'il etait et changez le  nom  du  fichier.  Lorsque  vous
  effectuez  des  modifications  que peuvent modifier le deroulement des
  programmes existants,  vous  pouvez  tout  simplement  incrementer  le
  nombre  situe  dans le nom propre --- dans ce cas, appelez la nouvelle
  version de la bibliotheque 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'etes pas oblige de nommer les
  bibliotheques de cette maniere, mais c'est une bonne convention.   Elf
  vous  donne une certaine liberte pour nommer des bibliotheques tant et
  si bien que cela peut perturber certains utilisateurs,  mais  cela  ne
  veut pas dire que vous etes oblige de le faire.

  Resume : supposons que choisissiez d'adopter la methode traditionnelle
  avec les mises a jour majeures qui peuvent  ne  pas  etre  compatibles
  avec  les  versions  precedentes  et  les mises a jour mineures qui ne
  posent pas ce probleme. Il suffit de creer la  bibliotheque  de  cette
  maniere :

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

  et tout devrait etre parfait !

  66..44..33..  aa..oouutt..  LLee bboonn vviieeuuxx ffoorrmmaatt

  La  facilite  de  construire  des bibliotheque partagees est la raison
  principale de passer a ELF. Ceci dit,  il  est  toujours  possible  de
  creer  des  bibliotheques  dynamiques  au  format  a.out. Recuperez 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  apres
  l'avoir  desarchive.  Je n'aime pas avoir l'air d'etre aussi partisan,
  mais il est clair que je n'ai jamais aime ce format :-).

  66..44..33..11..

  ZZMMAAGGIICC ccoonnttrree QQMMAAGGIICC

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

  Les editeurs de liens desuets ne gerent que le format ZMAGIC, ceux  un
  peu moins rustiques gerent les deux, et les plus recents uniquement le
  QMAGIC. Cela importe peu car le noyau gere les deux types.

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

  66..44..33..22..  GGeessttiioonn ddeess ffiicchhiieerrss

  Une  bibliotheque  dynamique a.out (DLL) est composee de deux fichiers
  et d'un lien symbolique. Supposons que l'on  utilise  la  bibliotheque
  _t_r_u_c,   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 a quoi servent-ils ?

  Lors  de  la  compilation, ld cherche libtruc.sa.  C'est le fichier de
  description de la  bibliotheque  :  il  contient  toutes  les  donnees
  exportees  et  les  pointeurs  vers  les  fonctions  necessaires  pour
  l'edition de liens.

  Lors de  l'execution,  le  chargeur  dynamique  cherche  libtruc.so.1.
  C'est  un  lien  symbolique  plutot  qu'un  reel  fichier pour que les
  bibliotheques puissent etre mise  a  jour  sans  avoir  a  casser  les
  applications  qui  utilisent  la  bibliotheque.  Apres la mise a jour,
  disons que l'on est passe a la version libfoo.so.1.3, le lancement  de
  ldconfig  va  positionner le lien. Comme cette operation est atomique,
  aucune application fonctionnant n'aura de probleme.

  Les bibliotheques DLL (Je sais que c'est une tautologie... mais pardon
  !)   semblent  etre  tres souvent plus importantes que leur equivalent
  statique. En fait, c'est qu'elles  reservent  de  la  place  pour  les
  extensions  ulterieures sous la simple forme de trous qui sont fait de
  telle maniere qu'ils n'occupent pas de place  disque  (NdT  :  un  peu
  comme  les  fichiers  core).  Toutefois,  un  simple  appel  a cp ou a
  makehole les remplira...  Vous pouvez effectuer une operation de strip
  apres  la  construction  de la bibliotheque, comme les adresses sont a
  des endroits  fixes.   NNee  ffaaiitteess  ppaass  llaa  mmeemmee  ooppeerraattiioonn  aavveecc  lleess
  bbiibblliiootthheeqquueess EELLFF !!

  66..44..33..33..  "" lliibbcc--lliittee "" ??

  Une  "  libc-lite  "  (contraction  de _l_i_b_c et _l_i_t_t_l_e) est une version
  epuree et reduite de la bibliotheque libc construite de telle  maniere
  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 liee avec une bibliotheque de ce genre il est tres
  fortement conseille de la remplacer avec une version complete.

  66..44..44..  EEddiittiioonn ddee lliieennss :: pprroobblleemmee ccoouurraannttss

  Envoyez-les moi !

      DDeess pprrooggrraammmmeess ssttaattiiqquueess lloorrssqquuee vvoouuss lleess vvoouulleezz
        partages"

        Verifiez que vous avez les bons liens pour que ld puisse trouver
        les  bibliotheques  partagees.  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 probleme
        apres etre passes des outils ELF 2.5 a  2.6  (binutils)  ---  la
        derniere  version  effectue une recherche plus intelligente pour
        les bibliotheques dynamiques et donc ils n'avaient pas cree tous
        les  liens symboliques necessaires.  Cette caracteristique avait
        ete supprimee pour des raisons de  compatibilite  avec  d'autres
        architectures  et  parce  qu'assez  souvent cela ne marchait pas
        bien. En bref, cela posait plus de problemes qu'autre chose.

      LLee pprrooggrraammmmee ``mmkkiimmaaggee'' nn''aarrrriivvee ppaass aa ttrroouuvveerr lliibbggcccc

        Comme  libc.so.4.5.x  et  suivantes,  libgcc   n'est   pas   une
        bibliotheque  partagee.  Vous devez remplacer les `-lgcc' sur la
        ligne  de  commande  par  `gcc  -print-libgcc-file-name`  (entre
        quotes)

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

      LLee mmeessssaaggee ____NNEEEEDDSS__SSHHRRLLIIBB__lliibbcc__44 mmuullttiippllyy ddeeffiinneedd
        Sont une consequence du meme probleme.

      LLee mmeessssaaggee ````AAsssseerrttiioonn ffaaiilluurree'''' aappppaarraaiitt lloorrssqquuee vvoouuss
        rreeccoonnssttrruuiisseezz uunnee
        DLL"  Ce  message  enigmatique  signifie  qu'un element de votre
        table _j_u_m_p a depasse la  table  car  trop  peu  de  place  etait
        reservee  dans  le  fichier jump.vars file.  Vous pouvez trouver
        le(s) coupable(s) en lancant la commande getsize fournie dans le
        paquetage  tools-2.17.tar.gz.  La seule solution est de passer a
        une nouvelle version majeure, meme  si  elle  sera  incompatible
        avec les precedentes.

      lldd:: oouuttppuutt ffiillee nneeeeddss sshhaarreedd lliibbrraarryy lliibbcc..ssoo..44
        Cela  arrive  lorsque vous effectuez l'edition de liens avec des
        bibliotheques differentes de la libc (comme les bibliotheques X)
        et que vous utilisez l'option -g sans utiliser l'option -static.

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

        Donc,  pour  resoudre  le  probleme,  ajoutez  l'option  -static
        lorsque  vous  compilez  avec  l'option -g, ou n'utilisez pas -g
        lors de l'edition de liens !

  77..  CChhaarrggeemmeenntt ddyynnaammiiqquuee

  _C_e _p_a_r_a_g_r_a_p_h_e _e_s_t _e_n _f_a_i_t _u_n _p_e_u _c_o_u_r_t  _:  _i_l  _s_e_r_a  _e_t_e_n_d_u  _d_a_n_s  _u_n_e
  _v_e_r_s_i_o_n _u_l_t_e_r_i_e_u_r_e _d_e_s _q_u_e _j_'_a_u_r_a_i _r_e_c_u_p_e_r_e _l_e _H_o_w_T_o _E_L_F

  77..11..  CCoonncceeppttss

  Linux  possede  des  bibliotheques dynamiques, comme on vous le repete
  depuis le debut de ce  document  !  Or,  il  existe  un  systeme  pour
  reporter  le  travail  d'association  des noms des symboles et de leur
  adresse dans la bibliotheque, qui est  normalement  effectue  lors  de
  l'edition de liens en l'effectuant lors du chargement du programme.

  77..22..  MMeessssaaggeess dd''eerrrreeuurr

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

      ccaann''tt llooaadd lliibbrraarryy:: //lliibb//lliibbxxxxxx..ssoo,, IInnccoommppaattiibbllee vveerrssiioonn
        (seulement a.out) Cela signifie que vous n'avez pas  la  version
        correcte  de  la bibliotheque (numero dit majeur). Non, il n'est
        pas possible d'effectuer un lien symbolique sur la  bibliotheque
        que  vous  possedez : si vous avez de la chance, vous obtiendrez
        un _s_e_g_m_e_n_t_a_t_i_o_n  _f_a_u_l_t.   Recuperez  la  nouvelle  version.   Un
        message  un peu equivalent existe egalement sur les systemes ELF
        :

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

     wwaarrnniinngg uussiinngg iinnccoommppaattiibbllee lliibbrraarryy vveerrssiioonn xxxxxx
        (seulement a.out) Vous avez un numero de version de bibliotheque
        (mineur)  inferieur  a la version avec laquelle a ete compile le
        programme.  Le programme fonctionnera surement. Une mise a  jour
        est toutefois conseillee.

  77..33..

  CCoonnttrroolleerr ll''ooppeerraattiioonn ddee cchhaarrggeemmeenntt ddyynnaammiiqquuee

  Il   existe  certaines  variables  d'environnements  que  le  chargeur
  dynamique utilise. Beaucoup  sont  exploitees  par  le  programme  ldd
  lorsqu'il    s'agit    de   particularites   de   l'environnement   de
  l'utilisateur, ce qui peuvent etre positionnees pour lancer  ldd  avec
  des  options  particulieres.  Voici  une  description  des differentes
  variables d'environnement que vous pouvez rencontrer :

  +o  LD_BIND_NOW --- normalement, les fonctions ne  sont  pas  cherchees
     dans  les  bibliotheques  avant  leur  appel. En positionnant cette
     option, vous verifiez que toutes les fonctions employees dans votre
     programmes  se  trouvent  bien  dans  la  bibliotheque  lors de son
     chargement, ce qui ralentit le lancement du programme. C'est  utile
     lorsque   vous   voulez   tester   que  l'edition  de  liens  s'est
     parfaitement deroulee et que tous les symboles sont bien  associes.

  +o  LD_PRELOAD peut etre defini avec un nom de fichier qui contient des
     fonctions surchargeant des fonctions deja existantes.  Par exemple,
     si  vous  testez  une  strategie  d'allocation memoire, et que vous
     voulez remplacer le malloc de la bibliotheque C par le votre  situe
     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 utilisa-
  tion  est  specifique  au  type  de  binaire  utilise.  Si  LD__T_y_p_e_B_i_-
  _n_a_i_r_e_PRELOAD  et  LD_PRELOAD sont positionnes, celui correspondant le
  mieux a la machine est utilise.

  +o  LD_LIBRARY_PATH contient une liste  de  repertoires  contenant  les
     bibliotheques  dynamiques.  Cela n'affecte pas l'edition de liens :
     cela n'a qu'un effet lors de l'execution. Il faut noter qu'elle est
     desactivee pour des programmes qui s'executent avec un setuid ou un
     setgid.  Enfin, LD_ELF_LIBRARY_PATH et LD_AOUT_LIBRARY_PATH peuvent
     etre  utilises  pour  orienter  le  mode de compilation du binaire.
     LD_LIBRARY_PATH ne  devrait  pas  etre  necessaire  en  principe  :
     ajoutez   les  repertoires  dans  le  fichier  /etc/ld.so.conf/  et
     relancez ldconfig.

  +o  LD_NOWARN s'applique au format a.out uniquement.   Lorsqu'elle  est
     positionnee  (c.a.d si elle existe par exemple avec LD_NOWARN=true;
     export LD_NOWARN) cela arrete le chargeur du programme meme sur des
     avertissements     insignifiants    (tels    que    des    messages
     d'incompatibilites de numeros mineurs de version).

  +o  LD_WARN s'applique a ELF uniquement.  Lorsqu'elle est  positionnee,
     on transforme le message habituellement fatal _C_a_n_'_t _f_i_n_d _l_i_b_r_a_r_y en
     un avertissement. Ce n'est pas positionne  par  defaut  mais  c'est
     important pour un programme comme ldd.

  +o  LD_TRACE_LOADED_OBJECTS  s'applique  a ELF uniquement, et permet de
     simuler l'execution des programmes comme s'ils l'etaient 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

  77..44..

  EEccrriirree ddeess pprrooggrraammmmeess eenn uuttiilliissaanntt llee cchhaarrggeemmeenntt ddyynnaammiiqquuee

  Cela  ressemble  enormement au systeme de chargement dynamique utilise
  sous Solaris 2.x. Ce systeme est decrit d'une maniere precise dans  le
  document expliquant la programmation avec ELF ecrit 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 a faire l'edition 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");
         }

       }

  88..  CCoonnttaacctteerr lleess ddeevveellooppppeeuurrss

  88..11..

  AAnnnnoonncceerr ddeess bboogguueess

  Commencez  par  mettre en doute le probleme. Est-ce specifique a Linux
  ou bien cela arrive avec gcc mais sur d'autres plates-formes ?  Est-ce
  specifique a la version du noyau ? A la version de la bibliotheque C ?
  Est-ce que ce probleme disparait lorsque vous effectuez une edition de
  liens  statique  ?  Pouvez-vous produire un code tres court mettant en
  evidence le probleme ?

  Apres avoir repondu apres ces quelques  questions,  vous  saurez  quel
  programme  est  a  l'origine du probleme. Pour un probleme direct avec
  GCC, le mieux est de consulter le fichier d'information livre  avec  :
  la  procedure pour rapporter un bogue y est detaille. Pour un probleme
  avec ld.so, la bibliotheque C ou  mathematique,  envoyez  un  courrier
  electronique  a  linux-gcc@vger.rutgers.edu.   Si  possible, donnez un
  court exemple mettant en evidence  le  probleme  ainsi  qu'une  courte
  description indiquant ce que le programme aurait normalement du faire,
  et ce qu'il fait en realite.

  88..22..  PPaarrttiicciippeerr aauu ddeevveellooppppeemmeenntt

  Si  vous  desirez  participer  au  developpement  de  GCC  ou  de   la
  bibliotheque C, la premiere chose a faire est de rejoindre la liste de
  diffusion  linux-gcc@vger.rutgers.edu.   Si  vous  desirez  uniquement
  savoir   de  quoi  ca  parle,  il  existe  des  archives  a  l'adresse
  <http://homer.ncm.com/linux-gcc/>.  Tout depend de ce que vous desirez
  faire ou apporter a ce projet !

  99..  DDiivveerrss

  99..11..  CCee ddooccuummeenntt

  Ce  HowTo  est  base  sur  la  FAQ de Mitchum DSouza's. Bon nombre des
  informations en proviennent. D'une maniere generale, il  est  frequent
  de  dire  une  phrase  du genre " je n'ai pas tout teste et donc ne me
  blamez pas si vous cassez votre  disque,  votre  systeme  ou  si  vous
  rompez avec votre epouse ".

  Le  nom  des  contributeurs  a  ce  document  sont  donnes  par  ordre
  alphabetique : 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  sur
  Linus  Torvalds,  sans  qui  ce genre d'exercice aurait ete difficile,
  voir impossible :-)

  Ne soyez pas offense si votre nom n'apparait pas dans la liste et  que
  vous  ayez  contribue a ce document (sous la forme d'un HowTo ou d'une
  FAQ).   Envoyez-moi  un  courrier  electronique  et  j'effectuerai  la
  correction.

  99..22..  TTrraadduuccttiioonn

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

  Note du traducteur : CCooccoorriiccoo !! La version francaise est  la  premiere
  traduction de ce document.

  99..33..  CCoonnttaaccttss

  Tout  contact  est le bienvenu. Envoyez-moi un courrier electronique a
  l'adresse suivante : dan@detached.demon.co.uk.  Ma clef  publique  PGP
  (ID     5F263625)     est     disponible    sur    mes    pages    WWW
  <http://ftp.linux.org.uk/~barlow/>,   Si   vous    souhaitez    rendre
  confidentiel certains messages.

  99..44..  CCooppyyrriigghhtt

  Toutes les remarques appartiennent a leurs auteurs respectifs.

  Ce    document    est    copyrighte    (C)    1996    Daniel    Barlow
  <dan@detached.demon.co.uk>. Il peut etre  reproduit  et  distribue  en
  partie  ou  entierement, sur tout support physique ou electronique, du
  moment  ou  ce  copyright  se  trouve  sur  toute   les   copies.   La
  redistribution  commerciale  est  autorisee  et  encouragee. Toutefois
  l'auteur de ce document doit etre  mis  au  courant  de  ce  genre  de
  distributions.

  Toute  traduction,  adaptation,  ou bien tout travail incorporant tout
  document HowTo Linux doit posseder ce  copyright.  De  cette  maniere,
  vous  ne  pouvez  pas  imposer  de restriction a la distribution de ce
  document.  Des exceptions peuvent etre eventuellement  accordees  sous
  certaines  conditions  : contactez le coordinateur des HowTo's Linux a
  l'adresse donnee ci-dessous.

  En resume, nous souhaitons voir diffuser l'information de  la  maniere
  la  plus large qui soit. Toutefois, nous souhaitons garder la maitrise
  de  ces  documents  et  nous  aimerions  etre  consultes  avant  toute
  diffusion des HowTo's.

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

  1100..  IInnddeexx

  Les entrees de cet index sont triees dans l'ordre alphabetique.

  +o  -fwritable-strings ``39'', ``56''

  +o  /lib/cpp ``16''

  +o  a.out ``1''

  +o  ar ``10''

  +o  as ``8''

  +o  <asm/*.h> ``19''

  +o  atoi() ``40''

  +o  atol() ``41''

  +o  executables trop gros ``63'', ``65'', ``77''

  +o  chewing gum ``3''

  +o  cos() ``68''

  +o  deboguer ``59''

  +o  divers ``72''

  +o  dlopen() ``82''

  +o  dlsym() ``83''

  +o  documentation ``4''

  +o  EINTR ``52''

  +o  elf ``0'', ``71''

  +o  execl() ``57''

  +o  fcntl ``47''

  +o  FD_CLR ``44''

  +o  FD_ISSET ``45''

  +o  FD_SET ``43''

  +o  FD_ZERO ``46''

  +o  fichier ``2''

  +o  <float.h> ``20''

  +o  gcc ``6''

  +o  gcc -fomit-frame-pointer ``61''

  +o  gcc -g ``60''

  +o  gcc -v ``14''

  +o  gcc, bogues ``15'', ``28'', ``29'', ``84''

  +o  gcc, options de compilation ``13'', ``25'', ``26''

  +o  gdb ``64''

  +o  fichiers d'en-tete ``17''

  +o  appels systemes interrompus ``51''

  +o  ld ``9''

  +o  LD_* : variables d'environnement ``80''

  +o  ldd ``81''

  +o  libc ``7''

  +o  libg.a ``62''

  +o  libgcc ``79''

  +o  <limits.h> ``21''

  +o  lint ``58''

  +o  <linux/*.h> ``18''

  +o  <math.h> ``70''

  +o  maths ``69''

  +o  mktemp() ``55''

  +o  numero de version ``12'', ``74''

  +o  optimisation ``27''

  +o  pages de manuel ``5''

  +o  QMAGIC ``76''

  +o  segmentation fault ``30'', ``54''

  +o  segmentation fault, in GCC ``33''

  +o  select() ``50''

  +o  SIGBUS ``34''

  +o  SIGEMT ``35''

  +o  SIGIOT ``36''

  +o  SIGSEGV ``31'', ``53''

  +o  SIGSEGV, in gcc ``32''

  +o  SIGSYS ``38''

  +o  SIGTRAP ``37''

  +o  sin() ``67''

  +o  soname ``73''

  +o  sprintf() ``42''

  +o  binaires linkes statiquement ``66'', ``78''

  +o  <stdarg.h> ``23''

  +o  <stddef.h> ``24''

  +o  strings ``11''

  +o  <sys/time.h> ``48''

  +o  <unistd.h> ``49''

  +o  <varargs.h> ``22''

  +o  ZMAGIC ``75''

