6

Is there a way of creating a dependency tree for packages \RequirePackageing each other for those packages used in my document, ideally with the respective required options and version numbers? Are there any tools or packages for this purpose? This is very important for debugging package options conflicts (see "Package options and \RequirePackage: order of commands and option conflicts?"; see also "What are best practices for package authors to deal with package conflicts?").

For example, I don't need to load graphicx explicitly because dtklogos (which I'm using) already requires/loads it. In fact graphicx also requires/loads graphics and also keyval, which is incidentally also required/loaded by microtype. Etc. I would like to give an example involving package option conflicts, but as the relevant dependencies are cumbersome to figure out and debug, no example is on my mind right now (I've bumped into several, but since they didn't compile, I abandoned them and have forgotten about them); this is one thing this question can actually help to address.

11
  • You need to know which package loads what before hand -> There must be a list of what loads what -> There must be a central log of this -> that log should be updated -> CTAN should have that too -> ... :) option clash for xcolor
    – percusse
    Feb 24, 2013 at 14:46
  • @percuße There must be a way for LaTeX to automatically detect calls to \RequirePackage for it to log/write/track them somewhere else. If not, something should probably be patched; I genuinely hope that I won't need to wait for LaTeX3 :-) Feb 24, 2013 at 15:11
  • I think that's unfortunately pretty much wishful thinking but indeed would be nice to have. However, there are not many such cases where you would have this problem. So manual approach would almost always be easier.
    – percusse
    Feb 24, 2013 at 15:18
  • 1
    \RequirePackage is everywhere yes but option clashes are rare. If some author decided to use dvipsnames and another svgnames for xcolor package, what should you do? What should be tracked? If a package requires another which requires yet enother how much deep should you go? The issue is not that straightforward to keep track of the packages AND their respective options.
    – percusse
    Feb 24, 2013 at 15:22
  • 2
    If your package needs graphicx, then load it, regardless, if it is already loaded or another package loads it. Thus package dtklogo might load graphicx in it current version, but this is very likely an implementation detail for the package. In a later version dtklogos might implement it differently without graphicx and your package is then broken. Feb 24, 2013 at 16:04

2 Answers 2

4

I agree with Joseph that you should always explicitly require any package that you need, regardless of whether any other package has already loaded it, but to answer your question about logging the dependency tree, one can hook into \@onefilewithoptions like so (this is better than just hooking \RequirePackage as it also hooks classes etc):

\errorcontextlines=\maxdimen

