Ai écrit la page sur écrire un nouveau package (fichier

"nouveau_package.tml").  J'ai modifié les codes que j'avais testés avant de
manière à les rendre plus simples donc il faudra que je fasse une
vérification.  Je commite sur les remarques encourageantes de Laurent.
 -- Joss
This commit is contained in:
noirel 2003-03-18 00:15:44 +00:00
parent 359d4185f2
commit 78c4fd9239

View file

@ -0,0 +1,517 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html
PUBLIC "-//ENS/Tuteurs//DTD TML 1//EN"
"tuteurs://DTD/tml.dtd">
<html>
<head>
<title>Son package</title>
</head>
<body>
<h1>Écrire son propre package</h1>
<h2>Pourquoi&nbsp;?</h2>
<p>
Définir son propre package permet&nbsp;:</p>
<ul>
<li>de ne pas avoir à toujours insérer toujours les mêmes lignes&nbsp;:
<pre>
\usepackage[francais]{babel}
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[dvips]{graphicx}
\usepackage{amsmath}
\usepackage{amssymb}
</pre>
</li>
<li>de ne pas avoir à redéfinir toutes ses macros et aussi de gagner
du temps à force de s'habituer à ses commandes persos&nbsp;;</li>
<li>d'avoir des documents cohérents entre eux.</li>
</ul>
<h2>Principe</h2>
<p>Nous allons créer un fichier «&nbsp;<code>mon_package.sty</code>&nbsp;» (ou
tout autre nom qui ne crée de doublon) qui comportera les instructions
qui permettront&nbsp;:</p>
<ul>
<li>de charger nos extensions préférées&nbsp;;</li>
<li>de définir nos commandes préférées&nbsp;;</li>
<li>de passer des options lors du chargement du package qui lui
donneront un comportement particulier.</li>
</ul>
<h2>Organisation</h2>
<h3>Listing</h3>
<pre>
<b>%% Informations générales</b>
\NeedsTeXFormat{LaTeX2e}[1999/01/01]
\ProvidesPackage{mon_package}[2003/01/01]
<b>%% Chargement des extensions</b>
\RequirePackage[dvips]{graphicx}
<b>%% Déclaration des options</b>
\DeclareOption{option}{...}
\DeclareOption*{...}
\ProcessOptions
<b>%% Définition des commandes</b>
\newcommand{\blabla}{Super commande}
<b>%% Fin du package</b>
\endinput
</pre>
<h3>Explications</h3>
<ul>
<li><code><b>\NeedsTeXFormat{&lt;formar&gt;}[&lt;version&gt;]</b></code>&nbsp;:
informe TeX du format (LaTeX2e, donc refus de LaTeX2.09, plain TeX,
eplain TeX, AMS-TeX, etc.) nécessaire pour l'utilisation du
package, on peut spécifier un argument optionnel (entre crochets)
permettant d'utiliser des versions récentes dudit format&nbsp;;</li>
<li><code><b>\ProvidesPackage{&lt;package&gt;}[&lt;version&gt;]</b></code>&nbsp;:
le package s'identifie (là encore on peut donner en argument
optionnel une date de version)&nbsp;;</li>
<li><code><b>\RequirePackage[&lt;options&gt;]{&lt;package&gt;}</b></code>&nbsp;:
équivalent de <code>\usepackage</code> pour l'écriture d'un package
ou d'une classe, on peut passer des options au package comme
habituellement&nbsp;;</li>
<li><code><b>\DeclareOption{&lt;option&gt;}{&lt;action&gt;}</b></code>&nbsp;:
déclare une option qui peut être passée lors de l'appel du
package, lorsque l'option <code>&lt;option&gt;</code> est passée
<code>&lt;action&gt;</code> est exécutée&nbsp;;</li>
<li><code><b>\DeclareOption*{&lt;action&gt;}</b></code>&nbsp;:
comportement adopté par le package quand il est confronté à une
option passée qui n'est pas déclarée&nbsp;;</li>
<li><code><b>\ProcessOptions</b></code>&nbsp;: exécute le code des options
passées, si cette commande n'existe pas dans le package les options
seront sans effet (bien prendre conscience que les declarations
n'exécutent pas de code!)&nbsp;;</li>
<li><code><b>\newcommand{\commande}{&lt;code&gt;}</b></code>&nbsp;:
définition d'une nouvelle commande (voir la page sur les
<a href="&url.tuteurs;logiciels/latex/macros.html">macros</a>)&nbsp;;</li>
<li><code><b>\endinput</b></code>&nbsp;: fin du package.</li> </ul>
<h2>Exemple simple</h2>
<p>Supposons qu'il m'arrive d'écrire des documents sans algorithmes et
d'autres avec. Lorsque j'en ai besoin je charge les packages
<code>algorithm</code> et <code>algorithmic</code> qui permettent de
mettre en forme des algorithmes, d'en faire une «&nbsp;liste des
algorithmes&nbsp;» et de les rendre flottants (voir la page...). Je peux
encore utiliser mon propre package pour gérer ces cas, il suffit
d'introduire une option «&nbsp;algo&nbsp;» quand on a besoin des fonctionnalités
idoines. Voilà comment&nbsp;:</p>
<pre>
<b>%% (...) \NeedsTeXFormat et \ProvidesPackage</b>
\newif\if@algo \@algofalse
\DeclareOption{algo}{\@algotrue}
\DeclareOption*{}<b>%% Ne rien faire quand une option est inconnue</b>
\ProcessOptions
\if@algo
\RequirePackage{algorithm}
\RequirePackage{algorithmic}
\RequirePackage{mes-commandes-algo}
\newcommand{\algorithme}{Blabla}
\fi
<b>%% (...) \newcommand's et \endinput</b>
</pre>
<p>
La commande <code>\newif\if<i>quelquechose</i></code> crée trois
commandes&nbsp;:</p>
<ul>
<li><code><b>\if<i>quelquechose</i></b></code>&nbsp; à utiliser ainsi (la
partie «&nbsp;else&nbsp;» est facultative)
<pre>
\if<i>quelquechose</i>
<i>Code si oui</i>
\else
<i>Code si non</i>
\fi
</pre></li>
<li><code><b>\<i>quelquechose</i>true</b></code>&nbsp;
<code>\if<i>quelquechose</i></code>&nbsp; devient
équivalent à <b>if true</b>&nbsp;;</li>
<li><code><b>\<i>quelquechose</i>false</b></code>&nbsp;
<code>\if<i>quelquechose</i></code>&nbsp; devient
équivalent à <b>if false</b>.</li>
</ul>
<p>Dans notre exemple on crée une instruction conditionnelle
<code>\if@algo</code> qui est équivalente à <b>if false</b> (à cause
de <code>\@algofalse</code>). Cependant, si l'option «&nbsp;algo&nbsp;» est
passée au package, on exécute <code>\@algotrue</code> qui a pour effet
de rendre <code>\if@algo</code> équivalent à <b>if true</b>. Les
packages relatifs à l'algo (et les commandes définies dans le bloc)
seront chargés si et seulement si l'option «&nbsp;algo&nbsp;» aura été passée dans
le fichier <code>.tex</code>&nbsp;:</p>
<ul>
<li>soit au niveau du <code>\usepackage</code>
<pre>
\documentclass[a4paper, dvips]{article}
\usepackage[<b>algo</b>]{mon_package}
\begin{document}
.
.
.
\end{document}
</pre></li>
<li>soit au niveau du <code>\documentclass</code>
<pre>
\documentclass[a4paper, dvips, <b>algo</b>]{article}
\usepackage{mon_package}
\begin{document}
.
.
.
\end{document}
</pre></li></ul>
<p><b>Remarque&nbsp;:</b> notons que dans les packages «&nbsp;@&nbsp;» est une lettre
(contrairement aux document <code>.tex</code> où «&nbsp;@&nbsp;» est un symbole)
et que donc on peut écrire des noms de commandes avec «&nbsp;@&nbsp;». D'où les
noms <code>\makeatletter</code> et <code>\makeatother</code> utilisées
dans des cas un peu exceptionnels. Dans un fichier <code>.tex</code>,
«&nbsp;<code>\if@algo</code>&nbsp;» aurait été interprétée comme la commande
<code>\if</code> suivie de «&nbsp;@algo&nbsp;».</p>
<h2>Exemple moins simple, plus réaliste</h2>
<h3>Listing</h3>
<pre>
\NeedsTeXFormat{LaTeX2e}[1999/01/01]
\ProvidesPackage{mon_package}[2003/01/01]
\newif\if@algo \@algofalse
\newif\if@listings \@listingsfalse
\DeclareOption{listings}{\@listingstrue}
\DeclareOption{algo}{\@algotrue}
\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{babel}}
\ProcessOptions
\RequirePackage{babel}
\if@algo
\RequirePackage{algorithm}
\RequirePackage{algorithmic}
\RequirePackage{mes-commandes-algo}
\fi
\if@listings
\RequirePackage{listings}
\RequirePackage{verbatim}
\RequirePackage{moreverb}
\RequirePackage{mes-commandes-listings}
\fi
\endinput
</pre>
<h3>Explications</h3>
<p>On déclare comme précédemment deux options «&nbsp;normales&nbsp;»&nbsp;:
<code>algo</code> et <code>listings</code> mais quand on est face à
une option inconnue on la passe à babel, ainsi&nbsp;:</p>
<pre>
\documentclass[a4paper]{article}
\usepackage[algo, listings, english, greek, francais]{mon_package}
\begin{document}
.
.
.
\end{document}
</pre>
<p>
sera équivalent à charger les modules d'algorithmiques, les modules de
d'écriture de programmes, et babel avec les options
<code>english</code>, <code>greek</code> et <code>francais</code>
(dans cet ordre). La commande <code>\PassOptionsToPackage<!--
-->{&lt;options&gt;}{&lt;package&gt;}</code> ne charge pas le package
<code>&lt;package&gt;</code>, elle rajoute les
<code>&lt;options&gt;</code> à la liste d'options qui seront passées
au package <code>&lt;package&gt;</code> lors de l'appel
<code>\RequirePackage{&lt;package&gt;}</code>.
</p>
<p>
<b>Remarque&nbsp;:</b> les options déclarées avec
<code>\DeclareOption{...}{...}</code> peuvent être passées comme
<em>options globales</em> du document comme dans&nbsp;:
</p>
<pre>
\documentclass[a4paper, algo, listings]{article}
\usepackage[english, greek, francais]{mon_package}
\begin{document}
.
.
.
\end{document}
</pre>
<p>
En revanche les langages doivent être passés au package lui-même
(notamment babel n'a pas tenté de trouver un langage nommé «&nbsp;a4paper&nbsp;»
ce qui aurait abouti à une erreur).
</p>
<h3>Limitations</h3>
<p>D'une part on ne peut pas utiliser ce mécanisme pour plusieurs
packages auquel on passerait les options non déclarées avec
<code>\DeclareOption{...}{...}</code> et d'autre part on ne peut pas
s'abstenir de passer au moins une option de langage au package.</p>
<h2>Exemple (très) compliqué</h2>
<h3>Prérequis</h3>
<ul>
<li>Avoir lu la doc du package <code>keyval</code> de David Carliste (ou
peut-être prochainement une page tuteurs à ce sujet)&nbsp;;</li>
<li> <code><b>\@ifundefined{commande}<!--
-->{&lt;then&gt;}{&lt;else&gt;}</b></code>&nbsp;: si
<code>\commande</code> (avec le backslash contrairement à l'argument
de <code>\@ifundefined</code>) n'est pas définie alors exécute
<code>&lt;then&gt;</code> sinon exécute
<code>&lt;else&gt;</code> (LaTeX interne)&nbsp;;</li>
<li> <code><b>\PackageWarning{&lt;package&gt;}<!--
-->{&lt;texte&gt;}</b></code>&nbsp;: produit un warning lors de la
compilation (par opposition à <code>\PackageError{...}{...}</code>)&nbsp;;</li>
<li> <code><b>\CurrentOption</b></code>&nbsp;: l'option en cours de
traitement&nbsp;;</li>
<li>le reste c'est du TeX, donc il ne vaut mieux pas s'attarder
dessus.</li>
</ul>
<h3>Listing général</h3>
<pre>
\NeedsTeXFormat{LaTeX2e}[1999/01/01]
\ProvidesPackage{mon_package}[2003/01/01]
\RequirePackage{keyval}
<b>%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Pour gérer les deux types d'options : %
% 1. les options normales (\DeclareOption{...}{...}) %
% 2. les options type key-val option=value (\define@key{...}{...}{...}) %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%</b>
\@ifundefined{my@unusedlist}{<b>%</b>
\let\my@unusedlist\@empty}{}
\@ifundefined{my@extractkey}{<b>%</b>
\def\my@extractkey#1=#2\my@extractkey{#1}}{}
\newcommand{\ProcessUnusedOptions}[1]{<b>%</b>
\let\my@tempa\@empty
\let\my@tempb\@empty
\@for\CurrentOption:=\my@unusedlist\do{<b>%</b>
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\my@key
\expandafter\expandafter\expandafter{<b>%</b>
\expandafter\my@extractkey\CurrentOption=\my@extractkey}<b>%</b>
\@ifundefined{KV@#1@\my@key}{<b>%</b>
\edef\my@tempa{\my@tempa,\CurrentOption,}}{<b>%</b>
\edef\my@tempb{\my@tempb,\CurrentOption,}}}<b>%</b>
\@for\CurrentOption:=\my@tempa\do{<b>%</b>
\ifx\CurrentOption\@empty\else
\PackageWarning{mypack}{`\CurrentOption' not defined.}\fi}<b>%</b>
\edef\my@tempb{<b>%</b>
\noexpand\setkeys{#1}{\my@tempb}}<b>%</b>
\my@tempb
\AtEndOfPackage{\let\@unprocessedoptions\relax}}
\DeclareOption*{<b>%</b>
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\my@unusedlist
\expandafter\expandafter\expandafter{<b>%</b>
\expandafter\my@unusedlist\expandafter,<b>%</b>
\CurrentOption}}
<b>%%%%%%%%%%%%%%%
% Fin du bloc %
%%%%%%%%%%%%%%%</b>
<b>%% Options «normales»</b>
\DeclareOption{foo}{&lt;action foo&gt;}
\DeclareOption{bar}{&lt;action bar&gt;}
<b>%% Options passées sous forme key=val</b>
\define@key{mypack}{&lt;key1&gt;}{&lt;action 1&gt; dépendant de #1}
\define@key{mypack}{&lt;key2&gt;}[&lt;default&gt;]<!--
-->{&lt;action 2&gt; dépendant de #1}
\ProcessOptions
\ProcessUnusedOptions{mypack}
\endinput
</pre>
<h3>Explications</h3>
<p>Dans l'exemple suivant</p>
<pre>
\documentclass[foo]{article}
\usepackage[foo, key1=value1, key2=value2]{mypack}
\begin{document}
.
.
.
\end{document}
</pre>
<p>l'option <code>foo</code> va agir comme dans les exemples simples,
<code>key1=value1</code> va exécuter le code <code>&lt;action 1&gt;</code>
en utilisant <code>value1</code> en lieu et place de <code>#1</code>. Idem
pour <code>key2=value2</code> sauf que on peut omettre la partie
«&nbsp;<code>=value2</code>&nbsp;» auquel cas <code>&lt;action 2&gt;</code> est exécuté
en utilisant <code>&lt;default&gt;</code> à la place de <code>#1</code>.
Par exemple si <code>mon_package.sty</code> contient&nbsp;:</p>
<pre>
<b>%% (...) </b>
\newcounter{nombre}
\define@key{mypack}{number}[14]{%
\setcounter{nombre}{#1}}
<b>%% (...) </b>
</pre>
<p>on pourra l'appeler ainsi</p>
<pre>
\documentclass[foo]{article}
\usepackage[number=10]{mypack}
\begin{document}
.
\thenombre\ affiche 10.
.
.
\end{document}
</pre>
<p>ou encore comme cela</p>
<pre>
\documentclass[foo]{article}
\usepackage[number]{mypack}
\begin{document}
.
\thenombre\ affiche 14.
.
.
\end{document}
</pre>
<p>ou bien sûr sans option du tout (auquel cas le code
<code>\setcounter</code> ne sera pas exécuté et donc le compteur
<code>nombre</code> vaudra zéro).</p>
<h3>Exemple d'application</h3>
<p>Si <code>mon_package</code> contient&nbsp;:</p>
<pre>
\newcommand{\pack@languages}{francais}
\define@key{mypack}{language}{%
\renewcommand{\pack@languages}{#1}}
\RequirePackage[\pack@languages]{babel}
</pre>
<p>alors on peut l'appeler ainsi</p>
<pre>
\documentclass[a4paper]{article}
\usepackage[<b>language={english, francais}</b>]{mon_package}
\newcommand{\option}{\texttt}
\begin{document}
.
\paragraph{Remarque}
Noter les accolades pour que l'option \option{francais} ne soit pas
passée comme une option à part.
.
.
\end{document}
</pre>
<p>ou encore ainsi&nbsp;:</p>
<pre>
\documentclass[a4paper]{article}
\usepackage{mon_package}
\newcommand{\option}{\texttt}
\begin{document}
.
Babel chargé avec l'option \option{francais}.
.
.
\end{document}
</pre>
<p>
Là encore les options de langages ne pourront pas être spécifiées
globalement avec la commande <code>\documentclass</code>. (La raison en est
que les options globales qui ne correspondent pas à des options déclarées
avec <code>\DeclareOption</code> ne sont pas transmises à
<code>\DeclareOption*</code>.)
</p>
<h2>Utiliser son package</h2>
<p>Le package <code>mon_package</code> doit pouvoir être trouvé par LaTeX,
pour cela on peut&nbsp;:</p>
<ul>
<li>mettre le fichier <code>mon_package</code> dans le même répertoire que
les fichier <code>.tex</code> qui l'utilisent&nbsp;;</li>
<li>mettre le fichier dans un répertoire de son compte (par exemple
<code>~/texmf/tex/latex/perso/</code> et créer la variable d'environnement
<code>export TEXINPUTS=$HOME/texmf//:</code> (certaines distributions
permettent de créer un fichier ls-R grâce à la commande
<code>texhash</code>)&nbsp;;</li>
<li>si l'on est root sur sa machine on peut le mettre dans l'arborescence
texmf classique (mais ça ne facilite pas des upgrades des distributions
LaTeX) et exécuter la commande <code>mktexlsr</code>.</li>
</ul>
<h2>Documentation et aide</h2>
<p>Pour une documentation concernant l'écriture de classe et de
packages&nbsp;: <code>clsguide</code> (à noter également les documentations
<code>fntguide</code>, <code>usrguide</code>)&nbsp; pour une documentation
générale sur LaTeX&nbsp;: <code>source2e</code> ou plus soft <em>The not so
short introduction to LaTeX</em> (disponible en français&nbsp;!).</p>
<p>Sur internet&nbsp;: <a href="http://www.ctan.org/">CTAN</a>, les
newsgroup <code>fr.comp.text.tex</code> et <code>comp.text.tex</code> sur
lesquels on peut faire une recherche <em>via</em> Google. Par
exemple&nbsp; comment réaliser le symbole «&nbsp;1&nbsp;» avec une double
barre pour désigner une fonction indicatrice&nbsp;? La réponse se trouve
sur Google, groupes et taper «&nbsp;<code>group:fr.comp.text.tex 1 barre
indicatrice</code>&nbsp;». C'est une source d'informations inépuisable.
Sinon les tuteurs ou forum <code>ens.forum.informatique.tex</code>.</p>
<div class="metainformation"> Auteur&nbsp;: Josselin Noirel
(16/03/2003)</div>
</body>
</html>