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}

5
  • a smilar question was answered here. a) you can use the aux file to save and restore number of runs b) i think your 2 nd point is good in this situation.
    – touhami
    Commented Mar 24, 2018 at 15:53
  • 2
    You can use \IfFileExists{\jobname.aux}{yes}{no} in the preamble as the aux file is generated on the first run, at \begin{document} so by definition it's not there on teh first run in the preamble Commented Mar 24, 2018 at 16:53
  • 1
    @DavidCarlisle no (yes-no) in preamble :-)
    – touhami
    Commented Mar 24, 2018 at 17:46
  • Was actually considering writing Missing \begin{document}, but refrained, haha. Commented Mar 24, 2018 at 17:50
  • @touhami it was a meta comment yes== yes code :-) Commented Mar 24, 2018 at 17:55

2 Answers 2

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}.

1
  • very nice work :-)
    – touhami
    Commented Mar 26, 2018 at 17:11
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} 
14
  • Awesome! I will just take your word for it that it works, since I don't have the files here to test it. One question though: Why \providecommand? Commented Mar 24, 2018 at 17:14
  • 1
    \providecommand defines the command only in first run since it is not defined yet. see here
    – touhami
    Commented Mar 24, 2018 at 17:42
  • 1
    One complication: Suppose you have already compiled the document so that the .aux file exists, you change a source file, and then compile the document again by latexmk. Because of the line in the .aux file defining \notfirstrun, the first compilation will be treated as a not-first run by the document. To overcome this, one can delete the .aux file first, as the answer points out. But it would also be possible to arrange for latexmk to fix the .aux file on the first run. I could provide suitable definition to put in a latexmkrc file. Commented Mar 25, 2018 at 18:19
  • 1
    @AndreasStorvikStrauman this is just to see the new comment
    – touhami
    Commented Mar 25, 2018 at 21:44
  • 1
    @AndreasStorvikStrauman I've added a suitable definition. Commented Mar 26, 2018 at 15:14

You must log in to answer this question.

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