0

If I run lualatex on a .tex file I only get ?? as a result from 'lastpage' in my document. Then if I run lualatex a second time, the correct result (2) is shown in the document footer.

Main Question: How can I avoid having to run latex twice on the same document(.tex file)?

It would be nice if there is a solution for that because I'm dynamically generating latex files from Java and every console lualatex doc.tex call is taking roundabout 2.5 seconds.

Used sources: lualatex on console and test.tex -> mwe
Console command: lualatex test.tex
Failure output:
LaTeX Warning: Reference `LastPage' on page 1 undefined on input line 23 Package lastpage Warning: Rerun to get the references right on input line 23
MWE:

\documentclass[8pt,a4paper]{extarticle}
\usepackage[T1]{fontenc}
\usepackage{graphicx}
\usepackage{lastpage}
\usepackage[left=1.5cm, right=1.5cm, top=0.0cm, bottom=0.0cm, headheight=42pt, includeheadfoot]{geometry}
\usepackage{fancyhdr}
\usepackage{lipsum}

\fancypagestyle{style1}{
    \fancyhf{}
    \fancyhead[L]{}
    \fancyhead[R]{}
    \fancyfoot[L]{\scriptsize Test}
    \fancyfoot[R]{\scriptsize Seite \textbf{\thepage} von \textbf{\pageref{LastPage}}}
    \setlength{\topmargin}{-70pt}
    \setlength{\headsep}{10pt}
    \setlength{\footskip}{20pt}
}

\begin{document}
    \pagestyle{style1}
    \lipsum[1-15]
\end{document}  
  • 4
    you can't avoid it. the document must have been compiled once to get the page number. – Ulrike Fischer Aug 13 at 14:54
  • Side remark: don't use \usepackage[T1]{fontenc} with luatex. – Ulrike Fischer Aug 13 at 16:04
  • 1
    To add to what @UlrikeFischer says, if anything else is added to the document after the first run (like a bibliography) that changes the number of pages, a third run may be needed to get the correct last page number. – barbara beeton Aug 13 at 17:16
  • 1
    Unfortunately this is one of the unusual things about LaTeX that cannot be changed. You might be able to speed up a single run a little bit by preloading the class and packages, see for example tex.stackexchange.com/questions/186833/… or tex.stackexchange.com/questions/42414/…. – Marijn Aug 13 at 17:39
2

Normally TeX can't use data like the number of pages on the first pages because LaTeX can't know yet how many pages there will be. But there is a trick: You can insert a reference to a PDF XObject on every page where the number of pages should be. A XObject is a separate object in a PDF file which can be referenced out of order. Then you can fill this XObject later with the number of pages.

Another complication is that LuaTeX forces you to decide the content of XObject before you can use it, but you can trick it by manipulating the PDF structures on a lower level:

\documentclass[8pt,a4paper]{extarticle}
\usepackage[T1]{fontenc}
\usepackage{graphicx}
\usepackage[left=1.5cm, right=1.5cm, top=0.0cm, bottom=0.0cm, headheight=42pt, includeheadfoot]{geometry}
\usepackage{fancyhdr}
\usepackage{lipsum}

\directlua{
  local n = pdf.reserveobj()% `n` will be a PDF object storing
                            % a reference to the XObject created later.
  local list = token.scan_list() % First we read a list to get the dimensions.
  node.flush_list(list.head) % The actual content isn't important
  local whatsit = node.new('whatsit', 'pdf_literal') % Now "call" the XObject /Form "manually"
  whatsit.mode = 1
  whatsit.data = "/Form Do"
  list.head = whatsit
  % Create a XObject managed by LuaTeX which only references our manual reference
  pages_xform = tex.saveboxresource(list, nil, '/XObject ' .. n .. ' 0 R')
  final_form_hack = n % And save the identifiers
}\hbox{\scriptsize\textbf{29}}% This \hbox decides how much space to reserve for the page number. 29 makes sure that all numbers up to 99 should be fine
\fancypagestyle{style1}{
    \fancyhf{}
    \fancyhead[L]{}
    \fancyhead[R]{}
    \fancyfoot[L]{\scriptsize Test}
    % Reference the XObject from TeX
    \fancyfoot[R]{\scriptsize Seite \textbf{\thepage} von \directlua{node.write((tex.useboxresource(pages_xform)))}}
    \setlength{\topmargin}{-70pt}
    \setlength{\headsep}{10pt}
    \setlength{\footskip}{20pt}
}

\AtEndDocument{
  \clearpage
  \directlua{
    % Now we know how many pages there are, so we can fill the XObject.
    local n = final_form_hack
    final_form_hack = nil
    local list = token.scan_list() % Scan the list with the number of pages
    local w, h, d, m = tex.getboxresourcedimensions(pages_xform)
    list.height, list.depth, list.width = h, d, w % Make sure our boxes have consistant sizes (otherwise LuaTeX will be confused)
    local xform = tex.saveboxresource(list, nil, nil, true, m)% And save it in a XObject
    pdf.immediateobj(n, "<</Form " .. xform .. " 0 R>>")% Finally store a reference in the object `n` created above
  }\hbox{%
    \scriptsize\textbf{\the\numexpr\value{page}-1\relax}% The actual number of pages
  }
}

\begin{document}
    \pagestyle{style1}
    \lipsum[1-30]
\end{document}  

Of course, this only affects the number of pages. If you have other references in your file (e.g. \label/\ref or just a table of content), similar problems will appear again.

  • Can a generic ref/label structure be pulled off based on this? Would save milltions of CPU hours worldwide... – Oleg Lobachev Aug 13 at 17:48
  • @OlegLobachev By design this requires that the dimensions are known from the beginning (If your footer leaves a little spaces because it would have expected a second digit you normally wouldn't notice, if every reference leaves blank space in case the number is bigger you will notice), all the fonts/sizes/etc have to be the same (no problem here because it is only used at one spot, can be hard otherwise) and these objects do not participate in linebreaking (OK for numbers, for \nameref you really don't want this). There are lot's of similar issues, so it's not suited for a generic system. – Marcel Krüger Aug 13 at 17:57
  • 1
    Also lots of documents are compiled multiple times anyway (e.g. during editing for previews, because you want to optimize breaks, etc.), so I don't think it would actually save that much. Probably it would be easier to get all people to use tools which automatically detect if another run is necessary instead of just running n times "just to make sure". Especially I once saw someone use a editor which deleted all aux files after every change and therefore always had to compile at least 3 times... – Marcel Krüger Aug 13 at 18:05
  • There is a \clearpage missing in the \AtEndDocument. Without it one will run into problems if floats are involved. It is a nice trick, but as you said: its use is rather restricted and as soon as some more references are involved one has to recompiled anyway. – Ulrike Fischer Aug 14 at 8:20
  • @UlrikeFischer Thanks – Marcel Krüger Aug 14 at 16:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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