%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \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} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%