GCC HOWTO pour Linux
 par Daniel Barlow <[email protected]>
 v1.17, 28 fevrier 1996

 (Adaptation  francaise  par  Eric  Dumas  <[email protected]>,  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  [email protected].   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  [email protected].   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 : [email protected].  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
 <[email protected]>. 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 :
 [email protected]

 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''