为什么 \renewcommand{\bibcite}[2]{...} 会导致 LaTeX 警告:标签可能已更改。请重新运行以获取正确的交叉引用?

为什么 \renewcommand{\bibcite}[2]{...} 会导致 LaTeX 警告:标签可能已更改。请重新运行以获取正确的交叉引用?

这就是问题的答案LaTeX 警告:标签可能已更改。重新运行以获取正确的交叉引用 Why I am getting undefined references?,然而这个答案又带来另一个问题。

文件中abntex2cite有这样几行看似无害的内容:

%we are repeating \bibcite command as defined in hyperref.sty
%so that we have it all together at one place.
\ifthenelse{\boolean{ABNThyperref}}{% not comment this, but the next two, to fix the warning
\renewcommand{\bibcite}[2]{%
 \@newl@bel{b}{#1}{\hyper@@link[cite]{}{cite.#1}{#2}}}%
  1. https://github.com/abntex/abntex2/blob/master/tex/latex/abntex2/abntex2cite.sty#L547-L548

经过几个小时对该包进行注释abntex2cite并根据一个简单示例进行测试后:

% How to make \PassOptionsToPackage add the option as the last option?
% https://tex.stackexchange.com/questions/385895/how-to-make-passoptionstopackage-add
\PassOptionsToPackage{brazil,main=english}{babel}

\documentclass[10pt,openright,twoside,a5paper]{abntex2}
\usepackage{filecontents}
\usepackage[alf]{abntex2cite}

% Package hyperref Warning: Token not allowed in a PDF string?
% https://tex.stackexchange.com/questions/384885/package-hyperref-warning-token-not
\pdfstringdefDisableCommands{\let\uppercase\relax}

\begin{document}

% How does 'filecontents' keep LaTeX parsing while temporarily stop writing output
% https://tex.stackexchange.com/questions/104159/how-does-filecontents-keep-latex-parsing
\begin{filecontents*}{refs2.bib}
@manual{abntex2classe,
  Author = {abnTeX2 and Lauro C{\'e}sar Araujo},
  Date-Added = {2013-01-09 10:37:38 +0000},
  Date-Modified = {2013-04-05 11:03:48 +0000},
  Organization = {Equipe abnTeX2},
  Title = {A classe abntex2},
  Url = {http://abntex2.googlecode.com/},
  Year = {2013},
  Bdsk-Url-1 = {http://code.google.com/p/abntex2/}}
\end{filecontents*}

The \cite{abntex2classe}.
\bibliography{refs2}
\end{document}

我发现每次我编译乳胶文件时,这些行都会导致出现这个警告:

Basic Builder: running pdflatex...done.
running pdflatex...done.

No errors. Warnings:

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

No bad boxes.

因此,如果我在文件中注释这些行abntex2cite.sty,我的简单乳胶文件就会在编译时没有任何警告:

Basic Builder: running pdflatex...done.
running bibtex...done.
running pdflatex...done.
running pdflatex...done.

No errors. No warnings. No bad boxes.

这些行是做什么的?有没有办法修复它们,以便LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right每次编译简单文件时它们都不会引起警告?

%we are repeating \bibcite command as defined in hyperref.sty
%so that we have it all together at one place.
\ifthenelse{\boolean{ABNThyperref}}{% not comment this, but the next two, to fix the warning
\renewcommand{\bibcite}[2]{%
 \@newl@bel{b}{#1}{\hyper@@link[cite]{}{cite.#1}{#2}}}%

答案1

abntex2cite.sty包括以下内容(其中包括您引用的行):

%we are repeating \bibcite command as defined in hyperref.sty
%so that we have it all together at one place.
\ifthenelse{\boolean{ABNThyperref}}{%
\renewcommand{\bibcite}[2]{%
 \@newl@bel{b}{#1}{\hyper@@link[cite]{}{cite.#1}{#2}}}%

这意味着作者复制了hyperref.sty他们编写此代码时碰巧拥有的任何版本的定义。这确实是一个非常糟糕的想法,因为软件包代码并不是一成不变的。软件包会得到错误修复、更新以与其他地方的新代码兼容、更新以包含新功能等。

在这种情况下,hyperref.sty现在说

\ltx@IfUndefined{NAT@parse}{%
  \providecommand*\@extra@binfo{}%
  \providecommand*\@extra@b@citeb{}%
  \def\bibcite#1#2{%
    \@newl@bel{b}{#1\@extra@binfo}{%
      \hyper@@link[cite]{}{cite.#1\@extra@b@citeb}{#2}%
    }%
  }%
\gdef\@extra@binfo{}%
  \let\Hy@bibcite\bibcite
  \begingroup
    \@ifundefined{bbl@cite@choice}{}{%
      \g@addto@macro\bbl@cite@choice{%
        \let\bibcite\Hy@bibcite
      }%
    }%
  \endgroup
  \providecommand*{\@BIBLABEL}{\@biblabel}%
  \def\@lbibitem[#1]#2{%
    ...

我不清楚这是否等同于 中的代码abntex2cite.sty,但根据您的经验,我猜不是。(即使现在等同,三个月或三年后可能就不是了。)

相关内容