In order to have a footer at each page that displays the current page number with the total number of pages (Eg.,4 of 12), I used lastpage package and placed the statement:

\rfoot{\thepage\ of \pageref{LastPage}}

just before the \begin{document} statement.

When I run lualatex doc-1.tex, I get the following warnings at the end.

LaTeX Warning: Reference `LastPage' on page 11 undefined on input line 209.


Package lastpage Warning: Rerun to get the references right on input line 210.

AED: lastpage setting LastPage

LaTeX Warning: Reference `LastPage' on page 12 undefined on input line 210.

[12] (/Users/amanda/ltx/s/build/store/upload/doc-1.aux)

LaTeX Warning: There were undefined references.

LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.

This results in footer that looks something similar to:

4 of ??

and the generated document does not have the \tableofcontents. Re-running it resolves the issue.

Is there a way, I could avoid this in the first place? I do not want to rerun the command to get it right the second time (since there would be many different documents all being generated at the same time).

If it is helpful, I have shared the lualatex code that I run to generate the document.


local function json_parser()
        local lpeg = assert(require("lpeg"))
        local C, Cf, Cg, Ct, P, R, S, V =
            lpeg.C, lpeg.Cf, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.R, lpeg.S, lpeg.V

        -- number parsing
        local digit    = R"09"
        local dot      = P"."
        local eE       = S"eE"
        local sign     = S"+-"^-1
        local mantissa = digit^1 * dot * digit^0 + dot * digit^1 + digit^1
        local exponent = (eE * sign * digit^1)^-1
        local real     = sign * mantissa * exponent / tonumber

        -- optional whitespace
        local ws = S" \t\n\r"^0

        -- match a literal string surrounded by whitespace
        local lit = function(str)
            return ws * P(str) * ws

        -- match a literal string and synthesize an attribute
        local attr = function(str,attr)
            return ws * P(str) / function() return attr end * ws

        -- JSON grammar
        local json = P{

            value =
                V"null_value" +
                V"bool_value" +
                V"string_value" +
                V"real_value" +
                V"array" +

            null_value =
                attr("null", nil),

            bool_value =
                attr("true", true) + attr("false", false),

            string_value =
                ws * P'"' * C((P'\\"' + 1 - P'"')^0) * P'"' * ws,

            real_value =
                ws * real * ws,

            array =
                lit"[" * Ct((V"value" * lit","^-1)^0) * lit"]",

            member_pair =
                Cg(V"string_value" * lit":" * V"value") * lit","^-1,

            object =
                lit"{" * Cf(Ct"" * V"member_pair"^0, rawset) * lit"}"

        return { parse = function(str) return assert(json:match(str)) end }

local socket = require("socket")
local json = json_parser()
local file = io.open("sample-true.json")
local start = socket.gettime()
tab = json.parse(file:read("*all"))
texio.write_nl("Time passed parsing JSON: " .. socket.gettime() - start .. " s\\string\n")

local function isempty(s)
return s == nil or s == ''

function renderSections(tab)
    for i,k in ipairs(tab['tableOfContents']) do
        local sec_start = socket.gettime()
        tex.print ("\string\\chapter{" .. k.section.title .. "}")
        tex.print("section text here")
        for ii,kk in ipairs(k["subsection"]) do
            tex.print ("\string\\section{" .. kk.title .. "}")
            tex.print ("some text here")
            for iii, kkk in ipairs(kk["content"]) do
                if kkk['type'] == "text" then
                    if not isempty(kkk["line"]) then
                elseif kkk["type"] == "table" then
                    local column_count = 0
                    local row_count = 0
                    col_schema = ""
                    for _ in ipairs(kkk["columns"]) do 
                        column_count = column_count + 1 
                        col_schema = col_schema .. " |X"
                    col_schema = col_schema .. "|"
                    for _ in ipairs(kkk["columns"][1]["values"]) do row_count = row_count + 1 end
                    if not isempty(kkk.title) then
                        tex.print("\string\\textbf{" .. kkk.title .."}")
                    tex.print("\string\\begin{tabularx}{\\linewidth}{"  .. col_schema ..  "}")
                    for ci, c in ipairs(kkk["columns"]) do
                        local c_name = string.gsub(c.name, "&","\\&")
                        if ci < column_count then
                            tex.print(" & ")
                    i = 1
                    while i <= row_count do
                        local c_c = 1
                        while c_c <= column_count do
                            local row_val = kkk["columns"][c_c]["values"][i]
                            row_val = string.gsub(row_val, "&", "\\&")
                            if c_c < column_count then
                                tex.print(" & ")
                            c_c = c_c + 1
                        i = i + 1
        texio.write_nl("Time passed rendering section: " .. socket.gettime() - sec_start .. " s\string\n")

\usepackage[landscape, margin=1in]{geometry}
    pdftitle={MAC Report},
% https://en.wikibooks.org/wiki/LaTeX/Colors

\rfoot{\thepage\ of \pageref{LastPage}}
\renewcommand*\contentsname{TABLE OF CONTENTS}


\paragraph{Document Information}

\subparagraph{Document information is given in the table below}

\begin{tabular}{|c| c| c|}
\textbf{S.No} & \textbf{Item} & \textbf{Information} \\
1 & Document ID & \directlua{tex.print(tab['documentId'])} \\
2 & Document Generated At & \directlua{tex.print(tab['documentGeneratedAt'])} \\
3 & Document Generated By & \directlua{tex.print(tab['documentGeneratedBy'])} \\
4 & MAC Protocol ID & \directlua{tex.print(tab['macProtocolID'])} \\
%\textcolor{NavyBlue}{TABLE OF CONTENTS}


Initial part of the document is static. Most part of the document is generated from renderSections function. I have also shared the json file named sample-true.json, in case you would want to reproduce it.

  • If you know in advance what ends up on which page, you can just generate an aux file, but I doubt that this is practical. – Henri Menke May 9 '19 at 10:32
  • 3
    Then it is not possible unless you invent time travel. – Henri Menke May 9 '19 at 10:43
  • 8
    The way that all references work, including LastPage and the table of contents, is that on every run through the document the data is written to the aux file. The aux file is read whenever the document is processed so on subsequent runs the data stored in the aux file is read in and can be used anywhere in the document. It is possible to write code that does not use the aux file but it will only be able to add "dynamic" content later in the document. For something like the number of the last page this is of no value because there are no pages after the last page. – Andrew May 9 '19 at 11:18
  • 4
    If you know how many pages there are you can say, before the \begin{document}, something like this: \newlabel{LastPage}{{}{123}{}{}{}}, then the number of pages will be known. The effect would be the same as running the document twice, however. Even MS Word requires you to write all the text before it can tell you how many pages are there. – Phelype Oleinik May 9 '19 at 11:40
  • 1
    If anything the second compilation will take a fraction more time as pages such as the table of contents or indexes are not and cannot be put together on the first run through. I am not aware of any way to reduce the compilation time. As far as LaTeX is concerned there is no difference between the first and subsequent compilations, except that there is more data in the aux, toc, ind, ... files – Andrew May 11 '19 at 13:09

Your Answer

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

Browse other questions tagged or ask your own question.