summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/pkgloader/pkgloader.tex
blob: 93ffd7808064626597dcae313d52277d78b49bc8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%%
%                                                                              %
%  Copyright (c) 2018 - Michiel Helvensteijn   (www.mhelvens.net)              %
%                                                                              %
%  https://github.com/mhelvens/latex-pkgloader                                 %
%                                                                              %
%  This work may be distributed and/or modified under the conditions           %
%  of the LaTeX Project Public License, either version 1.3 of this             %
%  license or (at your option) any later version. The latest version           %
%  of this license is in       http://www.latex-project.org/lppl.txt           %
%  and version 1.3 or later is part of all distributions of LaTeX              %
%  version 2005/12/01 or later.                                                %
%                                                                              %
%  This work has the LPPL maintenance status `maintained'.                     %
%                                                                              %
%  The Current Maintainer of this work is Michiel Helvensteijn.                %
%                                                                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%%

\documentclass[a4paper]{pkgloader-packagedoc}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Setup                                                                        %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\def\nt#1{\ensuremath{\hbox{\footnotesize$\langle$}\mathit{#1}\hbox{\footnotesize$\rangle$}}}
\def\|{\ \mid\ }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Global Changes                                                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\changes{0.1.0}{2014/01/29}
  {initial version}
  
\changes{0.2.0}{2014/05/10}
  {an important release, which implements most features described in
   the pkgloader TUGBoat article, and fixes a ton of bugs}
  
\changes{0.3.0}{2014/08/31}
  {fixed the package to work with more recent releases of expl3,
   which removed the individual l3kernel .sty files; additionally,
   pkgloader now understands preferred loading orders of cleveref}
  
\changes{0.4.1}{2014/10/26}
  {integrates a number of new package loading rules contributed by the community}
  
\changes{0.5.0}{2014/11/30}
  {integrates a number of new package loading rules contributed by the community}

\changes{0.5.1}{2017/09/20}
  {fixed the package to work aafter \cs_new:Nn was changed to only allow 'N' and 'n' in function signatures (2016/08/20)}

\changes{0.6.0}{2018/03/24}
  {integrates a number of new package loading rules contributed by the community}

\changes{0.7.0}{2018/04/29}
  {integrates a number of new package loading rules contributed by the community}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}                                                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\maketitle

\section {Introduction}  % % % % % % % % % % % % % % % % % % % % % % % % % % % %

\LaTeX\ can be extended by loading packages
using a \lstinline+\usepackage+, \lstinline+\RequirePackage+
or \lstinline+\RequirePackageWithOptions+ command. Similarly, documents load
a document class using \lstinline+\documentclass+, \lstinline+\LoadClass+
or \lstinline+\LoadClassWithOptions+.
Packages and classes can add definitions, change existing ones,
or otherwise extend functionality of the language.

While the Turing-complete power of the \TeX\ language is quite useful at times,
it does make it all too easy for independent package authors to step on each
others toes. CTAN is full of conceptually independent packages that cannot be
loaded together, or break if they are not loaded in a specific order.

Yet, until now, there has been no automated package management to speak of.
Document authors are usually told to avoid certain package combinations,
or to load packages in some specific order.
Occasionally, package authors patch their code to be aware of specific
other packages, circumventing known conflicts.
But this makes maintenance more difficult, because these package authors
are `mixing concerns'; they put code related to other packages into their
own package. And it is all done in an ad-hoc fashion.

Enter \lstinline+pkgloader+.



\subsection {Package Description} % % % % % % % % % % % % % % % % % % % % % %

Here is an example of main file for a \LaTeX\ document
which uses \lstinline+pkgloader+:

