Sophie

Sophie

distrib > Mandriva > 9.0 > i586 > by-pkgid > 0d5cd12c82d627a82c59047e1ba7b8a9 > files > 398

howto-html-fr-9.0-0.2mdk.noarch.rpm

<HTML>
<HEAD>
<TITLE>Portage et compilation</TITLE>
</HEAD>
<BODY>
<H1>4. <A NAME="s4"></A>Portage et compilation</H1>
<P>
<A HREF="GCC-HOWTO.html#toc4">Contenu de cette section</A></P>

<A NAME="index.25"></A> <H2>4.1 <A NAME="ss4.1"></A> Symboles d&eacute;finis automatiquement </H2>

<P>Vous pouvez trouver quels symboles votre version de gcc d&eacute;finit
automatiquement en le lan&ccedil;ant avec l'option <CODE>-v</CODE>.
Par exemple cela donne &ccedil;a chez moi :
<BLOCKQUOTE><CODE>
<PRE>
$ echo 'main(){printf(&quot;Bonjour !\n&quot;);}' | 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__ -
</PRE>
</CODE></BLOCKQUOTE>

Si vous &eacute;crivez du code qui utilise des sp&eacute;cificit&eacute;s Linux, il
est souhaitable d'impl&eacute;menter le code non portable de la mani&egrave;re suivante 
<BLOCKQUOTE><CODE>
<PRE>
#ifdef __linux__
/* ... code linux ... */
#endif /* linux */
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Utilisez <CODE>__linux__</CODE> pour cela, et <EM>pas</EM> <CODE>linux</CODE>.
Bien que cette macro soit d&eacute;finie, ce n'est pas une sp&eacute;cification POSIX.</P>
<P></P>

<H2>4.2 <A NAME="ss4.2"></A> Options de compilation</H2>

<P> La documentation des options de compilation se trouve dans les 
pages <EM>info</EM> de gcc (sous Emacs, utilisez <CODE>C-h i</CODE> puis
s&eacute;lectionnez l'option `gcc').  Votre distribution peut ne pas 
avoir install&eacute; la documentation ou bien vous pouvez en avoir une
ancienne. Dans ce cas, la meilleure chose &agrave; faire est de r&eacute;cup&eacute;rer
les sources de gcc depuis 
<A HREF="ftp://prep.ai.mit.edu/pub/gnu">ftp://prep.ai.mit.edu/pub/gnu</A>
 ou
l'un des ses nombreux miroirs dont 
<A HREF="ftp://ftp.ibp.fr/pub/gnu">ftp://ftp.ibp.fr/pub/gnu</A>
.</P>
<P>La page de manuel gcc (<CODE>gcc.1</CODE>) est en principe, compl&egrave;tement 
d&eacute;pass&eacute;e. Cela vous met en garde si vous d&eacute;sirez la consulter.</P>
<P></P>
<A NAME="index.27"></A> <A NAME="index.26"></A> <H3>Options de compilation  </H3>

