Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

The \listfiles command will give the list of all loaded files (and therefore also packages) at the end of the .log file, but how do I determine from inside LaTeX, whether package A was loaded before package B or vice versa?

share|improve this question
    
Please note: While the question is about packages, the answers are also usable for other files! –  Stephen Feb 25 '12 at 13:51

3 Answers 3

up vote 14 down vote accepted

You can access the list as a comma separated list of filenames in \@filelist

If you need this check after \begin{document} use \listfiles so LaTeX saves that information.

\listfiles does

  \@for\@currname:=\@filelist\do{%
      .....

to iterate over this list.

So for example you could define

\makeatletter

\def\test#1#2{%
\def\hmma{#1.sty}%
\let\hmmb\@empty
\@for\@currname:=\@filelist\do{%
   \ifx\@currname\hmma
     \def\hmmb{#2.sty}%
   \fi
   \ifx\@currname\hmmb
       \typeout{#1 loaded before #2}%
   \fi}}

then using this as:

\test{marginnote}{geometry}

will type out

marginnote loaded before geometry

if that is in fact the case.

As noted in the comments you might want to use different comand names in production code, also if the two .sty are removed from the test you can test other files such as class and def files that are listed by LaTeX, but would need to explicitly use the extension, so \test{marginnote.sty}{geometry.sty}

share|improve this answer
    
\@filelist was the information I was missing! Thanks! \@currname collides with the hyperref package: ! Undefined control sequence. \@currname ->\@nil Replacing \@currname by \@dc (or something longer, which is probably better to make sure it is not used elsewhere) works (got that \hmma/\hmmb ;-)). \newcommand{\test}[2] instead of \def\test#1#2 might be considered, too. –  Stephen Feb 25 '12 at 13:47
    
While my question was about packages, you might want to add a note that your answer also works for any files, if .sty is removed from the code and \test{marginnote.sty}{geometry.sty} is used. For other files e.g. \test{subdocumentabcd.tex}{subdocumentzyxw.tex} or checking for .cfg or included .pdf or whatsoever is then possible. Your solution is robust but not complicated. A really nice answer. (Your new badge already says so.) +1 (yesterday) and now also accepted. –  Stephen Feb 25 '12 at 13:47

Here's a way: the code from \usepackage{xparse} to \ExplSyntaxOff should go before checking any package, of course. The definition of the \test command is just for showing that the code works, though, and can be removed.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \l_pkgfirst_list_seq
\bool_new:N \l_pkgfirst_tmpa_bool
\cs_generate_variant:Nn \seq_set_split:Nnn { Nnx }
\NewDocumentCommand{\ifpackagefirst}{mmmm}
  {
   \bool_set_false:N \l_pkgfirst_tmpa_bool
   \seq_set_split:Nnx \l_pkgfirst_list_seq {,} { \use:c { @filelist} }
   \seq_if_in:NnT \l_pkgfirst_list_seq {#1} { \bool_set_true:N \l_pkgfirst_tmpa_bool }
   \seq_if_in:NnT \l_pkgfirst_list_seq {#2} { \bool_set_true:N \l_pkgfirst_tmpa_bool }
   \bool_if:NTF \l_pkgfirst_tmpa_bool
     { \pkgfirst_compare:nnnn {#1}{#2}{#3}{#4} }
     { \msg_term:x {OOPS,~packages~not~both~loaded} }
  }
\cs_new:Npn \pkgfirst_compare:nnnn #1 #2 #3 #4
  {
   \bool_set_false:N \l_pkgfirst_tmpa_bool
   \seq_map_inline:Nn \l_pkgfirst_list_seq
     {
      \str_if_eq:nnT { #1 } { ##1 }
        { \prg_map_break:n { \bool_set_true:N \l_pkgfirst_tmpa_bool } }
      \str_if_eq:nnT { #2 } { ##1 }
        { \prg_map_break:n { \bool_set_false:N \l_pkgfirst_tmpa_bool } }
     }
   \bool_if:NTF \l_pkgfirst_tmpa_bool {#3} {#4}
  }


\NewDocumentCommand\test{m m}
  {\ifpackagefirst{#1}{#2}{\msg_term:x {#1~before~#2}}{\msg_term:x {#1~after~#2}}}

\ExplSyntaxOff

\usepackage{graphicx}
\usepackage{imakeidx}
\usepackage{kantlipsum}


\test{graphicx.sty}{imakeidx.sty}

\test{imakeidx.sty}{kantlipsum.sty}

\test{kantlipsum.sty}{graphicx.sty}

\test{pippo.sty}{pluto.sty}

\stop

This is the output:

*************************************************
* graphicx.sty before imakeidx.sty
*************************************************
*************************************************
* imakeidx.sty before kantlipsum.sty
*************************************************
*************************************************
* kantlipsum.sty after graphicx.sty
*************************************************
*************************************************
* OOPS, packages not both loaded
*************************************************

Usage:

\ifpackagefirst{package1.sty}{package2.sty}
  {code to be executed if 1 has been loaded before 2}
  {code to be executed if 2 has been loaded before 1}

If the packages are not both loaded, no code will be executed.

share|improve this answer
    
+1 and thanks for moving! –  Stephen Feb 24 '12 at 17:38
    
It is good to have a completely different kind of solution for the problem. –  Stephen Feb 25 '12 at 13:48

A way to check for file order is to check the order of the files loaded in the @filelist.

\documentclass{book}
\usepackage{graphicx}
\usepackage{longtable}
\usepackage{verse}
\usepackage{hyperref}
\usepackage{caption}
\newcounter{ctr}
\makeatletter
\let\afilelist\@filelist
\begin{document}
% Just to see files
\@for\next:=\afilelist\do{%
 \next, \par
}
% Command factory
\stepcounter{ctr}
\@for\next:=\afilelist\do{%
      \expandafter\edef\csname @\next\endcsname{\thectr}
     \stepcounter{ctr}
}

% Define macro to check order
\def\checkpkgorder#1#2{%
   \edef\X{\csname @#1\endcsname}
    \edef\Y{\csname @#2\endcsname}
    \expandafter\ifnum\X\expandafter<\Y
      Yes loaded earlier \X, \Y
     \else
      No loaded later \X, \Y
   \fi
}

\checkpkgorder{book.cls}{ifxetex.sty}
\end{document}
share|improve this answer
    
+1 and thanks for moving! –  Stephen Feb 24 '12 at 17:38
    
For checking after \begin{document} and to cover a before b as well as b before a in one step your code is really useful, but because I need neither of those I accepted the answer of David Carlisle. –  Stephen Feb 25 '12 at 13:48
    
@Stephen Not to worry, David's answer was very elegant. It deserved to be accepted. Upvoted it myself also. –  Yiannis Lazarides Feb 25 '12 at 15:31

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.