\newcommand{\morecode}{\hbox{\vphantom{\LARGE(}\smash{\ \small\vdots}}}
\newcommand{\anyorder}{
	\smash{\small\hbox{
		\(
			\qquad\left.\vrule height 1em depth 1.4em width 0pt\right\}
			\hbox{\textit{\rmfamily any order}}
		\)
}	}	}
\newcommand{\optional}{
	\smash{\small\raisebox{-.7\baselineskip}{
		\(
			\qquad\left.
				\begin{array}{l}\\[.8em]\end{array}
			\right\}
			\hbox{\textit{\rmfamily optional}}
		\)
}	}	}
\begin{latex}
\RequirePackage{pkgloader}
    \documentclass{article}
    \usepackage{algorithm}
    \usepackage{hyperref} $\anyorder$
    \usepackage{float}
\LoadPackagesNow $\hskip44.3pt\optional$
$\morecode$
\begin{document} $\hdots$ \end{document}
\end{latex}

The idea is to load \lstinline+pkgloader+ before loading any other
package or class.
It can then intercept all loading requests, analyze them
and load them properly, taking this burden off the shoulders of
the average document author.

Between the second and fifth line, the loading of all packages
and classes is postponed. The \lstinline+\LoadPackagesNow+ command then
loads the packages in some valid order. This also happens automatically
upon reaching the end of the preamble. During this process,
`conflict resolving' code may also be run, meant specifically to make
other packages work together properly. If the above code were
compiled without \lstinline+pkgloader+,
the given package order would cause errors.
%%
The main advantage to this approach is that the complexity of dealing
with package conflicts is moved to the \lstinline+pkgloader+ package and handled
in a systematic manner.

If you are a document author, this may be all you need to know to use
\lstinline+pkgloader+. If you are interested in more advanced functionality,
read on!


\subsection {The \texttt{pkgloader} Area} % % % % % % % %

\describeanymacro
	{\ttfamily\bfseries\textbackslash RequirePackage\!\!\!\!\!}
	{{\ttfamily{\bfseries\{}pkgloader{\bfseries\}}\quad\ldots\quad{\bfseries\textbackslash LoadPackagesNow}}}

The \lstinline+pkgloader+ area is the area between
\lstinline+\RequirePackage{pkgloader}+ and
\lstinline+\LoadPackagesNow+.
Within it, the three traditional package-loading commands
are `hijacked', recording information rather than loading
packages directly. Also, a \lstinline+\Load+ command is
available, which offers more flexibility in regulating
package loading behavior.

|pkgloader| accepts sets of rules coming from outside
packages, though support is still somewhat limited.
Any |pkgloader-|\nt{something}|.sty| file can be loaded
within the |pkgloader| area by passing \nt{something}
as a package option. The file |pkgloader-recommended.sty|
is loaded this way by default. You can overwrite this by
passing |recommended=false| as an option. For example:

\begin{latex}
\RequirePackage[recommended=false, my-better-rules]{pkgloader}
     $\smash{\raisebox{-1pt}{\small\vdots}}$
\LoadPackagesNow
\end{latex}

This area does not play by the recommended package loading
rules, but uses the rules in |pkgloader-my-better-rules.sty|
instead.



\subsection {Package / Class Loading Requests} % % % % % % % %


\marginnote{\ttfamily\bfseries\textbackslash usepackage\\
	\textbackslash RequirePackage\\
	\textbackslash RequirePackageW{\ldots}s
	\textbackslash documentclass\\
	\textbackslash LoadClass\\
	\textbackslash LoadClassW{\ldots}s}\noindent
For requesting specific packages or classes inside the
|pkgloader| area, just use the commands always used
for this purpose:
	\lstinline+\usepackage+,
	\lstinline+\RequirePackage+ and
	\lstinline+\RequirePackageWithOptions+, as well as
	\lstinline+\documentclass+,
	\lstinline+\LoadClass+ and
	\lstinline+\LoadClassWithOptions+.
Their syntax and effective semantics
are the same as they have always been. Their effects are just delayed,
reordered and perhaps modified by the active \emph{package loading rules}.



\subsection {Package Loading Rules} % % % % % % % %