<P> gcc peut r&eacute;aliser un certain nombre d'optimisations sur le code g&eacute;n&eacute;r&eacute; 
en ajoutant l'option <CODE>-O</CODE><EM>n</EM> &agrave; la ligne de commandes, o&ugrave;
<EM>n</EM> est un chiffre. La valeur de <EM>n</EM>, et son effet exact, 
d&eacute;pend de la version de gcc, mais s'&eacute;chelonne normalement entre
0 (aucune optimisation) et 2 (un certain nombre) ou 3 (toutes les
optimisations possibles).</P>
<P>En interne, gcc interpr&egrave;te les options telles que <CODE>-f</CODE> et <CODE>-m</CODE>.  
Vous pouvez voir exactement ce qu'effectue le niveau sp&eacute;cifi&eacute; dans 
l'option <CODE>-O</CODE> en lan&ccedil;ant gcc avec l'option <CODE>-v</CODE> 
et l'option (non document&eacute;e)
<CODE>-Q</CODE>.  Par exemple, l'option <CODE>-O2</CODE>, effectue les op&eacute;rations
suivantes sur ma machine :
<BLOCKQUOTE><CODE>
<PRE>
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
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Utiliser un niveau d'optimisation sup&eacute;rieur &agrave; celui que le compilateur 
supporte (par exemple <CODE>-O6</CODE>) aura le m&ecirc;me effet qu'utiliser le plus 
haut niveau g&eacute;r&eacute;. Distribuer du code o&ugrave; la compilation est configur&eacute;e de
cette mani&egrave;re est une tr&egrave;s mauvaise id&eacute;e -- si d'autres optimisations
sont incorpor&eacute;es dans de versions futures, vous (ou d'autres utilisateurs)
pouvez vous apercevoir que cela ne compile plus, ou bien que le code
g&eacute;n&eacute;r&eacute; ne fait pas les actions d&eacute;sir&eacute;es.</P>
<P>
<A NAME="index.28"></A> 
 
Les utilisateurs de gcc 2.7.0 &agrave; 2.7.2 devraient noter qu'il y a un
bogue dans l'option <CODE>-O2</CODE>. Plus pr&eacute;cis&eacute;ment, la 
<EM>strength reduction</EM> ne fonctionne pas.  Un patch a &eacute;t&eacute; 
impl&eacute;ment&eacute; pour r&eacute;soudre ce probl&egrave;me, mais vous devez alors 
recompiler gcc. Sinon, vous devrez toujours compiler avec l'option
<CODE>-fno-strength-reduce</CODE>.</P>
<P></P>
<P></P>
<H3>Sp&eacute;cification du processeur</H3>

<P></P>
<P></P>
<P> Il existe d'autres options <CODE>-m</CODE> qui ne sont pas positionn&eacute;es
lors de l'utilisation de <CODE>-O</CODE> mais qui sont n&eacute;anmoins utiles dans certains
cas. C'est le cas pour les options <CODE>-m386</CODE> et <CODE>-m486</CODE>, 
qui indiquent &agrave; gcc de g&eacute;n&eacute;rer un code plus ou moins optimis&eacute;
pour l'un ou l'autre type de processeur. Le code continuera &agrave; fonctionner
sur les deux processeurs. Bien que le code pour 486 soit plus important, il
ne ralentit pas l'ex&eacute;cution du programme sur 386.</P>
<P>Il n'existe pas actuellement de <CODE>-mpentium</CODE> ou <CODE>-m586</CODE>.  Linus 
a sugg&eacute;r&eacute; l'utilisation des options 
<CODE>-m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2</CODE>,
pour exploiter les optimisations du 486 tout en perdant de la place
due aux probl&egrave;mes d'alignements (dont le Pentium n'a que faire). 
Michael Meissner (de Cygnus) nous dit :</P>
<P>
<BLOCKQUOTE>
" Mon avis est que l'option <CODE> -mno-strength-reduce </CODE> permet 
d'obtenir un code plus rapide sur un x86 (nota : je ne parle pas
du bogue <EM>strength reduction</EM>, qui est un autre probl&egrave;me). 
Cela s'explique en raison du peu de registres dont disposent ces processeurs
(et la m&eacute;thode de GCC qui consiste &agrave; grouper les registres dans l'ordre 
inverse au lieu d'utiliser d'autres registres n'arrange rien).
La <EM>strength reduction</EM> consiste en fait &agrave; rajouter 
des registres pour remplacer les multiplications par des additions.
Je suspecte &eacute;galement <CODE> -fcaller-saves</CODE> de ne pas arranger la 
situation. "
</BLOCKQUOTE>
</P>
<P>
<BLOCKQUOTE>
Une autre id&eacute;e est que <CODE>-fomit-frame-pointer</CODE> n'est pas obligatoirement
une bonne id&eacute;e.  
D'un c&ocirc;t&eacute;, cela peut signifier qu'un autre registre est disponible
pour une allocation. D'un autre c&ocirc;t&eacute;, vue la mani&egrave;re 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 fen&ecirc;tres relatives, ce qui signifie en clair 
que moins de cache est disponible pour l'ex&eacute;cution du processus.
Il faut pr&eacute;ciser que l'option <CODE>-fomit-frame-pointer</CODE>, signifie
que le compilateur doit constamment ajuster le pointeur de pile apr&egrave;s les
appels, alors qu'avec une fen&ecirc;tre, il peut laisser plusieurs appels 
dans la pile.
</BLOCKQUOTE>
</P>
<P>Le mot final sur le sujet provient de Linus :</P>
<P>
<BLOCKQUOTE>
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 r&eacute;elle optimisation que pour vous.
</BLOCKQUOTE>
</P>
<P></P>
<A NAME="index.33"></A> <A NAME="index.32"></A> <A NAME="index.31"></A> <A NAME="index.30"></A> <A NAME="index.29"></A> <H3><CODE>Internal compiler error: cc1 got fatal signal 11</CODE>     </H3>

<P> Signal 11 correspond au signal SIGSEGV, ou bien <EM>segmentation 
violation</EM>. Normalement, cela signifie que le programme s'est m&eacute;lang&eacute;
les pointeurs et a essay&eacute; d'&eacute;crire l&agrave; o&ugrave; il n'en a pas le droit. Donc, cela
pourrait &ecirc;tre un bug de gcc.</P>
<P>Toutefois, gcc est un logiciel assez test&eacute; et assez remarquable de ce c&ocirc;t&eacute;.
Il utilise un grand nombre de structures de donn&eacute;es complexes, et un
nombre impressionnant de pointeurs. En r&eacute;sum&eacute;, c'est le plus pointilleux
des testeurs de m&eacute;moire existants. Si vous <EM>n'arrivez pas &agrave; reproduire le 
bogue</EM> 
--- si cela ne s'arr&ecirc;te pas au m&ecirc;me endroit lorsque vous retentez la 
compilation --- c'est plut&ocirc;t un probl&egrave;me avec votre machine (processeur,
m&eacute;moire, carte m&egrave;re ou bien cache). <B>N'annoncez pas</B> la d&eacute;couverte
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 m&ecirc;me si le noyau s'arr&ecirc;te lors du
`<CODE>make zImage</CODE>' !  `<CODE>make zImage</CODE>'
doit compiler plus de 200 fichiers, et il en faut bien moins pour arriver
&agrave; faire &eacute;chouer une compilation.</P>
<P></P>
<P> Si vous arrivez &agrave; reproduire le bogue et (mieux encore) &agrave; &eacute;crire un
petit programme qui permet de mettre en &eacute;vidence cette erreur, alors
vous pouvez envoyer le code soit &agrave; la FSF, soit dans la liste linux-gcc.
Consultez la documentation de gcc pour plus de d&eacute;tails concernant les
informations n&eacute;cessaires.</P>
<P></P>

