18

Is there a way to make latexmk aware of external references as they are imported via the xr package? My Problem is that I have several files for weekly exercise sheets. Sometimes I have references to earlier exercises which I include via the xr package (neat thing...). As mistakes happen, I sometimes have to correct an exercise sheet after the next one has been issued. So I want a latexmk file2 recognize that file1 has changed and hence file1 has to be recompiled again before working on file2...?

Of course, I can (and actually do) put everything in a big make file which calls the latexmk commands on the individual files according to their dependencies but is there a latexmk-intrinsic way to automate this?

2 Answers 2

16
  • The following marks the dependencies on the external tex and aux files in the main file, even if those files do not already exist (there is otherwise no tex file dependency and the aux file dependency doesn't automatically happen if the file doesn't exist - the warning generated by the xr package is not processed by latexmk because it is different to the standard LaTeX warnings; namely it is missing a period after the filename).
  • It then uses a custom dependency to latexmk such that it knows how to build aux files. If an aux file with a different root filename needs to be regenerated, it causes latexmk to process the corresponding job (in a separate system call). Note that with this approach, any warnings from latexmk generated while processing the external documents will not be summarised at the end of the main run, and the concepts of $max_repeat and Run number $pass{$rule} of rule '$rule' are weakened!
  • This works best when latexmk has the recorder option activated (default since v4.31, otherwise enabled through the command line option -recorder=1 or appropriate line in .latexmkrc); without this, changes to the external aux files may be missed, though changes to the external tex files will still start the correct processing.
  • Currently, this requires use of the command \myexternaldocument instead of \externaldocument, though the original command could be patched.

I have provided the code in the context of a minimum example (though none was provided in the question) for better illustratation. Three files are shown below: file1.tex, file2.tex and .latexmkrc.

  • file1 references something in file2.
  • Executing latexmk file1 is sufficient to correctly build both file1 and file2.
  • Remember that using the -deps option to latexmk will show the dependency database and may help to verify how things are working.
  • Note the commented line in file2.tex to facilitate testing.

Here's file1.tex:

\documentclass{article}

%%% HELPER CODE FOR DEALING WITH EXTERNAL REFERENCES
\usepackage{xr}
\makeatletter
\newcommand*{\addFileDependency}[1]{% argument=file name and extension
  \typeout{(#1)}% latexmk will find this if $recorder=0 (however, in that case, it will ignore #1 if it is a .aux or .pdf file etc and it exists! if it doesn't exist, it will appear in the list of dependents regardless)
  \@addtofilelist{#1}% if you want it to appear in \listfiles, not really necessary and latexmk doesn't use this
  \IfFileExists{#1}{}{\typeout{No file #1.}}% latexmk will find this message if #1 doesn't exist (yet)
}
\makeatother

\newcommand*{\myexternaldocument}[1]{%
    \externaldocument{#1}%
    \addFileDependency{#1.tex}%
    \addFileDependency{#1.aux}%
}
%%% END HELPER CODE

% put all the external documents here!
\myexternaldocument{file2}

% just to see what's happening
\listfiles

\begin{document}

Label1 is on page \pageref{label1} of file2.

\end{document}

And file2.tex:

\documentclass{article}
\usepackage{lipsum}
\begin{document}
%\lipsum[1-10]% to test, comment or uncomment this line, and rerun `latexmk file1`. Note that both are then rebuilt as necessary and the page number in the generated `file1` is always correct.
\section{Label1}
\label{label1}
This is referenced by file1.
\end{document}

And finally .latexmkrc:

add_cus_dep( 'tex', 'aux', 0, 'makeexternaldocument' );

sub makeexternaldocument {
    # if the dependency isn't one of the files that this latexmk run will consider, process it
    # without this test, we would get an infinite loop!
    if (!($root_filename eq $_[0]))
    {
        system( "latexmk \"$_[0]\"" );
    }
}
5
  • 1
    Really helpful answer cyberSingularity. Many thanks. I have modified the definition of \myexternaldocument to allow the optional tag for the external document reference, and it seems to work well: \newcommand*{\myexternaldocument}[2][]{% \externaldocument[#1]{#2}% \addFileDependency{#2.tex}% \addFileDependency{#2.aux}% } \myexternaldocument[mapp:]{MovantsAppendix} Commented Jun 20, 2022 at 20:21
  • Many thanks for this detailed answer! Sadly, it seems to result in warnings with current latexmk versions, namely: ` ``Latexmk: Possible bug: In linking rules, I already set from_rules_main{file1.aux} to 'cusdep tex aux file1' But now I also have a different rule 'latex' that also made the file.``` This is also mentioned here. Commented Sep 14, 2022 at 18:52
  • Does this work with cyclic references (file1 references file2, and file2 references file1)? I'm getting an apparently infinite loop. Manually running pdflatex on both files a couple of times works fine though.
    – Jellby
    Commented Dec 8, 2022 at 8:50
  • This is absolutely beautiful! It has actually been adapted to an Overleaf guide, for anyone that wants to easily play around with it. I also modified the \myexternaldocument command to add tags, and defined a \newcommand{\myexternalref}[1]{\ref{mytag:#1}} for each of the externals to simplify referencing with tags. Commented Feb 22, 2023 at 10:20
  • Is there a way to add a prefix to the original labels? For example, I would like Theorem 2.2 from file1.tex to be cited as Theorem I.2.2 in file2.tex. The xr package admits options to \externaldocument: \externaldocument[I.]{file1}. Can this be adapted to overleaf? Commented Aug 2, 2023 at 20:22
0

Unless there is an internal link between the two or multiple files I doubt latexmk would recognize this. So the 2 cases are:

  1. Internal link between multiple files: For example if file1.tex had this phrase, latexmk will recognize the need to recompile if there are changes in file2 or file3 etc

    %file1.tex

    \begin{document}
    
    \input{file2.tex}
    \input{file3.tex}
    
    \end{document}
    

    %end of file1.tex

  2. Make file: But then if you use a for loop in a make file or a normal unix script file which says something like this:

    for /r %%x in (*.tex) do pdflatex "%%x"
    

    then there is a meagre change LaTeX would recognize it but then its just a for loop instead of individual lines of latexmk execution.

I hope this was of some help. Looking forward to see if anyone else had a solution for you.

You must log in to answer this question.

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