\marginnote{\ttfamily\bfseries\textbackslash Load}\noindent
Each invocation if the \lstinline+\Load+ command sets up a rule about
a class, package or packages, which are not necessarily ever loaded.
These rules can come from any number of different sources.
A central registry will be maintained together with \lstinline+pkgloader+ itself
in the form of |pkgloader-recommended.sty|,
specifying well-known conflicts and resolutions.
Individual package authors, however, can supply their own rules,
as can document authors. Though ideally, for the
average document author, things should `just work'.

The \lstinline+\Load+ command expects the following syntax:

\vskip\abovedisplayskip
\begingroup
\centering
\begin{tabular}{r@{\ \ \ \ }r@{\ \ \ \ }l}
	\nt{load}           &$::=$&   \lstinline+\Load+$\ \nt{package}\ \ \nt{clause}_1\ \ldots\ \nt{clause}_i$        \\
	                    &$ \|$&   \lstinline+\Load class+$\ \nt{package}\ \ \nt{clause}_1\ \ldots\ \nt{clause}_i$        \\
	                    &$ \|$&   \lstinline+\Load error+ $\ \ \ \,\nt{clause}_1\ \ldots\ \nt{clause}_i$         \\[2mm]
	
	\nt{package}        &$::=$&   \lstinline+[+$\;\nt{options}\;$\lstinline+] {+$\;\nt{pkg}\;$\lstinline+} [+$\;\nt{version}\;$\lstinline+]+     \\[2mm]
	
	\nt{clause}         &$::=$&   $\nt{order}\ \ \|\ \ \nt{condition}\ \ \|\ \ \nt{reason}$              \\[2mm]
	
	\nt{order}          &$::=$&   \lstinline+before {+ $\nt{pkg}_1\,$\lstinline+, +$\ldots\,$\lstinline+, +$\nt{pkg}_j$ \lstinline+}+            \\
		                &$ \|$&   \lstinline+after  {+ $\nt{pkg}_1\,$\lstinline+, +$\ldots\,$\lstinline+, +$\nt{pkg}_j$ \lstinline+}+            \\
		                &$ \|$&   \lstinline+early+                                                                \\
		                &$ \|$&   \lstinline+late+                                                                 \\[2mm]
	
	\nt{condition}      &$::=$&   \lstinline+always+                           $\ \ \|\ \ $
	                              \lstinline+if loaded+                        $\ \ \|\ \ $
	                              \lstinline+if {+ $\nt{\phi}$ \lstinline+}+   \\[2mm]
	
	\nt{\phi}           &$::=$&   $\nt{pkg}$                                   $\ \ \|\ \ $
		                          $\nt{\phi}\ $\lstinline+&&+$\ \nt{\phi}$     $\ \ \|\ \ $
		                          $\nt{\phi}\ $\lstinline+||+$\ \nt{\phi}$     $\ \ \|\ \ $
		                          \lstinline+!+$\;\nt{\phi}$                   $\ \ \|\ \ $
		                          \lstinline+(+$\;\nt{\phi}\;$\lstinline+)+                                                  \\[2mm]
	
	\nt{reason}         &$::=$&   \lstinline+because {+ $\nt{token{-}list}$ \lstinline+}+    
\end{tabular}
\endgroup
\vskip\belowdisplayskip

\noindent
\nt{pkg} represents a package or class name.
\nt{token{-}list} should expand to a human-readable text without formatting.

\marginnote{\ttfamily\bfseries if}\noindent
The \( \nt{condition} \) clause determines under which package loading
conditions any and all parts of a rule are invoked.
Here is an example of the use of the \( \nt{condition} \) clause:
\begin{latex}
\Load {res-ie-lst} if {inputenc && listings}
\Load {fixltx2e}   always
\end{latex}

\lstinline+res-ie-lst+ (a fictional package built specifically to resolve the
conflict between \lstinline+inputenc+ and \lstinline+listings+) will be loaded if requested
specifically, or if both \lstinline+inputenc+ and \lstinline+listings+ are loaded. The \lstinline+fixltx2e+ package is
always loaded, as it was created to smooth over some mistakes in the
\LaTeXe\ core.

\marginnote{\ttfamily\bfseries always\\ if loaded}
The \lstinline+always+ keyword makes a rule unconditional. The \lstinline+if loaded+
directive makes a rule conditional on its package already being loaded anyway.
This can be used to order two packages only when they are being loaded by other
means, and is actually the default behavior (in other words, \lstinline+if loaded+
really does nothing).

\marginnote{\ttfamily\bfseries before\\ after}
The \lstinline+before+ and \lstinline+after+ keywords should be pretty straightforward. They
can be used for things like:
\begin{latex}
\Load {xltxtra} after {graphicx}
\end{latex}
which fixes the loading order between these two packages when they are both loaded.

\marginnote{\ttfamily\bfseries early\\ late}
But the set of \LaTeX\ packages is constantly growing, and it appears that
some big packages should almost always be loaded early in the process,
and others should almost always be loaded late. Therefore the \lstinline+early+
and \lstinline+late+ stages are provided as a fallback mechanism. If two packages
are not related by an explicit application order, their loading order
may still be decided by their relative stages: \lstinline+early+ before `normal' before \lstinline+late+.
That way, conflicts may be avoided in a majority of cases.
This is implemented with |pkgloader-early| and |pkgloader-late| stubs in
the loading order graph.