<H2>4.3 <A NAME="ss4.3"></A> Portabilit&eacute;</H2>

<P> Cette phrase a &eacute;t&eacute; dite un jour : si quelque chose n'a pas &eacute;t&eacute;
port&eacute; vers Linux alors ce n'est pas important de l'avoir :-).</P>
<P>Plus s&eacute;rieusement, en g&eacute;n&eacute;ral seules quelques modifications mineures sont
n&eacute;cessaires car Linux r&eacute;pond &agrave; 100% aux sp&eacute;cifications POSIX.
Il est g&eacute;n&eacute;ralement sympathique d'envoyer &agrave; l'auteur du programme
les modifications effectu&eacute;es pour que le programme fonctionne sur Linux, pour
que lors d'une future version, un `make' suffise pour g&eacute;n&eacute;rer l'ex&eacute;cutable.</P>
<P></P>
<H3>Sp&eacute;cificit&eacute;s BSD (notamment <CODE>bsd_ioctl</CODE>, <CODE>daemon</CODE> et<CODE>&lt;sgtty.h&gt;</CODE>)</H3>

<P> Vous pouvez compiler votre programme avec l'option
<CODE>-I/usr/include/bsd</CODE> et faire l'&eacute;dition de liens avec <CODE>-lbsd</CODE> 
(en ajoutant <CODE>-I/usr/include/bsd</CODE> &agrave; la ligne <CODE>CFLAGS</CODE>
et <CODE>-lbsd</CODE> &agrave; la ligne <CODE>LDFLAGS</CODE> dans votre fichier
<CODE>Makefile</CODE>). Il est &eacute;galement n&eacute;cessaire de ne <B>pas</B>
ajouter <CODE>-D__USE_BSD_SIGNAL</CODE> si vous voulez 
que les signaux BSD fonctionnent car vous les avez inclus automatiquement
avec la ligne
<CODE>-I/usr/include/bsd</CODE> et en incluant le fichier d'en-t&ecirc;te
<CODE>&lt;signal.h&gt;</CODE>.</P>
<P></P>
<A NAME="index.38"></A> <A NAME="index.37"></A> <A NAME="index.36"></A> <A NAME="index.35"></A> <A NAME="index.34"></A> <H3>Signaux <EM>manquants</EM> (<CODE>SIGBUS</CODE>, <CODE>SIGEMT</CODE>, <CODE>SIGIOT</CODE>, <CODE>SIGTRAP</CODE>, <CODE>SIGSYS</CODE>, etc.)     </H3>

