\typeout{+==============================================+}
\typeout{|============ DEVELOPPER ======================|}
\typeout{+==============================================+}
% Les cinq premières lignes du source TeX
\chapter{Développer !}
\label{chap-developper}


\typeout{<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<}
\begin{epigraphe}{\recursion}
  \verb+% Les 5 premières lignes du source TeX+\\
  \verb+\chapter{Développer !}+\\
  \verb+\label{chap-developper}+\\
  \verb+\begin{epigraphe}{\recursion}+\\
  \verb`\verb&\verb@\verb|\verb#\verb°\verb/\verb+% Les 5 premières+\\/°#|@&`
\end{epigraphe}
\typeout{>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}



\begin{introchap}{Développer}
  de \emph{to develop}, « mettre au point » en anglais, est peut-être
  l'activité qu'il est idéal de réaliser sous un système \unix{}.  Il
  dispose en effet d'une palette impressionnante
  \voir[Chap.]{chap-guide-survie}{d'outils} ---~dédiés à une tâche
  spécifique~--- qu'on peut voir comme des composants logiciels
  pouvant communiquer entre eux de manière élégante et homogène.  Nous
  verrons en ouverture de ce chapitre une présentation détaillée des
  concepts fondamentaux de la programmation en shell ; la partie
  suivante est consacrée à l'étude de l'utilitaire \soft{make}, outil
  puissant permettant de gérer un projet de développement. Ce chapitre
  est clos par la présentation de l'utilisation d'un compilateur~C sur
  un système \unix{}. Pour développer sous \unix{}, il faut en outre
  savoir comment \emph{éditer} un fichier, ce pré-requis fait l'objet
  de la première section de ce chapitre.
\end{introchap}

  \begin{attention}
    Certaines sections de ce chapitre exigent que vous ayez quelques
    notions de programmation ou d'algorithmique : savoir ce qu'est une
    variable et une boucle ne seront pas inutile pour comprendre la
    section~\ref{sec-dev-shell} sur les scripts en shell. La
    section~\ref{sec-compiler-C} sur les projets en langage~C présuppose
    que vous connaissez ce langage, sa lecture est donc très
    certainement inutile si ça n'est pas le cas.
  \end{attention}

\section{Éditer un fichier}
\label{sec-dev-editer}
\index{editer@éditer un fichier}
\index{fichier!etditer@éditer}

Vous entendrez sans doute un jour quelqu'un vous dire : « sous
\unix{}, tout est fichier\footnote{Si vous ne l'avez jamais
  entendu, tentez de la placer lors d'une soirée entre amis, cela fait
  toujours de l'effet.} ». En outre, comme nous avons vu que les
commandes communiquent entre elles à l'aide de flots de texte, la
tâche qui consiste à éditer (c'est-à-dire créer/modifier) un fichier
contenant du texte est une tâche extrêmement courante sous \unix{}.


\subsection{Sans éditeur}

Même si cela reste rare, il peut arriver d'avoir à créer un fichier
contenant du texte sans éditeur de texte. Dans ce cas on peut utiliser
les \voir{sec-redirection}{redirections}, par exemple :
\begin{shellcom}
  ¢usercom«echo bonjour > fichier.txt»
\end{shellcom}
stocke la chaîne « \texttt{bonjour} » dans le fichier
\texttt{fichier.txt}. On peut même, éventuellement ajouter des sauts
de lignes (caractère~«\verb+\n+»), ou des tabulations
(caractères~«\verb+\t+») en utilisant l'option~\texttt{-e} de
\com{echo} :
\begin{shellcom}
  ¢usercom«echo -e "a\nb\nc\td" > bonjour.txt»
  ¢usercom«cat bonjour.txt»
  a
  b
  c       d
\end{shellcom}
\begin{gnuposix}
  Pour être sûr d'arriver à ses fins dans ce genre de situation il est
  souvent préférable d'utiliser la commande \com{printf} plutôt que la
  commande \com{echo}, en écrivant :
  \begin{shellcom}
    ¢usercom«printf "a\nb\nc\td\n" > bonjour.txt»
  \end{shellcom}
  \continuenota Ceci parce que la commande \com{echo} de votre système
  peut ne pas réagir à l'option \texttt{-e}.
\end{gnuposix}
Une autre manière de faire est d'utiliser la commande \com{cat} avec
une redirection :
\begin{shellcom}
  ¢usercom«cat > bonjour.txt» ¢comcomment«attente de données destinées à ¢texttt«bonjour.txt»»
  ¢comans«a» ¢touche«Entrée»
  ¢comans«b» ¢touche«Entrée»
  ¢touche«Ctrl»¢touche«d» ¢comcomment«caractère de fin de fichier»
\end{shellcom}
Ces méthodes ne permettent évidemment pas de modifier le contenu du
fichier créé, autrement qu'en l'écrasant avec de nouvelles données.

\subsection{Avec un éditeur}

Deux éditeurs sont très répandus sur les systèmes \unix{}, il s'agit
de \soft{vi} (prononcer « vi aïe ») et \soft{Emacs} (prononcer « et
max » ou « i max »). Les paragraphes \vref{sec-conf-vi} et
\vref{sec-conf-emacs} présentent respectivement ces deux éditeurs.
Dans l'immédiat voici ce qu'il faut savoir pour éditer un fichier avec
\emacs{} :
\begin{shellcom}[noendprompt]
  ¢usercom«emacs bonjour.txt»
\end{shellcom}
tapez alors tranquillement votre texte, puis pour le sauvegarder,
appuyez sur les touches \toucheCtrl{}\touche{x}\touche{s}
(c'est-à-dire \touche{x} puis \touche{s} tout en maintenant
\toucheCtrl{} enfoncée). Pour charger un fichier existant, utilisez la
commande \toucheCtrl{}\touche{x}\touche{f} Les menus
\texttt{Files/Save Buffer} et \texttt{Files/Open File...} vous
permettront d'effectuer également ces opérations.


\section{Faire des scripts en shell}
\label{sec-dev-shell}
\index{shell!scripts|(}
\index{scripts shell|(}

Cette section a pour but d'exposer les rudiments de la programmation
en shell. Le shell utilisé est \soft{bash}. C'est le shell développé
par le projet \gnu{}. Il incorpore les fonctionnalités du
shell~\soft{sh} ainsi que certaines tirées des shells \soft{csh} et
\soft{ksh}. La modeste expérience de l'auteur a montré qu'il est
nécessaire d'expérimenter pour parvenir à ses fins avec le shell ; il
permet cependant, une fois la phase d'apprentissage
passée\footnote{Passe-t-elle un jour ?}, d'automatiser certaines des
tâches quotidiennes d'un utilisateur de système \unix{} et pour cette
raison il est très utile d'en connaître les principes de base. La
lecture des chapitres~\ref{chap-guide-survie} et~\ref{chap-toolbox} est
un pré-requis indispensable à la lecture de cette section.
\begin{attention}
  Si vous utilisez un shell de connexion de type \com{tcsh} ou
  \com{csh}, rien ne vous empêche de programmer avec \com{sh} ou
  \com{bash}. C'est pourquoi nous focaliserons ici notre attention sur
  le shell \com{bash} de la famille \texttt{sh} qui, encore une fois, ne
  vous engage pas à changer vos habitudes « interactives » si vous
  utilisez un autre shell de connexion.
\end{attention}

Enfin, pour vous donner une idée de la complexité du programme
\soft{bash}, la commande :
\framaallongepage{1}
\begin{shellcom}
  ¢usercom«PAGER=cat man bash | wc -lw»
  Reformatting bash(1), please wait...
   4522   33934
\end{shellcom}
que vous êtes pratiquement capable de comprendre si vous avez lu
jusqu'ici, nous indique que la page de manuel de \soft{bash} sur le
système de votre serviteur, contient 33934~mots soit environ
4500~lignes sur un terminal d'environ 90~caractères de large. Pour
info :
\begin{shellcom}
  ¢usercom«pdftotext guide-unix.pdf - | wc -w»
  68837
\end{shellcom}
\texttt{guide-unix.pdf} est le document que vous avez sous les yeux...

\subsection{Commentaires}
\label{sec-shell-comment}
\index{commentaire en shell}
\index{shell!commentaire}
\index{;@\texttt{\#}}

Tout langage de programmation dispose de symboles particuliers pour
insérer des commentaires dans le code ; c'est-à-dire des portions de
texte qui seront ignorées par l'interpréteur ou le compilateur le cas
échéant. Ce caractère en langage de commande d'\unix{} est le
caractère~\verb+#+. Tout le texte suivant ce caractère jusqu'à la fin
de la ligne sera ignoré. Notons toutefois que s'il est suivi du
caractères~\verb+!+, ce qui suit est interprété d'une manière
particulière par le système comme expliqué au paragraphe suivant.

\subsection{Choisir l'interpréteur}
\index{interpréteur}

Un script en shell n'est qu'un fichier texte contenant une liste de
commandes. Par exemple, un fichier \texttt{bidule} contenant la
commande :
\begin{fichier}[label=bidule]
  echo bonjour
\end{fichier}
est un script shell ! Pour exécuter ce script on lance l'interpréteur
de commande avec le fichier comme argument  :
\begin{shellcom}
  ¢usercom«bash bidule»
  bonjour
\end{shellcom}
De manière à simplifier l'utilisation du script \texttt{bidule} on 
peut préciser quel sera l'interpréteur du programme contenu dans le
fichier. Pour cela on place en tête du fichier les deux caractères
\verb+#!+ suivis de la référence absolue de l'interpréteur utilisé :
\begin{fichier}[label=bidule]
  #!/bin/bash
  echo bonjour
\end{fichier}
il faudra ensuite rendre exécutable le script :
\begin{shellcom}
  ¢usercom«chmod +x bidule»
\end{shellcom}
Ces deux opérations permettent d'utiliser le script en l'appelant
directement comme une commande :
\begin{shellcom}
  ¢usercom«./bidule»
  bonjour
\end{shellcom}
Notons, qu'on peut généraliser cette idée à n'importe quel
interpréteur, par exemple, le fichier \texttt{test.awk} :
\begin{fichier}[label=test.awk]
  #!/usr/bin/awk -f
  /^Jim/{print $1,$3}
\end{fichier}
Une fois rendu exécutable, il donne bien ce qu'on attend du premier
exemple de la section~\vref{sec-awk} :
\begin{shellcom}
  ¢usercom«./test.awk fichier.dat»
  Jimi 1970
  Jim 1971
\end{shellcom}
ici c'est donc la commande \texttt{awk -f} qui est chargée
d'interpréter les commandes contenues dans \texttt{test.awk}.
% \begin{nota}
%   Par défaut c'est le shell de connexion qui est utilisé comme
%   interpréteur. Cependant, même si vous utilisez \texttt{bash} comme
%   \emph{login shell} il est conseillé d'insérer l'interpréteur par
%   souci de portabilité (par exemple pour qu'un utilisateur ayant
%   \texttt{csh} comme shell de connexion puisse utiliser votre script).
% \end{nota}





\subsection{Variables}
\label{sec-shell-var}
\index{variable!du shell}
\index{shell!variables}

Les variables du shell sont des symboles auxquels on affecte des
valeurs. Ces variables ne sont pas ou très faiblement typées comme
nous le verrons un peu plus bas. L'affectation et la lecture des
variables se fait grâce à la syntaxe suivante (voir
aussi~\vref{sec-unix-env}) :
\begin{fichier}[label=testvar.sh]
  #!/bin/bash
  N=4
  NOM=trucmuche
  echo "le nom est $NOM et la variable N vaut $N"
\end{fichier}
qui donne à l'exécution :
\begin{shellcom}
  ¢usercom«./testvar.sh»
  le nom est trucmuche et la variable N vaut 4
\end{shellcom}
Dans certaines situations il est nécessaire d'utiliser les accolades
en plus du dollar pour lire le contenu de la variable. La syntaxe est
alors \verb+${N}+.%$, par exemple :
\begin{fichier}
  #!/bin/bash
  BOF=loz
  echo mon nom est ${BOF}ano
\end{fichier}
%$
Sans les accolades, le shell aurait cherché la valeur de la variable
\verb+$BOFano+, %$
variable qui n'existe pas.  En shell, les variables ne sont pas
\emph{déclarées} au sens d'un langage de programmation compilé. En
fait toutes les variables existent potentiellement. Par conséquent, le
shell n'émet pas de message d'erreur lorsqu'on tente d'accéder à une
variable à laquelle on n'a jamais affecté de valeur. Cette variable
est considérée comme étant « vide » à l'expansion :
\begin{fichier}[label=varvide.sh]
  #!/bin/bash
  BOF=loz
  echo mon nom est $BOFano
\end{fichier}
                                %$
donne à l'exécution :
\begin{shellcom}
  ¢usercom«./varvide.sh»
  mon nom est
\end{shellcom}
ceci rend le débuggage de scripts parfois délicat. Pour pallier ce
problème on peut utiliser la commande :
\begin{shellcom}
  ¢usercom«set -u»
\end{shellcom}
pour demander au shell de générer une erreur lorsqu'on veut faire
référence à une variable non intialisée :
\begin{shellcom}
  ¢usercom«set -u»
  ¢usercom«echo $variablenonintialisee»
  -bash: variablenonintialisee: unbound variable
\end{shellcom}
%$

\subsubsection{Arguments de la ligne de commande}
\label{sec-shell-args}
\index{arguments!de la ligne de commande}
\index{shell!arguments (ligne de commande)}

Les arguments passés en ligne de commandes ---~c'est-à-dire lors de
l'appel de la commande que constitue le script~--- sont stockés dans les
variables \verb+$0+, \verb+$1+, \verb+$2+, etc. Ainsi : %$
\begin{fichier}[label=testarg.sh]
  #!/bin/sh
  echo Arguments "[$0] [$1] [$2] [$3] [$4]"
\end{fichier}
donne : %$
\begin{shellcom}
  ¢usercom«./testarg.sh -t bonjour "les amis" 34»
  Arguments [./testarg.sh] [-t] [bonjour] [les amis] [34]
\end{shellcom}
On peut noter qu'à l'instar du langage C, l'argument numéro $0$ est le
programme à exécuter, ici \texttt{./testarg.sh}.
\index{;@\texttt{""}}
\begin{attention}
  Notez en outre l'utilisation des guillemets en ligne de commande.
  Lors de l'exécution de \texttt{testarg.sh} on utilise ces guillemets
  pour regrouper les mots \texttt{les} et \texttt{amis} en une seule
  chaîne de caractères, on peut alors les considérer comme un seul
  argument.
\end{attention}
Pour le traitement des paramètres de la ligne de commande, on dispose
également de quelques variables prédéfinies :
\begin{itemize}
\index{;@\texttt{\$\#}}
\item la variable \verb+$#+ %$
  contient le nombre d'arguments de la ligne de commande sans compter
  la commande elle même ---~les arguments sont donc comptés à partir de
  \verb+$1+;%$
\index{;@\texttt{\$*}}
\index{;@\texttt{\$"@}}
\item les variables \verb+$*+ et \verb+$@+ contiennent toutes les deux
  l'ensemble des arguments à partir de \verb+$1+ %$
  mais ont une signification différente lorsqu'elles sont utilisées
  entre guillemets :
  \begin{fichier}[label=testarg2.sh]
    #!/bin/sh
    for ARG in "$*" ; do echo $ARG ; done
  \end{fichier}
  donne : 
  \begin{shellcom}
    ¢usercom«./testarg2.sh a b c»
    a b c
  \end{shellcom}
  dans ce cas l'ensemble des arguments est considéré comme une seule
  chaîne de caractères et :
  \begin{fichier}[label=testarg3.sh]
    #!/bin/sh
    for ARG in "$@" ; do echo $ARG ; done
  \end{fichier}
  donne : 
  \begin{shellcom}
    ¢usercom«./testarg3.sh a b c»
    a
    b
    c
  \end{shellcom}
  ici chaque argument est considéré comme une chaîne de caractères à
  part entière.
\end{itemize}


\subsubsection{Modifications}
\label{sec-shell-var-mod}
\index{variable!shell!modification}
\index{shell!variable!modification}

Il existe plusieurs mécanismes permettant d'agir sur les variables :
\begin{enumerate}
\item l'aide à l'instanciation de variables ;
\item le traitement du contenu.
\end{enumerate}
Chacun de ces mécanismes suit une syntaxe particulière (la plupart du
temps assez difficilement mémorisable !). Voici donc à titre d'exemple
quelques-uns des outils\footnote{Se reporter au \texttt{man} de
  \texttt{bash} pour des informations précises.} correspondant :
\begin{itemize}
\item \verb+${N:-4}+ renvoie la valeur de \texttt{N} si on lui en a
  affecté une, 4 sinon ; %$
  ce qui permet d'utiliser une valeur par défaut ;
\item \verb+${N:?+\comarg{msg}\verb+}+ %$
  renvoie le message d'erreur \comarg{msg} si \texttt{N} n'a pas été
  instancié et quitte le script ; ceci peut être utile pour tester les
  arguments de la ligne de commande.
\end{itemize}
Voici un exemple d'utilisation de ces outils :
\begin{fichier}[label=varmod.sh]
  #!/bin/sh
  NOM=${1:?"vous devez fournir un nom"}
  PRENOM=${2:-"djobi"}
  echo Qui : $PRENOM $NOM
\end{fichier}
ce qui peut donner à l'exécution :
\begin{shellcom}
  ¢usercom«./varmod.sh»
  ./varmod.sh: 1: vous devez fournir un nom
\end{shellcom}
le texte \verb+./varmod.sh: 1:+ doit se comprendre comme : «
l'argument \no{}1 du script \verb+varmod.sh+ est manquant » 
\begin{shellcom}
  ¢usercom«./varmod.sh djoba»
  Qui : djobi djoba
  ¢usercom«./varmod.sh goulbi goulba»
  Qui : goulba goulbi
\end{shellcom}
Pour ce qui est des outils de traitement de contenu la syntaxe est :
\begin{itemize}
\item \verb+${N%+\comarg{motif}\verb+}+ et \verb+${N%%+\comarg{motif}\verb+}+ 
    suppriment respectivement la plus petite et la plus longue chaîne
    répondant à l'expression régulière \comarg{motif}, à la \emph{fin}
    du contenu de la variable \texttt{N} ;
\item \verb+${N#+\comarg{motif}\verb+}+ et \verb+${N##+\comarg{motif}\verb+}+ 
    suppriment respectivement la plus petite et la plus longue chaîne
    répondant à l'expression régulière \comarg{motif}, au \emph{début}
    du con\-te\-nu de la variable~\texttt{N}.
\end{itemize}
et voici un exemple très instructif inspiré par \citet{bash} :
\begin{shellcom}
  ¢usercom«P=/home/local/etc/crashrc.conf.old»
  ¢usercom«echo ${P%%.*}» ¢comcomment«supprime la plus grande chaîne  commençant par `.'»
  /home/local/etc/crashrc
  ¢usercom«echo ${P%.*}» ¢comcomment«supprime la plus petite chaîne  commençant par `.'»
  /home/local/etc/crashrc.conf
  ¢usercom«echo ${P##/*/}» ¢comcomment«supprime la plus grande chaîne entourée de `/'»
  crashrc.conf.old
  ¢usercom«echo ${P#/*/}» ¢comcomment«supprime la plus petite chaîne entourée de `/'»
  local/etc/crashrc.conf.old
\end{shellcom}
Une application de ce type d'outils serait, par exemple, la conversion
en salve, de plusieurs fichiers JPEG en TIFF. En supposant que :
\begin{itemize}
\item les fichiers portent l'extension~\texttt{.jpg} ;
\item sont dans le répertoire courant ;
\item on dispose d'un utilitaire que l'on nommera \texttt{convert} qui
  est capable d'effectuer cette conversion ;
\end{itemize}
on peut alors écrire le script (voir \S~\vref{sec-structure-for} pour
l'utilisation de la boucle \texttt{for}) : 
\index{shell!boucle \texttt{for}}
\index{boucle \texttt{for}}
\begin{fichier}
  #!/bin/sh
  for F in *.jpg ; do
    convert "$F" "${F%.jpg}.tif"
  done
\end{fichier}
Dans ce script, si la variable \texttt{F} vaut à une itération
\texttt{bidule.1.jpg} alors :
\begin{itemize}
\item \verb+${F%.jpg}+ vaut \texttt{bidule.1}, c'est-à-dire le nom du
    fichier auquel on a supprimé la chaîne \texttt{.jpg} à la fin ;
\item \verb+{F%.jpg}.tif+ vaut \texttt{bidule.1.tif}, c'est-à-dire,
    \texttt{bidule.1} concaténé avec la chaîne \texttt{.tif}.
\end{itemize}
Finalement, à cette itération on exécute la commande :
\begin{verbatim}
   convert bidule.1.jpg bidule.1.tif
\end{verbatim}
Ce principe est très utile dans beaucoup de situations où l'on veut
traiter plusieurs fichiers. Par exemple le très classique cas où l'on
veut renommer un ensemble de fichiers :
\begin{shellcom}
  ¢usercom«ls *.wav»
  audio1.wav audio2.wav audio3.wav
  audio4.wav audio5.wav audio6.wav
  audio7.wav audio8.wav audio9.wav
\end{shellcom}
Imaginons que l'on veuille renommer ces fichiers sous la forme
suivante :
\begin{flushleft}
  \verb+crescent_+$x$\verb+.wav+
\end{flushleft}
On peut alors écrire :
\begin{fichier}
  #!/bin/sh
  for F in audio*.wav ; do
    mv $F crescent_${F#audio}
  done
\end{fichier}

\begin{note}
  Un moyen mnémotechnique de se souvenir de la syntaxe de ces
  opérateurs est la suivante : \texttt{\#} désigne en anglais le
  numéro (\emph{number}) et on dit généralement « numéro 5 » ;
  \texttt{\#} supprime donc en \emph{début} de chaîne ; inversement on
  dit généralement « 5~\% » , \texttt{\%} supprime donc en
  \emph{fin} de chaîne. Le nombre de caractères
\verb+#+ ou \verb+%+ 
rappelle si on supprime la plus \emph{petite} (1 caractère) ou la plus
\emph{longue} (2 caractères) chaîne correspondant au motif. 'Tain
c'est pô convivial ce bazar !
\end{note}


\subsubsection{Arithmétique}
\label{sec-shell-var-arithmetique}
\index{shell!variable!arithmétique}
\index{variable!shell!arithmétique}

Bien que les variables du shell ne soient pas typées, on peut
cependant évaluer des expressions arithmétiques ; ces expressions
n'auront un sens que si les contenus des variables sont des valeurs
numériques, bien entendu. La syntaxe pour évaluer une expression
arithmétique est :
\begin{flushleft}
  \verb+$[+\comarg{expression\_arithmétique}\verb+]+\\%$
  \quad ou\\
  \verb+$((+\comarg{expression\_arithmétique}\verb+))+ (à préférer)\\%$
\end{flushleft}
Par exemple :
\begin{shellcom}
  ¢usercom«N=3»
  ¢usercom«echo $((N+1))»
  4
  ¢usercom«N=$[N+4]»
  ¢usercom«echo $N»
  7
\end{shellcom}
%$
Pour illustrer l'utilisation de l'arithmétique sur les variables,
considérons par exemple que l'on dispose d'un
ensemble de fichiers dont les noms ont la forme suivante :
\begin{shellcom}
  ¢usercom«ls *.dat»
  2002-qsdfff.dat 2002-sdhjlk.dat  2002-yuiqso.dat
  2003-azerzz.dat 2003-sddfg.dat   2003-qsdfrtuy.dat
  2003-ertyf.dat  2004-ersssty.dat 2004-sdf.dat
  ...
\end{shellcom}
\framasautdepage
c'est-à-dire :
\begin{flushleft}
  \comarg{année sur 4 chiffres}\verb+-+\comarg{$n$ caractères}\verb+.dat+
\end{flushleft}
suite à une erreur de manipulation, on désire remplacer toutes les
années $a$ par $a-1$ (donc $2002$ par $2001$, $2003$ par $2002$,
etc.). Si l'on suppose qu'une variable \texttt{F} prenne comme valeur le nom
d'un de ces fichiers :
\begin{verbatim}
  2002-ertyf.dat
\end{verbatim}
alors on peut extraire l'année (\texttt{2002}) comme suit :
\begin{verbatim}
  annee=${F%-*}
\end{verbatim}
%$
maintenant la variable \texttt{annee} contient le nom du fichier sans
ce qui se trouve à partir du caractère~\verb+-+. On peut alors
décrémenter cette variable :
\begin{verbatim}
  annee=$((annee-1))
\end{verbatim}
%$
le nouveau nom du fichier sera composé de cette variable \texttt{annee}
concaténée avec ce qui se trouve après le caractère~\verb+-+, soit :
\begin{verbatim}
  $annee-${F#*-}
\end{verbatim}
D'où le script de conversion utilisant une boucle
\voir{sec-structure-for}{\texttt{for}}
\begin{fichier}[label=arithmetique.sh]
  #!/bin/sh
  for F in ????-*.dat ; do
    annee=${F%-*}
    annee=$((annee-1))
    mv "$F" $annee-${F#*-}
  done
\end{fichier}
%$

On aurait également pu extraire les deux parties du nom de fichier (année et le
reste) à l'aide de \voir[][2pt]{sec-sed}{\soft{sed}} comme le montre le programme suivant :
\begin{fichier}[label=arithmetique-2.sh]
  #!/bin/sh
  for F in ????-*.dat ; do
    annee=$(echo "$F" | sed -r 's/([0-9]{4})-.*/\1/')
    reste=$(echo "$F" | sed -r 's/[0-9]{4}-(.*)/\1/')
    annee=$((annee-1))
    echo mv "$F" $annee-$reste
  done
\end{fichier}
\framasautdepage Pour information l'expression régulière :
\begin{verbatim}
  [0-9]{4}-.*
\end{verbatim}
reconnaîtra une chaîne de caractères commençant par 4 chiffres, suivis
d'un tiret, suivi de ce qui vous passe par la tête. On notera
également l'utilisation de
la \voir{sec-toolbox-substitution-commande}{substitution de commande} et d'un
tube pour stocker dans une variable l'application de la commande
\com{sed} à la valeur~\verb+$F+. %$


\subsection{Structure de contrôle et tests}
\label{sec-shell-sc-test}

Les scripts en shell prennent leur intérêt lorsque l'on peut y insérer
des boucles et autres structures conditionnelles et itératives.
Chacune de ces structures de contrôle inclut généralement
l'évaluation d'une expression booléenne.
\begin{attention}
  On verra un peu plus loin qu'en réalité les valeurs des expressions
  booléennes correspondent toujours à un
  \voir{sec-developper-com-renv-val}{code de retour} d'une commande.
  Et que la valeur de ce code est interprétée comme « vrai » ou « faux
  ».
\end{attention}

\subsubsection{Tests}
\index{shell!test}
\index{test en shell}

La syntaxe pour effectuer un test ---~que nous reprendrons plus loin
avec les structures de contrôle~--- est la suivante :
\begin{flushleft}
  \texttt{test} \comarg{expression\_booléenne}\\
  \quad ou\\
  \texttt{[} \comarg{expression\_booléenne} \texttt{]}
\end{flushleft}
Plusieurs tests sont disponibles, ayant trait au contrôle de
caractéristiques de fichiers (existence, exécutabilité, etc.) et à la
comparaison de chaîne de caractères, ou d'expressions arithmétiques.
Parmi celles-ci :
\begin{center}
\index{test!f@\texttt{-f}}
\index{test!x@\texttt{-x}}
\index{test!d@\texttt{-d}}
\begin{tabular}{|l|l|}
  \hline
  test& renvoie « vrai » si...\\ \hline
  \verb+-f+ \comarg{fichier} & \comarg{fichier} existe\footnotemark \\
  \verb+-x+ \comarg{fichier} & \comarg{fichier} est exécutable\footnotemark \\
  \verb+-d+ \comarg{fichier} & \comarg{fichier} est un répertoire\footnotemark \\
  \hline
  \comarg[1]{chaîne}\texttt{=}\comarg[2]{chaîne} & 
  \comarg[1]{chaîne} et \comarg[2]{chaîne} sont identiques \\
  \comarg[1]{chaîne}\texttt{!=}\comarg[2]{chaîne} &
  \comarg[1]{chaîne} et \comarg[2]{chaîne} sont différentes \\
  \verb+-z+ \comarg{chaîne} &  \comarg{chaîne} est vide \\ \hline
\end{tabular}
\end{center}
\addtocounter{footnote}{-3}%
\stepcounter{footnote}\footnotetext{et est un fichier « régulier »
  (\anglais{regular file}) un fichier normal, quoi, pas un lien
  symbolique, ni un répertoire, ni ...}%
\stepcounter{footnote}\footnotetext{ou compulsable pour un
  répertoire.}%
\stepcounter{footnote}\footnotetext{ou un lien symbolique vers un
  répertoire.}%
Les expressions booléennes effectuant des tests arithmétiques peuvent
quant à elles, être réalisées sous la forme :
\begin{comsyntax}
  \comarg[1]{expr} \comarg{opérateur} \comarg[2]{expr}
\end{comsyntax}
où \comarg{opérateur} peut prendre les valeurs du tableau ci-dessous :
\begin{center}
\index{test!eq@\texttt{-eq}}
\index{test!ne@\texttt{-ne}}
\index{test!lt@\texttt{-lt}}
\index{test!gt@\texttt{-gt}}
\index{test!le@\texttt{-le}}
\index{test!ge@\texttt{-ge}}
\begin{tabular}{|l|l|}
\hline
\texttt{-eq} & égal (\emph{equal})\\
\texttt{-ne} & différent (\emph{not equal})\\
\texttt{-lt} & inférieur (\emph{less than})  \\ 
\texttt{-gt} & supérieur (\emph{greater than}) \\
\texttt{-le} & inférieur ou égal (\emph{less than or equal})\\
\texttt{-ge} & supérieur ou égal (\emph{greater than or equal})\\\hline
\end{tabular}
\end{center}
On peut également combiner les expressions booléennes :
\begin{center}
  \begin{tabular}{|l|l|}
    \hline
    test& renvoie « vrai » si...\\\hline
    \verb+!+ \comarg{expr} & \comarg{expr} renvoie « faux » \\
    \comarg[1]{expr} \verb+-a+ \comarg[2]{expr} & 
    \comarg[1]{expr} et (\anglais{and}) \comarg[2]{expr} renvoient « vrai » \\
    \comarg[1]{expr} \verb+-o+ \comarg[2]{expr} & 
    \comarg[1]{expr} ou (\anglais{or}) \comarg[2]{expr} renvoient « vrai »\\ \hline
\end{tabular}
\end{center}
Le shell ---~notamment \texttt{bash}~--- dispose de bien d'autres
outils de tests et nous vous invitons vivement à compulser la page de
manuel ou vous procurer l'ouvrage de \citet{bash} pour de plus amples
informations.

\subsubsection{Structures de contrôle}
\index{structures de contrôle}
\index{shell!structures de contrôle}

Voici trois structures de contrôle disponibles dans \com{bash}. Ce sont
les trois structures classiques d'un langage de programmation :
\begin{itemize}
\item le « if then else » pour faire un choix à partir d'une
  expression booléenne ;
\item le « case » permettant de faire un choix multiple en fonction
  d'une expression ;
\item le « tant que » dont le but est de réitérer des commandes tant
  qu'une expression est vraie.
\end{itemize}
Le shell dispose de quelques autres structures que nous passerons sous
silence. On peut également se référer au
paragraphe~\vref{sec-structure-for} pour la structure de contrôle de
type « for ». Toujours dans un souci de pragmatisme nous illustrons
ici l'usage de ces trois structures de contrôle grâce à des exemples.
Examinons tout d'abord le \texttt{if} :
\begin{fichier}[label=testif.sh]
  #!/bin/sh
  A=$1
  B=$2
  if [ $A -lt $B ]; then
     echo "l'argument 1 est plus petit que l'argument 2"
  else
     echo "l'argument 1 est plus grand que l'argument 2"
  fi
\end{fichier}
On peut noter l'utilisation du test \texttt{[...]} et du mot-clef
\texttt{fi} qui termine la clause \texttt{if then else}. Il ne faut
pas omettre le point-virgule qui clôt l'expression test. \`A
l'exécution :
\begin{shellcom}
  ¢usercom«./testif.sh 4 6»
  l'argument 1 est plus petit que l'argument 2
  ¢usercom«./testif.sh 45 6»
  l'argument 1 est plus grand que l'argument 2
\end{shellcom}

\index{while@\texttt{while}}
Pour illustrer l'utilisation du \texttt{while} écrivons une petite
boucle qui compte de 1 à~$n$ (un nombre donné par l'utilisateur) :
\begin{fichier}[label=testwhile.sh]
  #!/bin/sh
  LAST=$1
  n=1
  while [ "$n" -le "$LAST" ]; do
    echo -n "$n"
    n=$((n+1))
  done
  echo et voilou
\end{fichier}
%$
qui donne par exemple :
\begin{shellcom}
  ¢usercom«./testwhile.sh 10»
  1 2 3 4 5 6 7 8 9 10 et voilou
\end{shellcom}
\index{done@\texttt{done}}
Notez le mot-clef \texttt{done} qui clôt la clause \texttt{while}. Ici
l'option \texttt{-n} de la commande \com{echo} ne crée pas de saut de
ligne à la fin de l'affichage. Histoire de confirmer l'assertion de
Larry \textsc{Wall}\footnote{There's more than one way to do it.}, on
peut utiliser une boucle « pour » pour générer et afficher une
séquence. On fera appel à la commande \com{seq} dont voici un exemple
d'utilisation :
\begin{shellcom}
  ¢usercom«seq 1 5»
  1
  2
  3
  4
  5
\end{shellcom}
ce petit utilitaire a donc pour tâche d'afficher les entiers de~1
à~5. Si vous êtes curieux, la page de manuel vous indiquera que l'on
peut également changer l'incrément et deux ou trois autres choses. On
peut donc écrire le script suivant :
\begin{fichier}[label=compter.sh]
  #!/bin/sh
  for I in $(seq 1 10); do
     printf "%d " "$I"
  done
  echo et voilou.
\end{fichier}
%$
qui donne le même résultat que le script précédent.
\begin{gnuposix}
  Les puristes auront noté que la commande \com{seq} n'est disponible
  que pour les utilisateurs travaillant sur des systèmes où le paquet
  \soft{coreutils} de chez M. \gnu{} est installé.
\end{gnuposix}

\index{case@\texttt{case}} Pour ce qui est du \texttt{case}, on peut
imaginer que l'on veuille écrire un script permettant d'identifier
l'origine des fichiers en fonction de leur extension\footnote{Notez
  que l'utilitaire \com{file} fait ce travail beaucoup mieux...}.
\begin{fichier}[label=testcase-I.sh]
  #!/bin/sh
  
  NOM=${1:?"Donnez un nom de fichier svp"}
  EXT=${NOM##*.}
  
  case $EXT in
    tex) echo on dirait un fichier TeX ;;
    dvi) echo on dirait un fichier device independant ;;
    ps)  echo on dirait un fichier Postscript ;;
    *)   echo chai pô ;;
  esac
\end{fichier}
%$
On utilise ici le modificateur de variable \verb+##+ pour supprimer la
plus grande chaîne finissant par le caractère~«.» et ainsi obtenir
l'extension. Le mot-clef \texttt{esac} (case à l'envers) clôt la
clause \texttt{case}. Le choix par défaut est indiqué par~«\texttt{*}»
(n'importe quelle chaîne de caractères). \`A chaque choix correspond
une série de commandes à exécuter (ici une seule) ; série qui doit
être terminée par deux points-virgules~«\texttt{;;}». On teste :
\begin{shellcom}
  ¢usercom«./testcase-I.sh ~/LaTeX/guide/guide-unix.tex»
  on dirait un fichier TeX
  ¢usercom«./testcase-I.sh /etc/lpd.conf»
  chai pô
\end{shellcom}
\framaallongepage{2}
\begin{note}
  La chaîne de caractères précédant la parenthèse dans chaque clause
  de \texttt{case} peut être un \voir{sec-unix-jokers}{joker}
  (\anglais{wildcard}), comme le montre la dernière clause qui utilise
  le caractère~\texttt{*} pour indiquer « toute (autre) chaîne de
  caractère ».
\end{note}

Une limitation du script précédent est que les fichiers :
\begin{verbatim}
  tex
  .tex
\end{verbatim}
seront pris pour un fichier \TeX{}. Ceci est dû au fait que si :
\begin{shellcom}
  ¢usercom«NOM=tex»
\end{shellcom}
alors l'expression \verb+${NOM##*.}+ renvoie \verb+tex+ car aucune
substitution n'a pu être réalisée. On peut imaginer la solution
suivante qui utilise les caractères génériques du shell :
\begin{fichier}[label=testcase-II.sh]
  #!/bin/bash
  NOM=${1:?"Donnez un nom de fichier svp"}
  case $NOM in
    *[^/].tex) echo on dirait un fichier TeX ;;
    *[^/].dvi) echo on dirait un fichier device independant ;;
    *[^/].ps)  echo on dirait un fichier Postscript ;;
    *)   echo chai pô ;;
  esac
\end{fichier}
Dans ce script, l'expression \verb+*[^/].tex+ veut dire toute chaîne
de caractères composée de :
\begin{itemize}
\item \verb+*+ : toute chaîne même vide ;
\item \verb+[^/]+ : un caractère différent de \verb+/+ ;
\item \verb+.tex+
\end{itemize}

\subsubsection{Les commandes renvoient une valeur !}
\label{sec-developper-com-renv-val}

\index{if@\texttt{if}}
\index{structures de contrôle!if@\texttt{if}}

Les expressions booléennes utilisées par exemple dans la structure
\texttt{if} sont en réalité la valeur de retour d'une commande.  En
effet toute commande \unix{} renvoie une valeur en fonction du succès
de son exécution. Il existe en outre une variable particulière
contenant le code retour de la dernière commande exécutée : la
variable \verb+$?+. %$
\index{;@\texttt{\$?}}  Voici un exemple avec la commande \com{id} qui
donne des informations sur un utilisateur particulier :
\begin{shellcom}
  ¢usercom«id lozano»
  uid=1135(lozano) gid=200(users) groups=200(users)
  ¢usercom«echo $?»
  0 ¢comcomment«tout s'est bien passé.»
  ¢usercom«id djobi»
  id: djobi: No such user
  ¢usercom«id $?»
  1 ¢comcomment«Il y a eu un problème.»
\end{shellcom}
On peut alors utiliser cette valeur directement dans une structure de
type \texttt{if} comme suit :
\begin{fichier}[label=testtest.sh]
  #!/bin/bash
  if id $1 2> /dev/null 1>&2; then 
    echo c\'est un utilisateur
  else 
    echo ce n\'est pas un utilisateur
  fi 
\end{fichier}
%$
Il est important de noter que dans la construction :
\begin{fichier}
  if ¢comarg«commande test» ; then
     ¢comarg«commandes»
  fi
\end{fichier}
\comarg{commandes} seront exécutées si et seulement si
\comarg{commande test} renvoie la valeur~0 (indépendamment de ce
qu'elle peut afficher). Dans notre exemple on a donc :
\begin{shellcom}
  ¢usercom«./testtest.sh lozano»
  c'est un utilisateur
  ¢usercom«./testtest.sh djobi»
  ce n'est pas un utilisateur
\end{shellcom}
\index{;@\texttt{2>}} \index{;@\texttt{1>\&2}} On peut noter
l'utilisation de \voir{sec-pipe}{redirections} \texttt{2>} pour
rediriger le flux d'erreur~($2$) et \texttt{1>\&2} pour rediriger le
flux de sortie~($1$) sur le flux d'erreur~($2$).
\begin{note}
  Un script renvoie la valeur retournée par la dernière commande
  exécutée. On peut cependant forcer le renvoi d'une valeur
  particulière en utilisant la commande \com{exit} suivie d'une valeur.
\end{note}

Pour finir ce paragraphe et boucler la boucle des « expressions
booléennes », supposons qu'il existe dans le répertoire courant un
fichier \verb+guide-unix.tex+ et tapons :
\begin{shellcom}
  ¢usercom«[ -f guide-unix.tex ]»
  ¢usercom«echo $?»
  0 ¢comcomment«le fichier existe»
\end{shellcom}
Puis :
\begin{shellcom}
  ¢usercom« [ -f guide-unix.texitoi ]»
  ¢usercom«echo $?»
  1 ¢comcomment«le fichier n'existe de pas»
\end{shellcom}
%$
Où l'on apprend donc que \verb+[+ est une commande qui, comme beaucoup
de ses copines, renvoie 0 si tout est ok, et 1 sinon...


\subsection{Fonctions}
\label{sec-shell-fonction}
\index{shell!fonction}
\index{fonction du shell}

Une des caractéristiques des shells de la famille \texttt{sh} est la
possibilité de créer des fonctions. Voici un exemple succinct qui
illustre les syntaxes de déclaration et d'appel, ainsi que la
visibilité des variables :
\begin{fichier}[label=testfunc.sh]
  #!/bin/sh

  N=4
  function mafunc()
  {
    I=7
    echo $1 $2 $N
  }
  mafunc a b # appel à la fonction avec 2 arguments 
  echo et : $I
\end{fichier}
qui donne à l'exécution :
\begin{shellcom}
  ¢usercom«./testfunc.sh »
  a b 4
  et : 7
\end{shellcom}
on notera donc qu'à l'intérieur du corps de la fonction, les arguments
de celle-ci sont notés \verb+$1+, \verb+$2+, etc. En outre :
\begin{itemize}
\item les variables instanciées dans la fonction sont visibles en
  dehors (c'est le cas de~\verb+$I+ dans notre exemple) ;
\item les variables instanciées avant la définition de la fonction
  sont visibles dans celle-ci (c'est le cas de~\verb+$N+ dans notre
  exemple).
\end{itemize}
%$

Enfin, à l'instar d'un script, on peut faire renvoyer une valeur à une
fonction avec la commande \com{return} suivie d'une valeur. Voici un
exemple d'utilisation de fonction : on reprend le script
\texttt{arithmetique.sh} du
paragraphe~\vref{sec-shell-var-arithmetique} et on utilise une
fonction pour faire le changement de nom :
\begin{fichier}[label=arithmetique-3.sh]
  #!/bin/sh

  function changernom()
  {
    annee=${1%-*}
    annee=$[annee-1]
    mv "$1" "$annee-${1#*-}"
  }
  for F in ????-????.dat ; do
    changernom $F
  done
\end{fichier}

\index{arguments!de fonction en shell} \index{shell!scripts|)}
\index{scripts shell|)}

\subsection{Input field separator}
\label{sec-developper-IFS}

Un jour ou l'autre le développeur de script shell est confronté au
problème suivant. Avec notre fichier :
\begin{fichier}
  Jimi Hendrix 1970
  Jim Morrison 1971
  Janis Joplin 1969
\end{fichier}
on écrit naïvement le script ayant pour but d'effectuer un traitement
par ligne des fichiers passés en paramètre :
\begin{fichier}[label=naif.sh]
  #!/bin/sh
  for ligne in $(cat "$@") ; do
    echo "Une ligne : $ligne"
  done
\end{fichier}
%$
On aura une certaine déception à l'exécution :
\begin{shellcom}
  ¢usercom«./naif.sh fichier.dat»
  Une ligne : Jimi
  Une ligne : Hendrix
  Une ligne : 1970
  Une ligne : Jim
  Une ligne : Morrison
  Une ligne : 1971
  Une ligne : Janis
  Une ligne : Joplin
  Une ligne : 1969
\end{shellcom}
Ceci vient du fait que les éléments constituant la liste
\comarg{$\ell$} de :
\begin{flushleft}
  \verb+for ligne in + \comarg{$\ell$} \verb+; do ...+
\end{flushleft}
sont délimités par les caractères contenus dans la variable
\envvar{IFS}. Cette variable contient par défaut :
\begin{itemize}
\item le caractère espace,
\item la tabulation,
\item le saut de ligne.
\end{itemize}
Or nous souhaiterions ici clairement que les éléments de la liste 
soient délimités par le saut de ligne. Il suffit pour cela de modifier le
script :
\begin{fichier}[label=naif.sh]
  #!/bin/sh
  # c'est le saut de ligne qui fait office de séparateur pour 
  # chaque élément d'une liste
  IFS="
  " 
  for ligne in $(cat "$@") ; do
    echo "Une ligne : $ligne"
  done
\end{fichier}
%$
qui donnera ce qu'on attend, c'est-à-dire :
\begin{shellcom}
  ¢usercom«./naif.sh fichier.dat»
  Une ligne : Jimi Hendrix 1970
  Une ligne : Jim Morrison 1971
  Une ligne : Janis Joplin 1969
\end{shellcom}


\subsection{Fiabilité des scripts}
\label{sec-developper-fiabilite}

Pour rendre fiables les scripts que vous écrirez, il faudra qu'ils
puissent traiter correctement les fichiers aux noms « bizarroïdes ».
Le premier cas est le cas des noms de fichiers contenant des espaces.
Supposons que dans un répertoire :
\begin{shellcom}
  ¢usercom«ls -1»
  bidule.dat
  le machin.dat
  truc.dat
\end{shellcom}
et que l'on écrive le script suivant\footnote{Qui n'a comme seul
  intérêt l'exemple, puisque \texttt{rm *.dat} fera aussi bien l'affaire.} :
\begin{fichier}
  for f in *.dat ; do 
    echo "je vais effacer $f..."
    rm $f
  done
\end{fichier}
Celui-ci affichera, au moment de traiter le fichier \verb+le machin.dat+ :
\begin{verbatim}
  Je vais effacer le machin.dat
  rm: cannot lstat `le': No such file or directory
  rm: cannot lstat `machin.dat': No such file or directory
\end{verbatim}
C'est-à-dire que la commande \com{rm} tente d'effacer deux fichiers :
\begin{itemize}
\item le fichier \verb+le+
\item et le fichier \verb+machin.dat+
\end{itemize}
Pour faire comprendre à la commande \com{rm} que le nom du fichier est
composé des deux mots, on doit écrire :
\begin{fichier}
  for f in *.dat ; do 
    echo "je vais effacer $f..."
    rm "$f" ¢comcomment«on quote la variable»
  done
\end{fichier}

\index{tiret}
Autre situation « tordue » : lorsque le nom d'un fichier commence par
le caractère tiret (\verb+-+) par exemple \verb+-biduletruc.txt+. Dans
ce cas : 
\begin{shellcom}
  ¢usercom«ls -biduletruc.txt»
  ls: invalid option -- e
  Try `ls --help' for more information.
  ¢usercom«rm -biduletruc.txt»
  rm: invalid option -- b
  Try `rm --help' for more information.
\end{shellcom}
ici \verb+e+ est la première option inconnue à la commande \com{ls}.
Pour \com{rm} c'est l'option \texttt{b}. La solution\footnote{Une
  autre solution consiste à préfixer le nom du fichier par
  \texttt{./}} pour contourner ce problème est d'insérer dans la ligne
de commande le couple \verb+--+ pour indiquer que ce qui suit ne
contiendra plus d'option. Ainsi :
\begin{shellcom}
  ¢usercom«ls -- -biduletruc.txt»
  -biduletruc.txt
\end{shellcom}
On pourra faire de même pour la commande \com{rm}.

\section{Makefile}
\label{sec-dev-make}
\index{make@\texttt{make}|(}


L'utilitaire \com{make} est un outil destiné, au départ, à gérer la
compilation d'un projet incluant plusieurs fichiers. Grâce à un
fichier ---~le \texttt{makefile}~--- on précise quels sont les fichiers
à recompiler lorsqu'on apporte une modification à un ou plusieurs
fichiers composant le projet. Dans la pratique, \com{make} peut être
utilisé dans le cadre d'un projet dont la gestion ne nécessite pas
nécessairement de compilation ; en fait tout projet dans lequel on a
besoin à un moment donné de \emph{construire} (ou \emph{faire}) un
fichier à partir d'un ou plusieurs autres, peut faire appel à
\com{make}. On distinguera donc deux concepts :
\begin{enumerate}
\item l'utilitaire \com{make} lui-même qui est un programme, dont les
  versions varient selon le système ; nous utiliserons ici le
  \com{make} de \gnu{} ;
\item le fichier \texttt{makefile}, qui peut porter n'importe quel
  nom, et qui contient un ensemble de règles pour définir :
  \begin{enumerate}
  \item à partir de quels fichiers on construit le projet ;
  \item quels sont
    les fichiers à « refaire » en fonction des modifications apportées au
    projet.
  \end{enumerate}
  Ce fichier est interprété par l'utilitaire \com{make}.
\end{enumerate}


\subsection{Principes de base}
\label{sec-makefile-principes}

Nous exposons ici les concepts de base de l'utilisation de \com{make}
en nous basant sur un exemple simple : supposons que nous utilisions
le logiciel \com{xfig}\footnote{Qui est à la fois laid et pratique, et
  dispose de fonctionnalités étonnantes comme son fameux « open
  compound ».}  pour créer des dessins et que nous ayons besoin de les
insérer dans un document sous la forme d'un fichier au format
PostScript encapsulé\footnote{Le PostScript encapsulé diffère du
  Postscript dans la mesure où il est destiné à être intégré dans un
  autre document. Le fichier contient d'ailleurs à cette fin une «
  boîte englobante » (\anglais{bounding box}) permettant d'obtenir son
  encombrement.}.  Une fois le fichier \texttt{test.fig} sauvé au
format de \com{xfig}, on désire automatiser l'exportation en
PostScript, avec la commande\footnote{L'exportation peut certes être
  réalisée interactivement avec la souris, depuis le logiciel
  \com{xfig}, mais tel n'est pas notre propos.} :
\begin{shellcom}
  ¢usercom«fig2dev -L eps test.fig > test.eps»
\end{shellcom}




\subsubsection{Notion de cible}
\index{make@\texttt{make}!cible}
\index{cible \texttt{make}}

Comme nous le notions un peu plus haut, \com{make} permet de
\emph{fabriquer} des fichiers. Le fichier que l'on veut construire
s'appelle en jargon \com{make}, la \emph{cible}.  Supposons que le
fichier à exporter s'appelle \texttt{test.fig}, le fichier à fabriquer
se nommera \texttt{test.eps}. On crée alors un fichier que l'on nomme
\texttt{Makefile} contenant :
\begin{fichier}
  test.eps :
  ¢maketab fig2dev -L eps test.fig > test.eps
\end{fichier}
\index{tabulation avec \texttt{make}}
\begin{attention}
  le caractère \maketab{} indique l'insertion d'une \emph{tabulation}.
  Sa présence est \emph{indispensable} pour que l'utilitaire
  \com{make} analyse les règles du fichier \texttt{makefile}.
\end{attention}
Par défaut, \com{make} cherche à exécuter la première cible qu'il
rencontre. Par convention, on définit une cible \texttt{all} pour «
tout faire » :
\begin{fichier}
  all : test.eps

  test.eps :
  ¢maketab fig2dev -L eps test.fig > test.eps
\end{fichier}
Pour construire le fichier \texttt{test.eps} on peut alors au choix
lancer  :
\begin{shellcom}
  ¢usercom«make »
  fig2dev -L eps  test.fig > test.eps
\end{shellcom}
ou : 
\begin{shellcom}
  ¢usercom«make test.eps»
  fig2dev -L eps  test.fig > test.eps
\end{shellcom}
On peut d'ores et déjà remarquer que la commande à exécuter est
préalablement affichée à l'écran ; ceci peut être désactivé
(voir~\vref{sec-make-option}).
 
\subsubsection{Notion de dépendance}
\index{make@\texttt{make}!dépendance}
\index{dépendance \texttt{make}}

\`A chaque modification du fichier \texttt{test.fig}, il est
nécessaire d'exporter à nouveau en \texttt{eps}. C'est typiquement le
genre de tâche que l'on peut confier à \com{make}. On insère donc dans
le fichier \texttt{Makefile} une \emph{dépendance} qui spécifie que
la construction du fichier \texttt{test.eps} dépend de la date du
fichier \texttt{test.fig} :
\begin{fichier}
  test.eps : test.fig
  ¢maketab fig2dev -L eps test.fig > test.eps
\end{fichier}
La signification de cette dépendance est la suivante :
\begin{enumerate}
\item si le fichier \texttt{test.fig} est plus récent que le fichier
  \texttt{test.eps} la prochaine invocation de \com{make} construira à
  nouveau \texttt{test.eps} ;
\item sinon une invocation de \com{make} donnera :
  \begin{shellcom}
    ¢usercom«make»
    make: `test.eps' is up to date.
  \end{shellcom}
\end{enumerate}
qui est tout simplement la traduction de « est à jour ».
\begin{attention}
  L'utilitaire \com{make} gère les dépendances en utilisant les
  \emph{dates} associées aux fichiers ; il est donc impératif que
  l'horloge du système fonctionne correctement et en particulier, dans
  le cas d'un système en réseau, que l'heure du système stockant les
  fichiers soit synchrone avec l'heure du système exécutant
  l'utilitaire lui-même.
\end{attention}

\subsubsection{Notion de règle}
\index{make@\texttt{make}!règle}
\index{règle \texttt{make}}

L'ensemble formé par une cible, une ou des dépendances, et les
commandes s'appelle une \emph{règle}. La syntaxe générale est la
suivante :
\begin{flushleft}
  \quad \comarg{cible} \texttt{:} \comarg{dépendances}\\
  \quad \maketab \comarg[1]{commande}\\
  \quad \maketab \comarg[2]{commande}\\
  \quad \maketab ...\\
  \quad \maketab \comarg[n]{commande}
\end{flushleft}
Nous verrons par la suite que l'on peut définir des règles
relativement subtiles permettant d'automatiser la gestion de fichiers
de projets complexes.


\subsection{Variables}
\label{sec-make-variables}
\index{make@\texttt{make}!variables}
\index{variable!make@\texttt{make}}

Dans un fichier \texttt{Makefile} on peut utiliser des variables, par
exemple :
\begin{fichier}
  FICHIER = test
  FIGOPTS=-Leps
  all : $(FICHIER).eps
  $(FICHIER).eps : $(FICHIER).fig
  ¢maketab fig2dev $(FIGOPTS) $(FICHIER).fig > $(FICHIER).eps
\end{fichier}
%$
La syntaxe s'apparente donc à celle du shell :
\begin{itemize}
\item affectation avec l'opérateur \texttt{=} ;
\item accès avec l'opérateur \texttt{\$} et les parenthèses.
\end{itemize}

\subsection{Règles implicites et variables prédéfinies}
\label{sec-make-implicite}
\index{make@\texttt{make}!règle implicite} \index{règle implicite
  \texttt{make}} La règle que l'on a construite jusqu'ici est adaptée
au fichier \texttt{test.fig} et à lui seul. Un moyen de généraliser
cette règle à d'autres fichiers est d'utiliser ce qu'on nomme une
\emph{règle implicite}, permettant de définir de manière générale,
comment construire un fichier \texttt{.eps} à partir d'un fichier
\texttt{.fig}. Un fichier \texttt{Makefile} répondant à ce problème
peut être le suivant :
\begin{fichier}[numbers=left]
  EPSFILE = test.eps
  all : $(EPSFILE)
  %.eps : %.fig
  ¢maketab fig2dev -L eps $< > $@
\end{fichier}
%$
On peut expliquer ce \texttt{Makefile} quelque peu cryptique de la
manière suivante :
\begin{itemize}
\item la ligne $3$ contient :
  \begin{itemize}
  \item la cible \texttt{\%.eps} : c.-à-d. n'importe quel fichier dont
    l'extension est \texttt{eps} ;
  \item la dépendance \texttt{\%.fig} : un fichier de même nom sauf l'extension
    qui est remplacée par \texttt{.fig} ;
  \end{itemize}
\item la ligne 4 contient la commande proprement dite qui utilise des
  variables prédéfinies du \gnu{} \com{make} :
  \begin{itemize}
  \item la variable \verb+$<+ %$
    pour le premier fichier de la liste des dépendances
    (\ifframabookversion le fichier \fi\texttt{test.fig} dans notre exemple);
  \item la variable \verb+$@+ %$
    qui désigne le fichier cible (\texttt{test.eps}). %$
  \end{itemize}%$
\end{itemize}
Le mécanisme de création du fichier \texttt{test.eps} est donc le
suivant :
\begin{enumerate}
\item on doit faire \texttt{test.eps} (cible \texttt{all}) ;
\item pour ce faire, on dispose d'une règle permettant de faire un
  \texttt{.eps} à partir d'un \texttt{.fig} ;
\item il existe un fichier \texttt{test.fig} dans le répertoire ;
\item  on  peut donc faire \texttt{test.eps}.
\end{enumerate}
\begin{note}
  Il existe bien entendu d'autres variables automatiques, parmi
  celles-ci : \verb+$^+ %$
  qui contient toutes les dépendances de la cible séparées par des
  espaces. Voir le manuel info de \gnu{} \com{make} pour plus de
  précisions.
\end{note}

\subsection{Outils sur les variables}
\label{sec-make-var-outils}
\index{make@\texttt{make}!variable}
\index{variable!make@\texttt{make}}

On peut également, grâce à certaines des fonctionnalités du \gnu{}
\com{make}, automatiser l'instanciation des variables. Dans l'exemple
qui nous concerne, on peut dans un premier temps mettre dans une
variable \texttt{FIGFILE} tous les fichiers du répertoire de travail
portant l'extension \texttt{.fig} :
\begin{fichier}
  FIGFILE=$(wildcard *.fig)
\end{fichier}
%$
le mot-clef \texttt{wildcard} que l'on peut traduire par \emph{joker}
ou caractère générique permet donc ici d'arriver à nos fins. Une
deuxième étape consiste à créer la variable \texttt{EPSFILE} à partir
de \texttt{FIGFILE} en remplaçant dans le contenu de cette dernière,
la chaîne \texttt{.fig} par la chaîne \texttt{.eps} :
\begin{fichier}
  EPSFILE=$(patsubst %.fig, %eps,$(FIGFILE))
\end{fichier}
Le mot-clef \texttt{patsubst} signifie ici \emph{pattern
  substitution.} Notre \texttt{Makefile} permettant de gérer
l'exportation de nos dessins est maintenant capable de générer les
\texttt{.eps} à partir de tous les fichiers \texttt{.fig} du
répertoire courant. On peut également y rajouter une cible de «
nettoyage » permettant d'effacer les fichiers \texttt{.eps} lorsqu'ils
ne sont plus nécessaires :
\begin{fichier}
  FIGFILE=$(wildcard *.fig)
  EPSFILE=$(patsubst %.fig, %eps,$(FIGFILE))
  all : $(EPSFILE)
  clean :
  ¢maketab rm -f $(EPSFILE)
  %.eps : %.fig
  ¢maketab fig2dev -L eps $< > $@  
\end{fichier}
%$
Un raccourci de \texttt{patsubst} pour la substitution précédente est :
\begin{verbatim}
  EPSFILE=$(FIGFILE:.fig=.eps)
\end{verbatim}
%$
qui remplace la chaîne \texttt{.fig} par la chaîne \texttt{.eps}, à la
fin des mots. La forme \texttt{patsubst} est donc en quelque sorte une
généralisation de la précédente.


Plus généralement, on peut instancier une variable en utilisant le mot
clef \texttt{shell} suivi d'une ou plusieurs commandes interprétées
par le shell. Un exemple d'une telle construction peut être :
\begin{fichier}
  # récupère le dernier fichier TeX sauvé
  TMP=$(shell ls -1tr *.tex | tail -1)
  # enlève l'extension
  LASTTEXFILE=$(shell echo $(TMP) | sed s/\.tex$$// )
\end{fichier}
%$
\begin{note}
  Il existe bien d'autres outils de traitement sur les chaînes de
  caractères dans les variables, parmi ceux-ci de nombreux opérateurs
  de type « recher\-cher/rem\-pla\-cer », des opérateurs propres aux noms de
  fichiers (suppression d'extension, du répertoire, etc.), des boucles
  de type « pour chaque », voir à ce sujet le manuel au format
  \texttt{info} du \gnu{} \com{make}.
\end{note}

\subsection{Options et fonctionnalités diverses}
\label{sec-make-option}

\subsubsection{Options de make}

Comme toute commande \unix{}, \com{make} peut prendre quelques options
et paramètres :
\begin{itemize}
\item les paramètres doivent correspondre au nom d'une cible du \texttt{Makefile}. Dans notre exemple, elle peut être :
  \begin{shellcom}
    ¢usercom«make bidule.eps»
    ...
  \end{shellcom}
  ou : 
  \begin{shellcom}
    ¢usercom«make clean»
    rm -f arborescence.eps disques.eps flux.eps pipes.eps 
  \end{shellcom}
  si le fichier \texttt{bidule.fig} existe. Si \soft{make} ne trouve
  pas de règle pour fabriquer la cible, un message d'erreur est
  renvoyé :
  \begin{shellcom}
    ¢usercom«make djobi»
    make: Nothing to be done for `djobi'.
  \end{shellcom}
  Si aucun paramètre n'est précisé, c'est la première cible rencontrée
  qui est exécutée.
\item par défaut \com{make} cherche les règles et les cibles parmi 
  quelques fichiers dont les noms sont prédéfinis
  (\texttt{Makefile}, \texttt{makefile}, etc.), l'option~\texttt{-f}
  permet d'utiliser un autre nom pour le fichier :
  \begin{shellcom}
    ¢usercom«make -f bidule.mak»
    ...
  \end{shellcom}
\item l'option \texttt{-n} demande à \com{make} d'afficher les
  commandes prévues pour la cible en question, sans les exécuter ; ce
  qui peut être utile pour débuguer les \texttt{Makefile} ;
\item notez enfin que si la commande d'une règle est préfixée par le
  caractère~\verb+@+, cette commande n'est pas affichée avant d'être
  exécutée comme elle l'est par défaut :
  \begin{fichier}
    cible1 : 
    ¢maketab echo six bleus 1
    cible2 :
    ¢maketab @echo six bleus 2
  \end{fichier}
  \begin{shellcom}
    ¢usercom«make cible1 cible2 »
    echo six bleus 1 ¢comcomment«echo de la commande»
    six bleus 1
    six bleus 2 ¢comcomment«pas d'echo pour ¢texttt«cible2»»
  \end{shellcom}
\end{itemize}


\subsubsection{Règles prédéfinies}

Comme nous aurons l'occasion de le voir au
paragraphe~\ref{sec-compiler-C} les utilitaires \com{make}, et
notamment le \gnu{} \com{make}, définissent certaines règles dites
\emph{implicites} pour fabriquer des fichiers « standards ». \`A titre
d'information, le \gnu{} \com{make} dispose d'un catalogue de règles
pour, entre autres :
\begin{itemize}
\item compiler du C, du C++, du Pascal ;
\item faire des éditions de liens ;
\item créer des fichiers \texttt{dvi} à partir des sources \TeX{} ;
\item ...
\end{itemize}
Nous exploiterons ces règles prédéfinies dans la section suivante
dédiée à la compilation d'un programme en langage C.
\index{make@\texttt{make}|)}


\section{Faire des projets en langage C}
\label{sec-compiler-C}

Nous supposons ici que le lecteur connaît le langage C, et présentons
les mécanismes de la création d'un exécutable \unix{} à partir d'un
source écrit en~C. La création d'un programme passe par différentes
phases d'analyse dont on peut trouver des « méthodes » dans les livres
de génie logiciel et d'algorithmique.  Nous nous attarderons ici sur la
phase « technique » et supposons que le lecteur a un niveau correct en
langage C.


\subsection{Remarques préliminaires}
\label{sec-C-remarques}

\index{source}\index{fichier!source}
\index{exécutable}\index{fichier!exécutable}
\index{objet}\index{fichier!objet}
\index{bibliothèque}
\index{bibliothèque dynamique}
\index{compilation}
\index{edition@{édition de liens}}
\index{link@\emph{link}|see{edition}}

Voici un petit glossaire qui permettra de clarifier notre
vocabulaire. Les différents types de fichiers que nous rencontrerons
seront :
\begin{description}
\item[Source :] c'est le fichier texte qui contient le programme en
  langage C ;
\item[Exécutable :] c'est le fichier binaire qui contient des
  instructions destinées au processeur (code machine) et qui peut être
  chargé en mémoire par le système d'exploitation ;
\item[Objet :] c'est un fichier binaire résultant de la
  \emph{compilation}. Ce fichier contient le code machine de certaines
  fonctions définies par le programmeur et des appels à des fonctions
  définies autre part (dans un autre fichier objet ou dans une
  \emph{bibliothèque}) ;
\item[Bibliothèque :] c'est un fichier binaire s'apparentant à un fichier
  objet et contenant le code d'un certain nombre de fonctions rendues
  publiques ;
\item[Bibliothèque dynamique :] il s'agit d'une bibliothèque dont le
  code machine n'est pas inséré dans l'exécutable, mais qui est chargé
  à la demande lors de l'\emph{exécution}.
\end{description}
Les actions que nous serons amenés à effectuer pour la gestion de
notre projet seront :
\begin{description}
\item[Compilation :] c'est la phase permettant de faire une analyse
  syntaxique, grammaticale et sémantique du fichier source et de
  créer, si cette première phase se déroule sans heurt, un fichier
  objet ; elle se décompose en \anglais{preprocessing}, compilation et
  assemblage ;
\item[\'Edition de liens :] c'est la phase qui regroupe les fichiers
  objets et les bibliothèques, et qui après avoir vérifié que toutes
  les fonctions appelées dans les fichiers objets pointent bien vers
  un code objet, crée un exécutable. L'édition de liens en anglais se
  dit \emph{to link}, et l'utilitaire permettant de l'effectuer est le
  \emph{linker}.
\end{description}
%% Avec ce vocabulaire en tête, considérons quelques cas « typiques » de la
%% gestion de projet en langage C :
%% \begin{itemize}
%% \item la création d'un exécutable via un unique fichier source,
%%   s'effectue simplement par compilation du source, puis édition de
%%   liens  (cf. figure~\vref{fig-compil-simple}) ;
%% \item la création d'un exécutable à partir de plusieurs fichiers
%%   sources suit la logique suivante : compilation de chacun des
%%   sources, puis édition de liens qui gère les appels de fonction inter
%%   modules (cf. figure~\vref{fig-compil-separee}) ;
%% \item la création d'un exécutable en s'appuyant sur une bibliothèque
%%   statique (le code de la fonction appelée est inséré dans le fichier
%%   exécutable à l'édition de liens) ou dynamique (le code est chargé en
%%   mémoire à l'exécution) (cf. figure~\ref{fig-compil-lib}) ;
%% \end{itemize}
%% Dans les projets sérieux, on a affaire à la compilation séparée avec
%% l'utilisation et la création de bibliothèques.
%% \begin{figure}[htbp]
%%   \begin{center}
%%     \subfloat[Compilation simple]{%
%%       \label{fig-compil-simple}%
%%       \includegraphics[width=.87\textwidth]{projeta}}
%%     \subfloat[Compilation séparée]{%
%%       \label{fig-compil-separee}%
%%       \includegraphics[width=.87\textwidth]{projetb}}
%%     \subfloat[Compilation simple avec édition de liens dynamique 
%%     et statique]{%
%%       \label{fig-compil-lib}%
%%       \includegraphics[width=.87\textwidth]{projetc}}
%%     \caption{Gestion d'un projet de programmation}
%%     \label{fig-projet-programme}
%%   \end{center}
%% \end{figure}

\subsection{Étude du cas simple : un seul fichier source}

\begin{figure}[tb]
  \centering
  \includegraphics[width=\ifframabookversion.96\textwidth\else.87\textwidth\fi]{%
    projeta}
  \caption{Création d'un exécutable à partir d'un seul fichier source}
  \label{fig-C-simple}
\end{figure}
Supposons que l'on ait à créer un exécutable à partir du fichier
suivant (voir aussi figure~\vref{fig-C-simple}) :
\begin{fichier}[label=simple.c]
  int f()
  {
    return 4;
  }
  int main()
  {
    int i=f();
    printf("Bonjour tout le monde.\n");
    return 0;
  }
\end{fichier}
%$

\subsubsection{Création de l'exécutable}

On peut dans le cas simple d'un projet se réduisant à un seul fichier
source, lancer une commande qui crée directement l'exécutable :
\begin{shellcom}
  ¢usercom«gcc -o simple simple.c»
\end{shellcom}
C'est l'option \texttt{-o} \comarg{nom} qui permet de créer un
exécutable dont le nom est \comarg{nom}\footnote{Par défaut ce nom
  est généralement \texttt{a.out}, le nom que \textsc{Thompson} avait
  utilisé pour le premier assembleur créé sur les toutes premières
  versions d'\unix{}.}.  \index{fichier!exécutable} Ce nom peut être
choisi librement, aucune extension particulière n'est nécessaire.  Ce
sont les \emph{attributs} du fichier qui le rendent exécutable et non
son nom.
\begin{note}
  Ici les phases de compilation et d'édition de liens sont réalisées
  automatiquement sans que l'utilisateur n'ait à le demander
  explicitement. Dans ce cas, l'éditeur de liens trouve le code de la
  fonction~\texttt{f} dans le fichier \texttt{simple.c} compilé.
\end{note}


\subsubsection{Exécution}
\label{sec-developper-exe}
\index{exécution}
\index{fichier!exécutable}

On exécute le fichier résultant de l'édition de liens en l'appelant
par son nom :
\begin{shellcom}
  ¢usercom«./simple»
  Bonjour tout le monde.
\end{shellcom}
Tant que le répertoire où réside l'exécutable n'est pas listé dans le
contenu de la variable \envvar{PATH}, il est nécessaire de préfixer
l'exécutable par le chemin pour pouvoir l'exécuter : c'est ici la
signification du~«\texttt{./}» dans \texttt{./test}. Dans le cas
contraire, deux cas peuvent se produire :
\begin{enumerate}
\item le système ne trouve pas votre programme, par exemple si votre
  programme s'appelle \texttt{bidule} et que vous tentez de l'exécuter
  comme suit :
  \begin{shellcom}
    ¢usercom«bidule»
    bash: bidule: command not found
  \end{shellcom}
\item le système n'appelle pas \emph{votre} programme. Par exemple si
  vous avez la mauvaise idée de nommer votre exécutable \texttt{test} :
  \begin{shellcom}
    ¢usercom«test» ¢comcomment«Il semble ne rien se passer»
    ¢usercom«type test»
    test is a shell builtin
  \end{shellcom}
  il existe donc une autre commande nommée \texttt{test} et c'est elle
  qui est exécutée à la place de la votre.
\end{enumerate}
\begin{note}
  Certains objecteront à la lecture de ce paragraphe : « Mais pourquoi
  ne pas rajouter le répertoire courant dans la variable
  \envvar{PATH}\footnote{Si vous n'avez pas l'intention d'objecter,
    continuez donc à lire tranquillement en sautant ce qui suit...} ?
  » La réponse est que pour des raisons de sécurité il n'est pas
  conseillé de rajouter~«\texttt{.}» (le répertoire courant) dans
  cette variable (lire à ce sujet \cite{practical-unix}). Il est donc
  bon de prendre d'ores et déjà l'habitude d'utiliser le
  fameux~«\texttt{./}». On pourra également lire le paragraphe
  \vref{sec-conf-env} qui propose une autre solution.
\end{note}


\subsubsection{Préprocesseur}
\index{préprocesseur du C}
\index{compilation!préprocesseur}

Avant d'être compilé, un source en langage~C est passé à la moulinette
du \emph{préprocesseur}. Ce programme va traiter toutes les directives
de type \verb+#...+ et les remplacer par du code source. Il supprimera
également tous les commentaires. Le résultat de ce « traitement de
texte » sera présenté au compilateur. Sous \unix, le préprocesseur
porte le doux nom de \com{cpp} (\emph{C preprocessor}).  On peut voir
\com{cpp} en action en utilisant l'option \texttt{-E} de \com{gcc},
sur un fichier exemple :
\begin{fichier}[label=testcpp.c]
  #define N 4
  #define carre(a) ((a)*(a))

  int main(int argc, char** argv)
  {
    int i=N,j,k;
    j=2*N;
    k=carre(i+j);
    return 0;   
  }
\end{fichier}
puis :
\begin{shellcom}
  ¢usercom«gcc -E testcpp.c»
  int main(int argc, char** argv)
  {
    int i= 4 ,j,k;
    j=2* 4 ;
    k= (( i+j )*( i+j ));
    return 0;   
  }
\end{shellcom}
On peut également noter que le préprocesseur de \com{gcc} définit
plusieurs symboles qui identifient le système sous-jacent. On peut
utiliser ces symboles lorsqu'on veut créer du code C portable d'un
système (\unix{}) à un autre :
\begin{shellcom}
  ¢usercom«cpp -dM  testcpp.c»
  «¢normalfont ...»
  #define __linux__ 1
  #define __gnu_linux__ 1
  #define __unix__ 1
  #define __i386__ 1
  #define __INT_MAX__ 2147483647
  #define __LONG_LONG_MAX__ 9223372036854775807LL
  #define __DBL_MIN__ 2.2250738585072014e-308
  #define N 4
\end{shellcom}
Ces symboles  peuvent ensuite être exploités par des
directives de type \verb+#ifdef+ :
\begin{verbatim}
#if defined __linux__ && defined __i386__
int fonction_de_la_mort(int,int)
#else
int fonction_de_la_mort(double,double)
#endif
\end{verbatim}

\subsubsection{Répertoires de recherche}
\index{compilation!répertoires de recherche}
Lorsque \com{cpp} se met en branle, et qu'il rencontre une directive
\verb+#include+, il va chercher dans une liste de répertoires le
fichier spécifié. On peut voir la liste de recherche par défaut en
utilisant à nouveau l'option \texttt{-v} de \com{gcc} :
\begin{shellcom}
  ¢usercom«gcc -v -E fantome.c»
  «¢normalfont ...»
  gcc version 3.3.5 (Debian 1:3.3.5-13)
    /usr/lib/gcc-lib/i486-linux/3.3.5/cc1 -E -quiet -v src/testcpp.c
  #include "..." search starts here:
  #include <...> search starts here:
  /usr/local/include
  /usr/i386-redhat-linux/include
  /usr/lib/gcc-lib/i486-linux/3.3.5/include
  /usr/include
  End of search list.
\end{shellcom}
On notera que :
\begin{itemize}
\item les fichiers inclus par une directive du type
  \verb+#include "+\comarg{fichier}\verb+"+ sont recherchés à partir du
  \emph{répertoire courant} ;
\item on peut influer sur la liste des répertoires dans lesquels une
  directive \verb+#include+ recherche les fichiers, grâce à
  l'option~\texttt{-I} de \com{gcc}. Si par exemple, on désire inclure
  le fichier \texttt{bidule.h} se trouvant dans \verb+~/mes_includes+,
  on spécifiera en ligne de commande :
  \begin{shellcom}[noendprompt]
    ¢usercom«gcc -I ~/mes_includes -c monfichier.c »
  \end{shellcom}
  avec :
  \begin{fichier}[label=monfichier.c]
    #include <bidule.h> /* ou "bidule.h" */
    ...
  \end{fichier}
\end{itemize}


\subsubsection{Voir le code assembleur}

Sur les systèmes \unix{} utilisant l'environnement de développement de
chez \gnu, la plupart des langages de programmation compilés (C, C++,
Pascal, Prolog) sont d'abord traduits en langage d'assemblage, on fait
ensuite appel à l'outil assembleur pour produire le fichier objet. Par
simple curiosité on peut voir le code assembleur produit pour le
fichier suivant :
\begin{fichier}[label=testas.c]
  int mafonction(double d)
  {
    return 2.3*d-7.4;
  }
\end{fichier}
On peut demander à \soft{gcc} de s'arrêter à la phase d'assemblage
(c'est-à-dire ne pas produire le fichier objet) avec la commande
suivante :
\begin{shellcom}
  ¢usercom«gcc -S testas.c»
  ¢usercom«ls -l testas.*»
  -rw-r--r--  1 lozano lozano  57 Nov 11 18:30 testas.c
  -rw-r--r--  1 lozano lozano 640 Nov 11 18:31 testas.s
\end{shellcom}
On peut alors ---~toujours dans le cadre d'une curiosité
malsaine~--- examiner le contenant du code assembleur généré, avec la
commande \com{cat} :
\begin{shellcom}
  ¢usercom«cat testas.s»
  ...
  mafonction:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $16, %esp
  ...
\end{shellcom}
%$
On peut ensuite traduire ce code en appelant explicitement l'outil
assembleur :
\begin{shellcom}
  ¢usercom«as testas.s -o testas.o»
\end{shellcom}

\subsubsection{Autres options intéressantes}
\index{compilation!options}

\com{gcc} dispose de moult options que nous ne détaillerons bien
évidemment pas ici. Voici cependant quelques options utiles à
connaître pour mener à bien vos projets :
\begin{itemize}
\index{compilation!optimisation}
\index{optimisation à la compilation}
\item l'option \texttt{-O}\comarg{nombre}\footnote{Ici il s'agit d'un
    « O » majuscule, pour « optimisation. »} met en route
  différentes méthodes d'optimisation pour produire du code plus
  rapide ou utilisant moins de mémoire. En ce qui concerne
  \comarg{nombre}, il peut prendre des valeurs de $0$ à $3$ ($0$ : pas
  d'optimisation, $3$ : optimisation max) ;
  \index{compilation!warning@\emph{warnings}}
  \index{warning@\emph{warning} à la compilation}
\item l'option \texttt{-Wall} affiche tous les \emph{warnings} de
  compilation ; c'est une option incontournable qui permet d'attirer
  l'attention du programmeur sur des portions de programmes «
  douteuses » (variables non initialisées, problème de transtypage,
  ...) ;
\item \texttt{-D}\comarg{macro} est une option passée au préprocesseur
  qui produit le même résultat que l'inclusion dans le source d'une
  ligne \verb+#define +\comarg{macro} 1 ;
\end{itemize}
\index{compilation!en ligne de commande|)}


\subsection{Compilation séparée}
\label{sec-compilation-separee}
\index{compilation!séparée}

\begin{figure}[tb]
  \centering
  \includegraphics[width=\ifframabookversion.96\textwidth\else.87\textwidth\fi]{%
    projetb}
  \caption{Compilation séparée}
  \label{fig-C-separee}
\end{figure}
Dans le contexte de la compilation séparée on a à compiler plusieurs
modules source. Examinons, en guise d'exemple, la situation
(figure~\vref{fig-C-separee}) dans laquelle un fichier contient le
\texttt{main} :
\begin{fichier}[label=main.c]
  #include <stdio.h>
  #include "mod.h"
  
  int f() { return 4; }
  int main(int argc, char** argv)
  {
    int i=g(f());
    return 0;
  }  
\end{fichier}
qui fait appel à une fonction \texttt{g} dont la déclaration se
trouve dans \texttt{mod.h} et la définition dans \texttt{mod.c} :
\begin{fichier}[label=mod.h]
  float g(float);
\end{fichier}
\begin{fichier}[label=mod.c]
  float g(float f)
  {
    return 2*f;
  }
\end{fichier}
Pour compiler ce projet :
\begin{enumerate}
\item On doit compiler séparément \texttt{main.c} et \texttt{mod.c} ;
\item Faire l'édition de liens à partir des fichiers objets créés.
\end{enumerate}

\subsubsection{Compilation en ligne de commande}
\label{sec-compilation-commande}
\index{compilation!en ligne de commande|(} 
\index{fichier!objet} 

Pour créer un fichier objet à partir d'un source en
langage~C ---~c'est-à-dire procéder à la phase de compilation~--- on peut
lancer la commande :
\begin{shellcom}
  ¢usercom«gcc -c main.c -o main.o» ¢comcomment«compilation du premier module»
  ¢usercom«gcc -c mod.c -o mod.o» ¢comcomment«compilation du deuxième module»
\end{shellcom}
Il faut noter ici l'option \texttt{-c} du compilateur qui précise
qu'on n'effectue que la compilation et l'option~\texttt{-o}
(\emph{output}) précise que les fichiers objet doivent être stockés
dans les fichiers \texttt{main.o} et \texttt{mod.o}.

\subsubsection{Édition de liens en ligne de commande}
\label{sec-editiondelien-commande}
\index{edition@{édition de liens}!en ligne de commande}
Pour passer à la phase suivante qui est la création de l'exécutable
par le biais de l'édition de liens, on utilise la commande suivante :
\begin{shellcom}
  ¢usercom«gcc -o main main.o mod.o»
\end{shellcom}
Pour effectuer l'édition de liens, on précise donc le nom de
l'exécutable avec l'option \texttt{-o}, et on spécifie quels sont les
fichiers objet à lier.


\subsection{Bibliothèques}
\label{sec-compilation-bibliothèque}
\index{edition@{édition de liens}!avec bibliothèques}
\index{bibliothèque et édition de liens}
\index{exécutable!lié dynamiquement}

\subsubsection{Lier un exécutable avec une bibliothèque}

Pour ce qui concerne Linux ---~et c'est le cas de la plupart des
systèmes \unix~--- les exécutables créés sont des exécutables
\emph{dynamiques}, c'est-à-dire que le code qu'ils contiennent fait
appel à des bibliothèques dynamiques. Soit le source suivant :
\begin{fichier}[label=bonjour.c]
  #include <stdio.h>
  int main() 
  { 
    printf("bonjour tout le monde\n"); 
    return 0; 
  }
\end{fichier}
et la commande suivante pour créer un exécutable :
\begin{shellcom}
  ¢usercom«gcc -o bonjour bonjour.c»
\end{shellcom}
On peut examiner l'exécutable créé  avec la commande \com{ldd} pour
obtenir les bibliothèques dont il dépend :
\begin{shellcom}
  ¢usercom«ldd bonjour»
      libc.so.6 => /lib/libc.so.6 (0x4001a000)
      /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
\end{shellcom}
On voit donc ici que l'exécutable \texttt{bonjour} est lié
dynamiquement avec la bibliothèque standard, dite « libC » (voir
figure~\vref{fig-C-dyn}).
\begin{figure}[tb]
  \centering
  \includegraphics[width=\ifframabookversion.93\textwidth\else.87\textwidth\fi]{projetc1}
  \caption{Édition de liens dynamique.}
  \label{fig-C-dyn}
\end{figure}
Ces deux bibliothèques sont automatiquement ajoutées à l'édition de
liens, sur le système Linux de l'auteur. La première contient le code
de la bibliothèque standard du C (et donc celui de la fonction
\texttt{printf}), la deuxième contient les instructions permettant de
charger dynamiquement les bibliothèques.


Dans certaines situations, il faut préciser explicitement que le code
fait appel à des fonctions définies dans une bibliothèque spécifique.
Par exemple pour compiler le fichier en langage~C suivant faisant appel
à une routine de la bibliothèque mathématique :
\begin{fichier}[label=testmath.c]
  #include <stdio.h>
  #include <stdlib.h>
  #include <math.h>

  int main(int argc, char** argv)
  {
    if (argc==2)
      /* renvoie la racine de l'argument 1 */
      printf("%f\n",sqrt(atof(argv[1])));
    return 0;
  }
\end{fichier}
on procédera comme suit :
\begin{shellcom}
  ¢usercom«gcc -c testmath.c -o testmath.o»
  ¢usercom«gcc -o testmath  testmath.o -lm»
\end{shellcom}
L'option \texttt{-l} précise que l'on veut ajouter la bibliothèque
mathématique du~C à l'édition de liens. On a alors :
\begin{shellcom}
  ¢usercom«ldd testmath»
  libm.so.6 => /lib/libm.so.6 (0x40021000)
  libc.so.6 => /lib/libc.so.6 (0x40043000)
  /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
\end{shellcom}
on constate donc que l'exécutable \texttt{testmath} est lié
dynamiquement avec la bibliothèque mathématique stockée dans le
fichier~\texttt{/lib/libm.so.6}.
%
%
\index{exécutable!lié statiquement}
%
%
\begin{figure}[tb]
  \centering
  \includegraphics[width=\ifframabookversion.93\textwidth\else.87\textwidth\fi]{projetc2}
  \caption{Édition de liens statique.}
  \label{fig-C-stat}
\end{figure}
Il est possible de forcer la création d'un exécutable statique. Pour
cela on impose alors au \textsl{linker} d'insérer dans l'exécutable le
code des fonctions provenant de ou des bibliothèques nécessaires :
\begin{shellcom}
  ¢usercom«gcc -static -o testmath.stat testmath.o -lm»
  ¢usercom«ls -lh testmath*»
  -rwxr-xr-x  1 lozano lozano  12K Nov 11 17:54 testmath
  -rw-r--r--  1 lozano lozano  223 Nov 11 17:54 testmath.c
  -rw-r--r--  1 lozano lozano  948 Nov 11 17:54 testmath.o
  -rwxr-xr-x  1 lozano lozano 471K Nov 11 17:58 testmath.stat
\end{shellcom}
On pourra noter la différence de taille des exécutables créés. Ceci
confirme que dans le cas « statique » le code des fonctions issu des
bibliothèques est inséré dans l'exécutable (voir figure~\vref{fig-C-stat}).


\subsubsection{Où sont les bibliothèques ?}
\label{sec-ou-sont-les-libs}
\index{edition@{édition de liens}!répertoires de recherches}
\index{bibliothèque!emplacement}

Lorsqu'on précise, lors de l'édition de liens, l'option \texttt{-l}
suivie de \texttt{m}, le \textsl{linker} cherche dans une série de
répertoires prédéterminée, un fichier nommé \texttt{libm.so} pour la
bibliothèque dynamique et \texttt{libm.a} pour la bibliothèque
statique. Dans le cas où la bibliothèque à inclure n'est pas dans la
liste de répertoires standard, il est nécessaire d'utiliser l'option
\texttt{-L} suivie du répertoire où se trouve la bibliothèque en
question. Par exemple, on écrira :
\begin{shellcom}
  ¢usercom«gcc -L ~/lib -o djobi djobi.o -lmabib»
\end{shellcom}
si la bibliothèque \texttt{libmabib.so} ou \texttt{libmabib.a} se
trouve dans le répertoire \verb+~/lib+.  S'il s'agit d'une
bibliothèque dynamique (\texttt{libmabib.so}), pour pouvoir
\emph{exécuter} le fichier \texttt{djobi}, il faudra impérativement
indiquer au programme qui charge les bibliothèques dynamiques où se
trouve \texttt{libmabib.so}.  On peut réaliser cela en positionnant la
variable d'environnement \envvar{LD\_LIBRARY\_PATH} avec la liste des
répertoires susceptibles de contenir des bibliothèques dynamiques :
\begin{flushleft}
  \quad\verb+export LD_LIBRARY_PATH=+\comarg[1]{dir}\verb+:+\comarg[2]{dir}\verb+:+
  \verb+$LD_LIBRARY_PATH+ 
\end{flushleft}
%$
Dans notre exemple on écrira :
\begin{shellcom}
  ¢usercom«export LD_LIBRARY_PATH=~/lib:$LD_LIBRARY_PATH»
\end{shellcom}
À titre indicatif, sous le système HPUX (l'\unix{} de Hewlett Packard)
cette variable se nomme \envvar{SHLIB\_PATH}.

%$pour emacs-font-lock


\subsubsection{Créer une bibliothèque}
\label{sec-creer-lib}

On peut créer des bibliothèques qui seront liées statiquement ou
dynamiquement lors de l'édition de liens. La création d'une bibliothèque
consiste à rassembler un certain nombre de fichiers objets dans un
seul fichier. On supposera, à titre d'exemple, que l'on dispose de
trois fichiers : \texttt{mod1.o} \texttt{mod2.o} et \texttt{mod3.o}
résultant de la compilation de trois fichiers écrits en langage~C.

\paragraph{Statique}
\label{sec-creer-lib-statiques}

Pour créer une bibliothèque statique, on pourra utiliser la commande :
\framaserre{\baselineskip}%
\begin{shellcom}
  ¢usercom«ar ruv libbidule.a mod1.o mod2.o mod3.o»
  ar: création de libbidule.a
  a - mod1.o
  a - mod2.o
  a - mod3.o
\end{shellcom}
La commande \com{ar} crée un fichier bibliothèque
\texttt{libbidule.a}.  L'option \texttt{ru} permet d'insérer en
remplaçant chaque objet dans l'archive, l'option \texttt{v} permet de
rendre la commande \com{ar} plus bavarde qu'elle ne l'est par défaut.
On se reportera à la page de manuel pour plus de détail.  Une fois la
bibliothèque statique créée on peut l'utiliser lors d'une édition de
liens comme suit :
\begin{shellcom}
  ¢usercom«gcc -L. -o monappli monmain.o -lbidule»
\end{shellcom}
On notera  :
\begin{enumerate}
\item l'option \texttt{-L} pour indiquer qu'il faut chercher la
  bibliothèque dans le répertoire courant ;
\item la syntaxe \texttt{-lbidule} qui cherche une bibliothèque
  nommée \texttt{libbidule.a}
\end{enumerate}
\begin{note}
  L'option \texttt{-s} de la commande \com{ar} ou l'utilisation de la
  commande \com{ranlib} en lieu et place de \com{ar} permet de créer
  un index des symboles et ainsi d'accélerer les éditions de liens que
  l'on réalisera avec  la bibliothèque.
\end{note}

\paragraph{Dynamique}
\label{sec-creer-lib-dynamiques}

Pour créer une bibliothèque dynamique on utilisera la syntaxe suivante :
\begin{shellcom}
  ¢usercom«gcc -shared -o libbidule.so mod1.o mod2.o mod3.o»
\end{shellcom}
Pour utiliser une telle bibliothèque à l'édition de liens :
\begin{shellcom}
  ¢usercom«gcc -L. -o monappli monmain.o -lbidule»
\end{shellcom}
\begin{attention}
  Il faudra s'assurer que la variable d'environnement
  \envvar{LD\_LIBRARY\_PATH} conti\-en\-ne le répertoire où se trouve
  \texttt{libbidule.so} pour que cette dernière puisse être chargée au
  moment de l'exécution de \texttt{monappli} (cf.
  \S~\vref{sec-ou-sont-les-libs}).
\end{attention}


\subsection{Se simplifier la vie avec \com{make}}
\label{sec-compiler-avec-make}
\index{make@\texttt{make}!compiler avec}
\index{compilation!avec \texttt{make}}

Encore une fois, nous supposons que le lecteur a à sa disposition le
\gnu{} \com{make}. Ce dernier définit deux règles liées à la gestion
de projet en C et C++. La première règle est la suivante :
\begin{flushleft}
  \verb+%.o : %.c+\\
  \maketab\verb+$(CC) -c $(CPPFLAGS) $(CFLAGS) $<+ 
\end{flushleft}
qui indique comment construire le fichier objet à partir du fichier~C.
Les variables \texttt{CPPFLAGS} et \texttt{CFLAGS} permettent
respectivement de passer des options au préprocesseur et au
compilateur\footnote{En C++, \texttt{CFLAGS} devient
  \texttt{CXXFLAGS}.}.  On pourra donc utiliser par exemple le
\texttt{makefile} suivant :
\begin{fichier}[label=makefile.test.1]
  CFLAGS=-Wall
  CPPFLAGS=-I/usr/local/machin-chose
  
  test.o : test.c
\end{fichier}
ce qui donnera : 
\begin{shellcom}
  ¢usercom«make -f makefile.test.1»
  cc -Wall -I/usr/local/machin-chose  -c test.c -o test.o
\end{shellcom}
Le \gnu{} \com{make} positionne par défaut la variable \verb+$(CC)+ à
la valeur \com{cc}.  %$
En outre, il définit un ensemble de règles pour l'édition de liens :
\begin{itemize}
\item s'il n'y a qu'un seul fichier objet, la règle est la suivante :
\begin{flushleft}
  \verb+% : %.o+\\
  \maketab\verb+$(CC) $(LDFLAGS) $< $(LOADLIBES)+
\end{flushleft}
\texttt{LDFLAGS} permet de passer des options au linker, et
\texttt{LOADLIBES} permet d'indiquer quelles sont les bibliothèques
nécessaires à l'édition de liens.
\item s'il s'agit d'une compilation séparée, une règle du type :
  \begin{flushleft}
    \texttt{main : main.o fichier1.o fichier2.o}
  \end{flushleft}
  lancera la compilation des fichiers \texttt{main.c},
  \texttt{fichier1.c} et \texttt{fichier2.c}, puis l'édition de liens
  avec les trois fichiers objets générés pour créer l'exécutable
  \texttt{main}. Dans le cas de la compilation séparée, il est
  nécessaire qu'un des fichiers source porte le nom de la cible (ici
  c'est \texttt{main.c}).
\end{itemize}
Voyons deux exemples, le premier pour le cas d'un seul fichier objet :
\begin{fichier}[label=makefile.test.2]
  CFLAGS=-Wall
  CPPFLAGS=-I/usr/local/machin-chose
  LDFLAGS=-L/usr/local/bidule-truc
  LOADLIBES=-lbidule

  test : test.o
\end{fichier}
qui donne :
\begin{shellcom}
  ¢usercom«make -f makefile.test.2 test»
  cc -Wall -I/usr/local/machin-chose  -c test.c -o test.o
  cc -L/usr/local/bidule-truc  test.o -lbidule  -o test
\end{shellcom}
Dans le cas de la compilation séparée, on pourra écrire le
\texttt{makefile} suivant qui permet de créer l'exécutable de
l'exemple du paragraphe~\vref{sec-compilation-separee} :
\begin{fichier}[label=makefile.test.3]
  CFLAGS=-Wall
  CPPFLAGS=-I/usr/local/machin-chose
  LDFLAGS=-L/usr/local/bidule-truc
  LOADLIBES=-lbidule

  main : main.o mod.o
\end{fichier}
qui donne :
\begin{shellcom}
  ¢usercom«make -f makefile.test.3»
  cc -Wall -I/usr/local/machin-chose  -c main.c -o main.o
  cc -Wall -I/usr/local/machin-chose  -c mod.c -o mod.o
  cc -L/usr/local/bidule-truc main.o mod.o -lbidule -o main
\end{shellcom}


Pour finir cette section sur l'utilisation de \soft{make} dans le
cadre d'un projet en langage~C, nous allons voir comment on peut
demander à \soft{gcc} de générer pour nous les dépendances du projet.
\index{make@\texttt{make}!générer les dépendances}
\index{compilation!générer les dépendances} Dans notre exemple de
compilation séparée, ces dépendances sont les suivantes :
\begin{itemize}
\item \texttt{mod.o} dépend uniquement de \texttt{mod.c} : on
  doit reconstruire le premier si le dernier a été modifié ;
\item \texttt{main.o} dépend de \texttt{main.c} et de
  \texttt{mod.h} à cause de la présence de la directive
  \verb+#include "mod.h"+ : si \texttt{mod.h} ou \texttt{main.c}
  a été modifié il faut reconstruire \texttt{main.o}.
\end{itemize}
Cette liste peut être générée automatiquement par \com{gcc} grâce à
l'option~\texttt{-MM} qui affiche les dépendances liées aux fichiers
inclus avec la directive du préprocesseur \verb+#include"+\comarg{fichier}\verb+"+.  Ainsi :
\begin{shellcom}
  ¢usercom«gcc -MM main.c mod.c»
  main.o: main.c mod.h
  mod.o: mod.c
\end{shellcom}
On peut utiliser cette option de \texttt{-MM} directement dans le
\texttt{makefile} lui-même :
\begin{fichier}
  CFLAGS=-Wall
  CPPFLAGS=-I/usr/local/machin-chose
  LDFLAGS=-L/usr/local/bidule-chouette
  LOADLIBES=-lbidule
  OBJFILES=main.o est_f.o
  CFILES=$(OBJFILES:.o=.c)

  main : $(OBJFILES)
  depend.dat : 
  ¢maketab $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(CFILES) > depend.dat
  -include depend.dat
\end{fichier}
%$
Dans ce \texttt{makefile}, on a défini une cible nommée
\texttt{depend.dat} dont le but est de construire le fichier de
dépendances~\texttt{depend.dat}. La directive \texttt{-include} permet
ensuite d'inclure le fichier \texttt{depend.dat} même si celui-ci
n'existe pas (c'est la signification du tiret qui préfixe
\texttt{include}). On pourra également remarquer l'utilisation des
variables \verb+$(OBJFILES)+ et \verb+$(CFILES)+, créées ici pour «
rationaliser » le \texttt{makefile} (cf.
\S~\vref{sec-make-var-outils}).


\section*{Conclusion}
\label{sec-developper-conclusion}

La « digestion » des informations fournies dans ce chapitre devrait
vous donner les bases nécessaires pour créer des scripts divers et
variés, lesquels, à l'instar de ceux de l'auteur, iront en se
complexifiant et s'améliorant. La connaissance des outils « standard »
d'\unix{} (\com{awk}, \com{sed}, etc.), couplée avec celles des scripts
shell et du fonctionnement de \com{make}, est un atout majeur pour
entamer un projet de développement ambitieux. C'est également un atout
pour se lancer dans les tâches d'administration système.  La
connaissance des principes de base de la compilation sous \unix{} est
quant à elle importante, car elle permet de comprendre les mécanismes
qui entrent en jeu dans la création d'un exécutable.

%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "../framabook"
%%% End: 
