Conflito entre listagens e hiperref: "lstnumber.-14.11" referenciado, mas não existe

Conflito entre listagens e hiperref: "lstnumber.-14.11" referenciado, mas não existe

Estou vendo as seguintes mensagens de erro do pdflatex em um projeto realmente gigantesco:

(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

A parte superior do meu arquivo principal fica assim:

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

Um exemplo do \codeblockcorpo do texto:

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

E um exemplo de \codeblockref:

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

Infelizmente, se você juntar apenas esses trechos em um arquivo de teste e executá pdflatex test.tex; pdflatex test.tex-lo, tudo funcionará bem! (Exceto que o hiperlink no número "1" na verdade vai para o índice, não para a página 1.) Mas quando faço a mesma coisa na escala de muitos capítulos, recebo as mensagens de erro vistas lstnumber.-14.11no topo do essa questão.

Eu descobri que esse lstnumber.-<some number>é o formato dos rótulos gerados automaticamente pelo listingspacote, então presumo que seja uma interação ruim entre listingse hyperref. Mas o que exatamente está errado e o que posso fazer para consertar?


O que \hspace{1em}está na minha \codeblockmacro foi minha tentativa ingênua de contornar o bug descritoaqui, caso esse fosse o problema.

Responder1

Aqui está o exemplo de como isso deve ser feito, na minha opinião:

No \codeblockcomando \labelé aplicado antes da \lstinputlistingmacro ser usada, ou seja, antes do listingscontador ter sido aumentado para permitir a referência com \refstepcounter-- usar \labelantes \refstepcounteré um erro muito comum e como tal, a informação de referência cruzada escrita por \labelé usada a partir de um potencial \refstepcounterusado antes , que pode estar em conjunto com um sectioncontador etc., portanto, as informações estão erradas e as coordenadas da hiperâncora são obtidas de uma instância de âncora mais antiga. Dessa forma, os links apontam para uma posição errada.

Na verdade, \lstinputlistingtem a label=opção de especificar o nome do rótulo.

O seguinte é um formulário muito reduzido fornecido por quem não é MWE, mas funciona.

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

Responder2

No processo de postar esta pergunta, me deparei com a resposta! (Não que eu entendapor quefunciona...)

se você juntar apenas esses trechos em um arquivo de teste e executar pdflatex test.tex; pdflatex test.tex- funciona bem! (Exceto que o hiperlink no número "1" na verdade vai para o índice, não para a página 1.)

Quando houve erros, não fiquei surpreso que o hiperref tenha ido para o lugar errado. Com o caso de teste reduzido, porém, fiquei intrigado. Então fui ler sobrequeproblema, e descobri que o que eu queria era \phantomsectionassim:

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

Observe que meu culto à carga \hspace{1em}não é mais necessário (AFAIK); e consegui colocar de volta os caracteres especiais que lst:#1-#2substituí foo#1#2ao tentar reduzir o caso de teste.

...E num passe de mágica, de repente meu projeto gigantesco compila perfeitamente! Não há mais mensagens de erro misteriosas. Todos os links de hiperref vão para as páginas corretas e mostram o corpo do texto correto.

Não tenho ideia de por que a omissão \phantomsectioncausou tanto estrago, mas depois de colocá-lo, está tudo consertado!

informação relacionada