<P> Linux respecte les sp&eacute;cifications 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) :</P>
<P>
<BLOCKQUOTE>
" Les signaux SIGBUS, SIGEMT, SIGIOT, SIGTRAP, et SIGSYS ont &eacute;t&eacute; omis 
de la norme POSIX.1 car leur comportement est d&eacute;pendant de l'impl&eacute;mentation
et donc ne peut &ecirc;tre r&eacute;pertori&eacute; d'une mani&egrave;re satisfaisante.
Certaines impl&eacute;mentations peuvent fournir ces signaux mais doivent
documenter leur effet "
</BLOCKQUOTE>
</P>
<P></P>
<P>La mani&egrave;re la plus &eacute;l&eacute;gante de r&eacute;gler ce probl&egrave;me est de
red&eacute;finir ces signaux &agrave; <CODE>SIGUNUSED</CODE>.  La mani&egrave;re <EM>normale</EM> de 
proc&eacute;der est d'entourer le code avec les <CODE>#ifdef</CODE> appropri&eacute;s :</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
#ifdef SIGSYS
/* ... code utilisant les signaux non posix  .... */
#endif
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P></P>
<A NAME="index.39"></A> <H3>Code K &amp; R </H3>

<P> GCC est un compilateur ANSI, or il existe beaucoup de code
qui ne soit pas ANSI. </P>
<P>Il n'y a pas grand chose &agrave; faire, sauf rajouter l'option
<CODE>-traditional</CODE> lors de la compilation. Il effectue certaines 
v&eacute;rifications suppl&eacute;mentaires. Consultez les pages info gcc.</P>
<P>Notez que l'option <CODE>-traditional</CODE> a pour unique effet de changer la forme
du langage accept&eacute; par gcc. Par exemple, elle active l'option
<CODE>-fwritable-strings</CODE>, qui d&eacute;place toutes les cha&icirc;nes de caract&egrave;res
vers l'espace de donn&eacute;es (depuis l'espace de texte, o&ugrave; elle ne 
peuvent pas &ecirc;tre modifi&eacute;es). Ceci augmente la taille de la m&eacute;moire 
occup&eacute;e par le programme.</P>
<P></P>
<A NAME="index.41"></A> <A NAME="index.40"></A> <H3>Les symboles du pr&eacute;processeur produisent un conflit avecles prototypes du code  </H3>