% begin code to log calls to \@onefilewithoptions (http://tex.stackexchange.com/questions/99723/creating-a-dependency-tree-requirepackage-for-packages-used-in-my-document)
\makeatletter
\def\@log@onefilewithoptions@{}% this will store the file tree
\def\@log@onefilewithoptions@delim{^^J}%
\def\@log@onefilewithoptions#1[#2][#3]#4{% our hook
    \ifx\@currnamestack\@empty
        \def\@log@onefilewithoptions@tmp{.}%
    \else
        \edef\@log@onefilewithoptions@tmp{\expandafter\@parse@curnamestack\@currnamestack\@nil}%
    \fi
    \expandafter\g@addto@macro\expandafter\@log@onefilewithoptions@\expandafter{\@log@onefilewithoptions@tmp}%
    \edef\@log@onefilewithoptions@tmp{#4[#2]{#1}[#3]\@log@onefilewithoptions@delim}%
    \expandafter\g@addto@macro\expandafter\@log@onefilewithoptions@\expandafter{\@log@onefilewithoptions@tmp}%
}
\def\@parse@curnamestack#1#2#3#4\@nil{%
    |%
    \@log@onefilewithoptions@ifblank{#4}{%
        +%
    }{%
        \@parse@curnamestack#4\@nil
    }%
}
\newcommand{\typeoutonefilewithoptionstree}{\typeout{@onefilewithoptions tree follows:\@log@onefilewithoptions@delim\@log@onefilewithoptions@ end @onefilewithoptions tree.}}
% display the tree at end document (for demonstration purposes)
\AtEndDocument{\typeoutonefilewithoptionstree}%
% patch the original to invoke our hook first, and to show the tree if there's an option clash
\def\@onefilewithoptions#1[#2][#3]#4{%
  %added by cyberSingularity
  \@log@onefilewithoptions{#1}[#2][#3]{#4}%
  %end addition
  \@pushfilename
  \xdef\@currname{#1}%
  \global\let\@currext#4%
  \expandafter\let\csname\@currname.\@currext-h@@k\endcsname\@empty
  \let\CurrentOption\@empty
  \@reset@ptions
  \makeatletter
  \def\reserved@a{%
    \@ifl@aded\@currext{#1}%
      {\@if@ptions\@currext{#1}{#2}{}%
        {%added by cyberSingularity
        \typeout{Option clash for \@cls@pkg\space #1. To help,}%
        \typeoutonefilewithoptionstree
        %end addition
        \@latex@error
            {Option clash for \@cls@pkg\space #1}%
            {The package #1 has already been loaded
             with options:\MessageBreak
             \space\space[\@ptionlist{#1.\@currext}]\MessageBreak
             There has now been an attempt to load it
              with options\MessageBreak
             \space\space[#2]\MessageBreak
             Adding the global options:\MessageBreak
             \space\space
                  \@ptionlist{#1.\@currext},#2\MessageBreak
             to your \noexpand\documentclass declaration may fix this.%
             \MessageBreak
             Try typing \space <return> \space to proceed.}}}%
      {\@pass@ptions\@currext{#2}{#1}%
       \global\expandafter
       \let\csname ver@\@currname.\@currext\endcsname\@empty
       \InputIfFileExists
         {\@currname.\@currext}%
         {}%
         {\@missingfileerror\@currname\@currext}%
    \let\@unprocessedoptions\@@unprocessedoptions
    \csname\@currname.\@currext-h@@k\endcsname
    \expandafter\let\csname\@currname.\@currext-h@@k\endcsname
              \@undefined
    \@unprocessedoptions}
    \@ifl@ter\@currext{#1}{#3}{}%
      {\@latex@warning@no@line
         {You have requested,\on@line,
          version\MessageBreak
            `#3' of \@cls@pkg\space #1,\MessageBreak
          but only version\MessageBreak
           `\csname ver@#1.\@currext\endcsname'\MessageBreak
          is available}}%
    \ifx\@currext\@clsextension\let\LoadClass\@twoloadclasserror\fi
    \@popfilename
    \@reset@ptions}%
  \reserved@a}
% borrowed from etoolbox (don't really want to load it just for this)
\newcommand{\@log@onefilewithoptions@ifblank}[1]{%
  \etb@ifblank@i#1&&\@secondoftwo\@firstoftwo:}
\long\def\etb@ifblank@i#1#2&#3#4#5:{#4}
\makeatother
% end code to log calls to \@onefilewithoptions



% real document begins
\documentclass[a4paper]{article}
\usepackage{graphicx}
\usepackage{keyval}
%\usepackage{tikz}% uncomment this to get an option clash on the next line
\usepackage[svgnames]{xcolor}

\begin{document}
    See console output or log file.
\end{document}

Now, when you get an option clash, you should get a dump of the dependency tree just before the error.

Also, the dependency tree is always shown \AtEndDocument.

Note that in both cases, one needs to examine the console or log output, which will contain something like this:

@onefilewithoptions tree follows:
.cls[a4paper]{article}[]
.sty[]{graphicx}[]
|+sty[]{keyval}[]
|+sty[]{graphics}[]
||+sty[]{trig}[]
||+sty[]{infwarerr}[2007/09/09]
||+sty[]{ltxcmds}[2010/12/07]
.sty[]{keyval}[]
.sty[svgnames]{xcolor}[]
end @onefilewithoptions tree.

Hopefully this is easy enough to read.

5

While as indicated in comments I'd recommend simply requiring those packages you use directly, the idea of a 'tree' of package dependencies has been addressed for LaTeX2e in the pkgloader package: see Automated management of package options and loading order) for more on this. As described in the package documentation, the idea is that you give the list of packages you want to use in any order and it then 'sorts out' the dependency tree.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .