tuteurs.ens.fr/logiciels/latex/nouveau_package.tml
2009-09-27 15:43:57 +02:00

518 lines
15 KiB
XML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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 ?</h2>
<p>
Définir son propre package permet :</p>
<ul>
<li>de ne pas avoir à toujours insérer toujours les mêmes lignes :
<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 ;</li>
<li>d'avoir des documents cohérents entre eux.</li>
</ul>
<h2>Principe</h2>
<p>Nous allons créer un fichier « <code>mon_package.sty</code> » (ou
tout autre nom qui ne crée de doublon) qui comportera les instructions
qui permettront :</p>
<ul>
<li>de charger nos extensions préférées ;</li>
<li>de définir nos commandes préférées ;</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> :
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 ;</li>
<li><code><b>\ProvidesPackage{&lt;package&gt;}[&lt;version&gt;]</b></code> :
le package s'identifie (là encore on peut donner en argument
optionnel une date de version) ;</li>
<li><code><b>\RequirePackage[&lt;options&gt;]{&lt;package&gt;}</b></code> :
équivalent de <code>\usepackage</code> pour l'écriture d'un package
ou d'une classe, on peut passer des options au package comme
habituellement ;</li>
<li><code><b>\DeclareOption{&lt;option&gt;}{&lt;action&gt;}</b></code> :
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 ;</li>
<li><code><b>\DeclareOption*{&lt;action&gt;}</b></code> :
comportement adopté par le package quand il est confronté à une
option passée qui n'est pas déclarée ;</li>
<li><code><b>\ProcessOptions</b></code> : 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!) ;</li>
<li><code><b>\newcommand{\commande}{&lt;code&gt;}</b></code> :
définition d'une nouvelle commande (voir la page sur les
<a href="&url.tuteurs;logiciels/latex/macros.html">macros</a>) ;</li>
<li><code><b>\endinput</b></code> : 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 « liste des
algorithmes » 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 « algo » quand on a besoin des fonctionnalités
idoines. Voilà comment :</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 :</p>
<ul>
<li><code><b>\if<i>quelquechose</i></b></code>  à utiliser ainsi (la
partie « else » 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> 
<code>\if<i>quelquechose</i></code>  devient
équivalent à <b>if true</b> ;</li>
<li><code><b>\<i>quelquechose</i>false</b></code> 
<code>\if<i>quelquechose</i></code>  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 « algo » 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 « algo » aura été passée dans
le fichier <code>.tex</code> :</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 :</b> notons que dans les packages « @ » est une lettre
(contrairement aux document <code>.tex</code> où « @ » est un symbole)
et que donc on peut écrire des noms de commandes avec « @ ». 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>,
« <code>\if@algo</code> » aurait été interprétée comme la commande
<code>\if</code> suivie de « @algo ».</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 « normales » :
<code>algo</code> et <code>listings</code> mais quand on est face à
une option inconnue on la passe à babel, ainsi :</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 :</b> les options déclarées avec
<code>\DeclareOption{...}{...}</code> peuvent être passées comme
<em>options globales</em> du document comme dans :
</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é « a4paper »
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) ;</li>
<li> <code><b>\@ifundefined{commande}<!--
-->{&lt;then&gt;}{&lt;else&gt;}</b></code> : 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) ;</li>
<li> <code><b>\PackageWarning{&lt;package&gt;}<!--
-->{&lt;texte&gt;}</b></code> : produit un warning lors de la
compilation (par opposition à <code>\PackageError{...}{...}</code>) ;</li>
<li> <code><b>\CurrentOption</b></code> : l'option en cours de
traitement ;</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
« <code>=value2</code> » 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 :</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 :</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 :</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 :</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 ;</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>) ;</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 : <code>clsguide</code> (à noter également les documentations
<code>fntguide</code>, <code>usrguide</code>)  pour une documentation
générale sur LaTeX : <code>source2e</code> ou plus soft <em>The not so
short introduction to LaTeX</em> (disponible en français !).</p>
<p>Sur internet : <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  comment réaliser le symbole « 1 » avec une double
barre pour désigner une fonction indicatrice ? La réponse se trouve
sur Google, groupes et taper « <code>group:fr.comp.text.tex 1 barre
indicatrice</code> ». C'est une source d'informations inépuisable.
Sinon les tuteurs ou forum <code>ens.forum.informatique.tex</code>.</p>
<div class="metainformation"> Auteur : Josselin Noirel. Dernière
modification le <date value="$Date: 2007-07-17 10:02:52 $"/>.
</div>
</body>
</html>