<P> Un des probl&egrave;mes fr&eacute;quents se produit lorsque certaines fonctions
standards sont d&eacute;finies comme macros dans les fichiers d'en-t&ecirc;te
de Linux et le pr&eacute;processeur refusera de traiter 
des prototypes identiques. Par exemple, cela peut arriver
avec <CODE>atoi()</CODE> et <CODE>atol()</CODE>.</P>
<P></P>
<A NAME="index.42"></A> <H3><CODE>sprintf()</CODE> </H3>

<P> Parfois, soyez prudent lorsque vous effectuez un portage &agrave; partir
des sources de programmes fonctionnant sous SunOs, surtout avec 
la fonction <CODE>sprintf(string, fmt, ...)</CODE> car elle renvoie 
un pointeur sur la cha&icirc;ne de caract&egrave;res alors que Linux (suivant la norme ANSI)
retourne le nombre de caract&egrave;res recopi&eacute;s dans la cha&icirc;ne de caract&egrave;res.</P>
<P></P>
<P></P>
<A NAME="index.49"></A> <A NAME="index.48"></A> <A NAME="index.47"></A> <A NAME="index.46"></A> <A NAME="index.45"></A> <A NAME="index.44"></A> <A NAME="index.43"></A> <H3><CODE>fcntl</CODE> et ses copains.  O&ugrave; se trouve la d&eacute;finition de <CODE>FD_*</CODE> et compagnie ?       </H3>

<P> Dans <CODE>&lt;sys/time.h&gt;</CODE>.  Si vous utilisez
<CODE>fcntl</CODE> vous voudrez probablement inclure 
<CODE>&lt;unistd.h&gt;</CODE> &eacute;galement, pour avoir le prototype de la fonction.</P>
<P>D'une mani&egrave;re g&eacute;n&eacute;rale, la page de manuel pour une fonction
donne la liste des fichiers d'en-t&ecirc;te &agrave; inclure.</P>
<P></P>
<A NAME="index.50"></A> <H3>Le timeout de <CODE>select()</CODE>. Les programmescommencent dans un &eacute;tat d'attente active </H3>

<P> A une certaine &eacute;poque, le param&egrave;tre timeout de la fonction 
<CODE>select()</CODE> &eacute;tait utilis&eacute; en lecture seule.  C'est pourquoi la page
de manuel comporte une mise en garde :</P>
<P>
<BLOCKQUOTE>
select() devrait retourner normalement le temps &eacute;coul&eacute; depuis le
timeout initial, s'il s'est d&eacute;clench&eacute;, en modifiant la valeur point&eacute;e par
le param&egrave;tre <CODE>time</CODE>. Cela sera peut-&ecirc;tre impl&eacute;ment&eacute; dans les
versions ult&eacute;rieures du syst&egrave;me. Donc, il n'est pas vraiment prudent de 
supposer que les donn&eacute;es point&eacute;es ne seront pas modifi&eacute;es lors de l'appel
&agrave; select().
</BLOCKQUOTE>
</P>
<P>Mais tout arrive avec le temps ! Lors d'un retour de 
<CODE>select()</CODE>, l'argument <CODE>timeout</CODE> recevra le
temps &eacute;coul&eacute; depuis la derni&egrave;re r&eacute;ception de donn&eacute;es. Si aucune
donn&eacute;e n'est arriv&eacute;e, la valeur sera nulle, et les futurs
appels &agrave; cette fonction utilisant le m&ecirc;me <CODE>timeout</CODE>
auront pour r&eacute;sultat un retour imm&eacute;diat.</P>
<P>Pour r&eacute;soudre le probl&egrave;me, il suffit de mettre la valeur <CODE>timeout</CODE>
dans la structure &agrave; chaque appel de <CODE>select()</CODE>.  
Le code initial &eacute;tait 
<BLOCKQUOTE><CODE>
<PRE>
      struct timeval timeout;
      timeout.tv_sec = 1; 
      timeout.tv_usec = 0;
      while (some_condition)
            select(n,readfds,writefds,exceptfds,&amp;amp;timeout); 
