2

I'm seeing the following error messages from pdflatex on a really gigantic project:

(see the transcript file for additional information)pdfTeX warning (dest): name
{lstnumber.-14.11} has been referenced but does not exist, replaced by a fixed 
one

pdfTeX warning (dest): name{lstnumber.-18.22} has been referenced but does not 
exist, replaced by a fixed one

pdfTeX warning (dest): name{lstnumber.-9.40} has been referenced but does not e
xist, replaced by a fixed one

pdfTeX warning (dest): name{lstnumber.-4.3} has been referenced but does not ex
ist, replaced by a fixed one

The top of my main file looks like this:

\documentclass[ebook,10pt,oneside,final]{memoir}
\usepackage{microtype}

% support for code listings
\usepackage[final]{listings}
\include{autodedent}
\lstset{
  basicstyle=\ttfamily\footnotesize,
  numberstyle=\footnotesize,
  breaklines=true,
  numbers=left,
  firstnumber=1,
  rangeprefix=//,
  includerangemarker=false
}

% support for indexing
\usepackage{makeidx}
\makeindex

% make _ a non-special character
\usepackage{underscore}

% support for cross-references
\usepackage{hyperref}
% \newcommand{\href}[2]{#2}

% fix spacing in \tableofcontents
\renewcommand\partnumberline[1]{#1\hspace{1em}}

% custom commands for use in the text of the book itself
\newcommand{\newterm}[1]{\textit{#1}}
\newcommand{\code}[1]{\mbox{\lstinline[basicstyle=\ttfamily]$#1$}}
\newcommand{\slurl}[1]{\href{https://#1}{\textsl{#1}}}
\newcommand{\codeblock}[2]{\label{foo#1#2}\hspace{1em}\lstinputlisting[linerange=ex#2-dex#2,autodedent]{examples-ch#1.cc}}
\newcommand{\codeblockref}[2]{\pageref{foo#1#2}}
\newcommand{\Csharp}{C\#}

\begin{document}

\frontmatter
\include{preface}
\tableofcontents

\mainmatter

% ...and so on...

An example of \codeblock from the body of the text:

Let's write a function to multiply each of the elements
in an array by 2.

\codeblock{1}{1}

Our function \code{double_each_element} works \emph{only} with objects of type
\code{array_of_int}...

And an example of \codeblockref:

Compare this version of the code to the version on page
\codeblockref{1}{1}.

Unfortunately, if you throw just these snippets together in a test file and run pdflatex test.tex; pdflatex test.tex — it works fine! (Except that the hyperlink on the number "1" actually goes to the table of contents, not to page 1.) But when I do the same thing at the scale of many chapters, I get the error messages about lstnumber.-14.11 seen at the top of this question.

I did find out that lstnumber.-<some number> is the format of the labels that are auto-generated by the listings package, so I assume this is some bad interaction between listings and hyperref. But what exactly is going wrong and what can I do to fix it?


The \hspace{1em} in my \codeblock macro was my naïve attempt to work around the bug described here, in case that was the problem.

egreg
  • 1,121,712

2 Answers2

4

Here's the example how it should be done, in my opinion:

In \codeblock the \label command is applied before the \lstinputlisting macro is used, i.e. before the listings counter has been increased to allow for referencing with \refstepcounter -- using \label before \refstepcounter is a very common error and as such, the cross-reference information written by \label is used from a potential \refstepcounter used before, which could be in conjunction with a section etc. counter, so the information is wrong and the hyper anchor coordinates are taken from an older anchor instance before. This way, the links point back to a wrong position.

In fact, \lstinputlisting has a label= option to specify the label name.

The following is a very reduced form given by the non-MWE but works.

\documentclass[ebook,10pt,oneside,final]{memoir}
\usepackage{microtype}

% support for code listings

\begin{filecontents}{examplehelloworld.c}
#include<stdio.h>

int main(int argc,char **argv)
{
  printf("Hello World!\n");
  return(0);
}
\end{filecontents}

\usepackage[final]{listings}
%\include{autodedent}
\lstset{
  basicstyle=\ttfamily\footnotesize,
  numberstyle=\footnotesize,
  breaklines=true,
  numbers=left,
  firstnumber=1,
  rangeprefix=//,
  includerangemarker=false
}

% support for indexing
\usepackage{makeidx}
\makeindex

% make _ a non-special character
\usepackage{underscore}

% support for cross-references
\usepackage{hyperref}
% \newcommand{\href}[2]{#2}

% fix spacing in \tableofcontents
\renewcommand\partnumberline[1]{#1\hspace{1em}}

% custom commands for use in the text of the book itself
\newcommand{\newterm}[1]{\textit{#1}}
\newcommand{\code}[1]{\mbox{\lstinline[basicstyle=\ttfamily]$#1$}}
\newcommand{\slurl}[1]{\href{https://#1}{\textsl{#1}}}
\newcommand{\codeblock}[2]{\hspace{1em}\lstinputlisting[language={C},label={lst:#1-#2}]{examplehelloworld.c}}
\newcommand{\codeblockref}[2]{\pageref{lst:#1-#2}}
\newcommand{\Csharp}{C\#}


\usepackage{blindtext}

\begin{document}

\frontmatter
%\include{preface}
\tableofcontents

\mainmatter


\blindtext[3]


Reference: \codeblockref{1}{4}

\blindtext[5]


\codeblock{1}{4}



\end{document}
  • "as such, the cross-reference information written by \label is used from a potential \refstepcounter used before" ... "the hyper anchor coordinates are taken from an older anchor instance before. This way, the links point back to a wrong position" — sorry, I can't parse either of these phrases. In your example, is the only difference that you moved the \label into the label={lst:#1-#2} parameter to \lstinputlisting, or is there something else happening in there also? – Quuxplusone Apr 19 '17 at 05:26
  • @Quuxplusone: Yes, what happens what I described before: \lstinputlisting uses \refstepcounter automatically and then applies the label. Your approach with \phantomsection is an unnecessary by-pass, because \phantomsection introduces phantom anchors that are grabbed by \label (actually by hyperref in the background) –  Apr 19 '17 at 05:28
0

In the process of posting this question, I stumbled across the answer! (Not that I understand why it works...)

if you throw just these snippets together in a test file and run pdflatex test.tex; pdflatex test.tex — it works fine! (Except that the hyperlink on the number "1" actually goes to the table of contents, not to page 1.)

When it was throwing errors, I wasn't surprised that the hyperref went to the wrong place. With the reduced test case, though, I was puzzled. So I went reading about that problem, and found that what I wanted was \phantomsection, like this:

\newcommand{\codeblock}[2]{\phantomsection\label{lst:#1-#2}\lstinputlisting[linerange=ex#2-dex#2,autodedent]{examples-ch#1.cc}}
\newcommand{\codeblockref}[2]{\pageref{lst:#1-#2}}

Notice that my cargo-cult \hspace{1em} is no longer needed (AFAIK); and I was able to put back the special characters in lst:#1-#2 that I'd replaced with foo#1#2 when trying to reduce the test case.

...And by magic, suddenly my gigantic project compiles fine! No mysterious error messages anymore. All the hyperref links go to the right pages, and show the right body text.

I have no idea why omitting \phantomsection caused such havoc, but after putting it in, everything's fixed!