3

Backround

So I've gathered that latexmk runs pdflatex until "all files are up to date".

Problem and motivation

Say that I have some dynamic content that should only be run once. By dynamic I mean a content that changes every time you run it.

In principle: assume you could have a command \randomNumber which change every time it is run, giving you a random number, and thus causes latexmk to run forever.

A real world example would be compiling Rnw-files that have randomness in them.

\immediate\write18{compileMyKnitr}\input{myRnw.tex}

Question

Is there

  1. A latex command that will tell me how many runs latexmk have done

and/or

  1. Some fancy logic that can be done with e.g. the .aux file to determine whether this is the first run or not?

Ideally \ifFirstRun{\doSomething} or \LatexmkRunOnce{\doSomething}

2 Answers2

4

Here is a solution. Deleting the .aux means restart the counter, (even if no counter is used here).

1)

\documentclass{article}

\providecommand\runsnumber{1}
\makeatletter
\AtEndDocument{%
    \write\@auxout{%
        \xdef\string\runsnumber{\the\numexpr\runsnumber+1\relax}}}
\makeatother
\begin{document}
foo

\runsnumber
\end{document}

2)

\documentclass{article}

\makeatletter
\AtEndDocument{\write\@auxout{\gdef\string\notfirstrun{}}}
\newcommand{\iffirstrun}{%
    \@ifundefined{notfirstrun}}
\makeatother
\begin{document}
foo
\iffirstrun{yes}{no}
\end{document} 
John Collins
  • 11,183
  • 3
  • 32
  • 33
touhami
  • 19,520
4

There are two parts to a solution.

First is to make a .tex file that detects whether it's being compiled on the first run or not:

\documentclass{article}

\makeatletter
\AtEndDocument{\write\@auxout{\gdef\string\notfirstrun{}}}
\newcommand{\iffirstrun}{%
    \@ifundefined{notfirstrun}}
\makeatother
\begin{document}
foo
\iffirstrun{yes}{no}
\end{document} 

(Note that the syntax for the use of \iffirstrun is different from that for standard \iff... constructs. That could be fixed, of course.)

This solution puts a line \gdef\notfirstrun{} in the .aux file, to flag that the next run is not the first.

However, with only that part of the solution, when latexmk is again invoked after a change in source file(s), the first actual run will not be treated as a first run by the document. This is normally not desired. One could avoid this by deleting the .aux file, which may result in a lot of extra processing (and is easy to forget). This problem is solved by the following code in a latexmkrc file:

$latex = 'internal my_latex latex %O %S';
$lualatex = 'internal my_latex lualatex %O %S';
$pdflatex = 'internal my_latex pdflatex %O %S';
$xelatex = 'internal my_latex xelatex -no-pdf %O %S';
sub my_latex {
   if ( ( -e $aux_main ) && ($pass{$rule} == 1) ) {
      print "========Remove any 'notfirstline' line from aux file\n";
      my $aux_bak = "$aux_main.bak";
      rename $aux_main, $aux_bak;
      my $auxold = new FileHandle;
      my $auxnew = new FileHandle;
      open $auxold, "<$aux_bak";
      open $auxnew, ">$aux_main";
      while (<$auxold>) {
         if ( ! /^\\gdef \\notfirstrun\{\}$/ ) { print $auxnew $_; }
      }
      close $auxold;
      close $auxnew;
  }
  return system( @_ );
}

It uses a couple of internal variables of latexmk: $aux_main and $pass{$rule}.

John Collins
  • 11,183
  • 3
  • 32
  • 33