</PRE>
</CODE></BLOCKQUOTE>

et doit devenir :
<BLOCKQUOTE><CODE>
<PRE>
      struct timeval timeout;
      while (some_condition) 
      {
            timeout.tv_sec = 1; 
            timeout.tv_usec = 0;
            select(n,readfds,writefds,exceptfds,&amp;amp;timeout);
      }
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Certaines versions de Mosaic &eacute;taient connues &agrave; une certaine &eacute;poque
pour avoir ce probl&egrave;me. </P>
<P>La vitesse de rotation du globe terrestre &eacute;tait inversement
proportionnelle &agrave; la vitesse de transfert des donn&eacute;es !</P>
<P></P>
<A NAME="index.52"></A> <A NAME="index.51"></A> <H3>Appels syst&egrave;mes interrompus  </H3>

<H3>Symptomes :</H3>

<P>Lorsqu'un processus est arr&ecirc;t&eacute; avec un Ctrl-Z et relanc&eacute; - ou bien
lorsqu'un autre signal est d&eacute;clench&eacute; dans une situation diff&eacute;rente : 
par exemple avec un Ctrl-C, la terminaison d'un processus, etc, on
dit qu'il y a " interruption d'un appel syst&egrave;me " , ou bien
" write : erreur inconnue " ou des trucs de ce genre.</P>
<P></P>
<H3>Probl&egrave;mes :</H3>

<P>Les syst&egrave;mes POSIX v&eacute;rifient les signaux plus souvent que 
d'autres Unix plus anciens. Linux peux lancer les gestionnaires
de signaux :
<UL>
<LI> d'une mani&egrave;re asynchrone (sur un top d'horloge)</LI>
<LI> lors d'un retour de n'importe quel appel syst&egrave;me</LI>
<LI> pendant l'ex&eacute;cution des appels syst&egrave;mes suivants :
<CODE>select()</CODE>, <CODE>pause()</CODE>, <CODE>connect()</CODE>,
<CODE>accept()</CODE>, <CODE>read()</CODE> sur des terminaux, des sockets, des pipes 
ou des fichiers situ&eacute;s dans <CODE>/proc</CODE>, <CODE>write()</CODE> sur des
terminaux, des sockets, des pipes ou des imprimantes, <CODE>open()</CODE> 
sur des FIFOs, des lignes PTYs ou s&eacute;ries,
<CODE>ioctl()</CODE> sur des terminaux, <CODE>fcntl()</CODE> avec la commande
<CODE>F_SETLKW</CODE>, <CODE>wait4()</CODE>, <CODE>syslog()</CODE>, et toute op&eacute;ration
d'ordre TCP ou NFS.  </LI>
</UL>
</P>
<P>Sur d'autres syst&egrave;mes d'exploitation, il est possible que vous
ayez &agrave; inclure dans cette cat&eacute;gorie les appels syst&egrave;mes suivants :
<CODE>creat()</CODE>, <CODE>close()</CODE>, <CODE>getmsg()</CODE>, <CODE>putmsg()</CODE>,
<CODE>msgrcv()</CODE>, <CODE>msgsnd()</CODE>, <CODE>recv()</CODE>, <CODE>send()</CODE>,
<CODE>wait()</CODE>, <CODE>waitpid()</CODE>, <CODE>wait3()</CODE>, <CODE>tcdrain()</CODE>,
<CODE>sigpause()</CODE>, <CODE>semop()</CODE>.</P>
<P></P>
<P></P>
<P>Si un signal (que le programme d&eacute;sire traiter) est lanc&eacute; pendant
l'ex&eacute;cution d'un appel syst&egrave;me, le gestionnaire est lanc&eacute;. Lorsque
le gestionnaire du signal se termine, l'appel syst&egrave;me d&eacute;tecte qu'il a &eacute;t&eacute;
interrompu et se termine avec la valeur -1 et <CODE>errno = EINTR</CODE>. 
Le programme n'est pas forc&eacute;ment au courant de ce qui s'est pass&eacute; et
donc s'arr&ecirc;te.</P>
<P>Vous pouvez choisir deux solutions pour r&eacute;soudre ce probl&egrave;me.</P>
<P>(1)Dans tout gestionnaire de signaux que vous mettez en place, ajoutez
l'option <CODE>SA_RESTART</CODE> au niveau de <EM>sigaction</EM>. Par exemple, 
modifiez
<BLOCKQUOTE><CODE>
<PRE>
  signal (signal_id, mon_gestionnaire_de_signaux);