The following example uses the \( \nt{order} \) clause
in addition to the \( \nt{condition} \) clause:
\begin{latex}
\Load {res-ie-lst} if {inputenc && listings}
                after {inputenc ,  listings}
\Load {fixltx2e} always early
\end{latex}
An important observation about the loading order is that it
might form a cycle when contradictory ordering rules are specified:
\begin{latex}
\Load {pkg1} after {pkg2}
\Load {pkg2} after {pkg1}
\end{latex}
In practice this could happen if the authors of \lstinline+pkg1+ and \lstinline+pkg2+
independently discover a conflict, and both try to solve it by patching
their code and having their own package be loaded last. \lstinline+pkgloader+
can provide a clear error message when this happens, allowing the
two package authors to seek contact and collaborate on a solution.

\marginnote{\ttfamily\bfseries error}
Now, about the \lstinline+error+ keyword.
Initially all package combinations are valid. But if two packages
are irredeemably incompatible, their combination can be made to trigger
an error message by a command such as the following:
\begin{latex}
\Load error if {algorithms && pseudocode}
\end{latex}
These two packages provide almost identical functionality and conflict
on many command-names. It was generally agreed upon that they should
never be loaded together. Document authors should simply choose one
or the other.

\marginnote{\ttfamily\bfseries because}
Finally, the \( \nt{reason} \) clause can be used to supply a
human-readable explanation of a rule.
We finish the above examples by providing reasons:
\begin{latex}[basewidth=.598em]
\Load {res-ie-lst} if {inputenc && listings}
                after {inputenc ,  listings}
      because {it allows the use of 1 byte unicode
               characters in code listings}

\Load {fixltx2e} always early
      because {it fixes some imperfections in LaTeX2e}

\Load error when {algorithms && pseudocode}
      because {they provide almost identical functionality
               and conflict on many command names}
\end{latex}
In the future, reasons will be extracted automatically to
generate documentation. For now, they are displayed with error
messages related to the rule in question.


\subsection {Status} % % % % % % % %

So far, \lstinline+pkgloader+ seems to work as expected, but has not
yet been tested as extensively as it should be. Therefore, bug-reports
on the |pkgloader| issue tracker on Github would be most welcome.
Also, lots more recommended package loading rules are needed.

I nonetheless decided to publish the package now, because I've been
promising to do so for a while now:

\begin{center}
	\url{http://tex.stackexchange.com/questions/123174}
\end{center}

\noindent
I hope that, with feedback and community collaboration,
use of this package will become widespread and package
authors will be able to work in a more modular fashion.

\emph{Future versions} of |pkgloader| will be able to
intelligently merge package options
and to track packages loaded by other packages in order
to better inform the user --- perhaps even fix problems
by carrying information into the next run through auxiliary files.
But most of this will depend on feedback.



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{document}                                                                 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%