</PRE>
</CODE></BLOCKQUOTE>

en
<BLOCKQUOTE><CODE>
<PRE>
  signal (signal_id, mon_gestionnaire_de_signaux);
  { 
        struct sigaction sa;
        sigaction (signal_id, (struct sigaction *)0, &amp;amp;sa);
#ifdef SA_RESTART
        sa.sa_flags |= SA_RESTART;
#endif
#ifdef SA_INTERRUPT
        sa.sa_flags &amp;amp;= ~ SA_INTERRUPT;
#endif
        sigaction (signal_id, &amp;amp;sa, (struct sigaction *)0);
  }
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Notez que lors de certains appels syst&egrave;mes vous
devrez souvent regarder si <CODE>errno</CODE> n'a pas &eacute;t&eacute; positionn&eacute;e &agrave; 
<CODE>EINTR</CODE> par vous m&ecirc;me comme avec <CODE>read()</CODE>, <CODE>write()</CODE>,
<CODE>ioctl()</CODE>, <CODE>select()</CODE>, <CODE>pause()</CODE> et <CODE>connect()</CODE>. </P>
<P>(2) A la recherche de <CODE>EINTR</CODE> :</P>
<P>Voici deux exemples avec <CODE>read()</CODE> et <CODE>ioctl()</CODE>,</P>
<P>Voici le code original utilisant <CODE>read()</CODE></P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
int result;
while (len &gt; 0) 
{ 
  result = read(fd,buffer,len);
  if (result &lt; 0) 
        break;
  buffer += result; 
  len -= result;
}
</PRE>
</CODE></BLOCKQUOTE>

et le nouveau code </P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
int result;
while (len &gt; 0) 
{ 
  result = read(fd,buffer,len);
  if (result &lt; 0) 
  { 
        if (errno != EINTR) 
                break; 
  }
  else 
  { 
        buffer += result; 
        len -= result; 
  }
}
</PRE>
</CODE></BLOCKQUOTE>

Voici un code utilisant  <CODE>ioctl()</CODE></P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
int result;
result = ioctl(fd,cmd,addr);
</PRE>
</CODE></BLOCKQUOTE>

et cela devient
<BLOCKQUOTE><CODE>
<PRE>
int result;
do 
{ 
   result = ioctl(fd,cmd,addr); 
}
while ((result == -1) &amp;&amp; (errno == EINTR));
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Il faut remarquer que dans certaines versions d'Unix de type BSD 
on a l'habitude de relancer l'appel syst&egrave;me. Pour r&eacute;cup&eacute;rer les interruptions
d'appels syst&egrave;mes, vous devez utiliser les options 
<CODE>SV_INTERRUPT</CODE> ou <CODE>SA_INTERRUPT</CODE>.</P>
<P></P>
<A NAME="index.56"></A> <A NAME="index.55"></A> <A NAME="index.54"></A> <A NAME="index.53"></A> <H3>Les cha&icirc;nes et leurs acc&egrave;s en &eacute;critures (ou les programmes qui provoquent des" segmentation fault " d'une mani&egrave;re al&eacute;atoire)    </H3>

<P> GCC a une vue optimiste en ce qui concerne ses utilisateurs, en 
croyant qu'ils respectent le fait qu'une cha&icirc;ne dite constante l'est
r&eacute;ellement. Donc, il les range  dans la zone <EM>texte(code)</EM> du 
programme, o&ugrave; elles peuvent &ecirc;tre charg&eacute;es puis d&eacute;charg&eacute;es 
&agrave; partir de l'image binaire de l'ex&eacute;cutable situ&eacute;e sur disque (ce qui &eacute;vite
d'occuper de l'espace disque). Donc, toute tentative d'&eacute;criture dans 
cette cha&icirc;ne provoque un " segmentation
fault ".</P>
<P>Cela peut poser certains probl&egrave;mes avec d'anciens codes, par exemple
ceux qui utilisent la fonction <CODE>mktemp()</CODE> avec une cha&icirc;ne constante
comme argument.  <CODE>mktemp()</CODE> essaye d'&eacute;crire dans la cha&icirc;ne pass&eacute;e
en argument.</P>
<P>Pour r&eacute;soudre ce probl&egrave;me, 
<OL>
<LI>compilez avec l'option <CODE>-fwritable-strings</CODE> pour indiquer
&agrave; gcc de mettre les cha&icirc;nes constantes dans l'espace de donn&eacute;es</LI>
<LI> r&eacute;&eacute;crire les diff&eacute;rentes parties du code pour allouer 
une cha&icirc;ne non constante puis effectuer un strcpy des donn&eacute;es
dedans avant d'effectuer l'appel.</LI>
</OL>
</P>
<P></P>
<A NAME="index.57"></A> <H3>Pourquoi l'appel &agrave; <CODE>execl()</CODE> &eacute;choue ? </H3>

<P> Tout simplement parce que vous l'utilisez mal. Le premier argument
d'<CODE>execl</CODE> est le programme que vous d&eacute;sirez ex&eacute;cuter. Le second et ainsi
de suite sont en fait le &eacute;l&eacute;ments du tableau <CODE>argv</CODE> que vous appelez.
Souvenez-vous que <CODE>argv[0]</CODE> est traditionnellement fix&eacute; m&ecirc;me si
un programme est lanc&eacute; sans argument. Vous devriez donc &eacute;crire :
<BLOCKQUOTE><CODE>
<PRE>
execl(&quot;/bin/ls&quot;,&quot;ls&quot;,NULL);
</PRE>
</CODE></BLOCKQUOTE>

et pas 
<BLOCKQUOTE><CODE>
<PRE>
execl(&quot;/bin/ls&quot;, NULL);
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P></P>
<P> Lancer le programme sans argument est consid&eacute;r&eacute; comme &eacute;tant une
demande d'affichage des biblioth&egrave;ques dynamiques associ&eacute;es au programme,
si vous utilisez le format a.out. ELF fonctionne d'une mani&egrave;re diff&eacute;rente.</P>
<P></P>
<P>(Si vous d&eacute;sirez ces informations, il existe des outils plus simples;
consultez la section sur le chargement dynamique, ou la page de manuel
de <CODE>ldd</CODE>).</P>
<P></P>
<P></P>

<HR>
<P>
Chapitre <A HREF="GCC-HOWTO-5.html">suivant</A>,
Chapitre <A HREF="GCC-HOWTO-3.html">Pr&eacute;c&eacute;dent</A>
<P>
Table des mati&egrave;res de <A HREF="GCC-HOWTO.html#toc4">ce chapitre</A>,
 <A HREF="GCC-HOWTO.html#toc">Table des mati&egrave;res</A> g&eacute;n&eacute;rale</P>
<P>
<A HREF="GCC-HOWTO.html">D&eacute;but</A> du document,
 <A HREF="#0"> D&eacute;but de ce chapitre</A></P>
</BODY>
</HTML>