
Eu realmente preciso de ajuda - tenho usado LaTeX casualmente há vários anos, mas raramente tive que me aprofundar em detalhes ou problemas, e não consigo descobrir isso.
Problema
Estou trabalhando com um .cls
arquivo fornecido pela minha organização que possui uma linha (possivelmente) problemática. Ele define uma macro que armazena o segundo dígito do tamanho do ponto inserido e, em seguida, usa isso para inserir um .clo
arquivo. Um MWE emparelhado é o seguinte:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mwe}
\RequirePackage{etoolbox}
\newrobustcmd\@ptsize{}
\DeclareOption{10pt}{\renewrobustcmd\@ptsize{0}}
\DeclareOption{11pt}{\renewrobustcmd\@ptsize{1}}
\DeclareOption{12pt}{\renewrobustcmd\@ptsize{2}}
\ExecuteOptions{11pt}
\ProcessOptions
\input{size1\@ptsize.clo}
Também criei um .tex
arquivo MWE para compilar:
\documentclass[11pt]{mwe}
\begin{document}
\end{document}
No entanto, quando compilo isso usando latexmk -synctex=1 -interaction=nonstopmode -file-line-error -pdf -outdir=%OUTDIR% %DOC%
(dentro do VSCode usando LaTeX Workshop), recebo este arquivo de log com uma mensagem dizendo
`File `[email protected]' not found`
O registro diz:
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (MiKTeX 20.11) (preloaded format=pdflatex 2020.11.3) 3 NOV 2020 08:57
entering extended mode
**"path/to/mwe/mwe.tex"
("path/to/mwe/mwe.tex"
LaTeX2e <2020-10-01> patch level 2
L3 programming layer <2020-10-27> xparse <2020-03-03> ("path/to\mwe\mwe.cls" <-- In case it matters, these slashes
Document Class: mwe really do switch directions
(path\to\tex/latex/etoolbox\etoolbox.sty <-- Here as well
Package: etoolbox 2020/10/05 v2.5k e-TeX tools for LaTeX (JAW)
\etb@tempcnta=\count175
)
! LaTeX Error: File `[email protected]' not found.
Type X to quit or <RETURN> to proceed,
or enter new name. (Default extension: clo)
Enter file name:
Solução potencial
O problema é o seguinte: se eu alterar o .cls
arquivo para que @ptsize
seja definido via \newcommand
e \renewcommand
em vez de via \newrobustcmd
e \renewrobustcmd
, o arquivo MWE acima .tex
funcionará perfeitamente, gerando um PDF em branco (duas páginas).
Alguém poderia a) explicar por que isso está acontecendo (até onde eu sei, esse .cls
arquivo funciona bem para outras pessoas na minha organização) eb) qual seria a abordagem de práticas recomendadas para esse problema? Agradeço antecipadamente!
Responder1
A diferença de comportamento pode ser vista neste código de exemplo:
\makeatletter
\protected\def\@ptsize{1}
\input{size1\@ptsize.clo}
\stop
que costumava inserir size11.clo
, mas desde o lançamento do LaTeX 2020-10-01 isso não acontece mais, em vez disso, apresenta erros com:
! LaTeX Error: File `[email protected]' not found.
Type X to quit or <RETURN> to proceed,
or enter new name. (Default extension: clo)
Enter file name:
Esta foi uma mudança deliberada no mecanismo de análise de nomes de arquivos do LaTeX. Ele foi substituído por um analisador mais robusto que não expande macros protegidas (junto com vários outros benefícios). O comportamento do novo analisador é o correto em relação a macros robustas: estasnão podefuncionam em contextos somente de expansão porque eles irão quebrar de uma forma ou de outra (você pode encontrar toneladas de exemplos de que em volta), portanto, não expandi-los é a coisa razoável a fazer.
O arquivo de classe em sua organização faz mau uso de comandos robustos para armazenar alguns dados (o que normalmente chamamos de “lista de tokens”). Dados como esse geralmente sempre precisam estar disponíveis para outras macros, por isso precisam ser expandidos e, portanto, não podem ser robustos/protegidos. A coisa certa a fazer, se você puder editar o arquivo de classe, é substituir \(re)newrobustcmd
por \(re)newcommand
:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mwe}
\RequirePackage{etoolbox}
\newcommand\@ptsize{}
\DeclareOption{10pt}{\renewcommand\@ptsize{0}}
\DeclareOption{11pt}{\renewcommand\@ptsize{1}}
\DeclareOption{12pt}{\renewcommand\@ptsize{2}}
\ExecuteOptions{11pt}
\ProcessOptions
\input{size1\@ptsize.clo}
Para que conste, a mensagem de erro
! LaTeX Error: File `[email protected]' not found.
fica assim porque o analisador de nome de arquivo funciona com \escapechar=-1
, então \@ptsize
é atingido \string
e se torna @ptsize
.
Responder2
Se por algum motivo obscuro for insistido em armazenar dados que devem ser recuperáveis em macros robustas, então você mesmo pode acionar a expansão e colocar os tokens na ordem correta, usando alguns \expandafter
// \romannumeral
truques de troca de argumentos:
arquivo mwe.cls
:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mwe}
\RequirePackage{etoolbox}
\newrobustcmd\@ptsize{}
\DeclareOption{10pt}{\renewrobustcmd\@ptsize{0}}
\DeclareOption{11pt}{\renewrobustcmd\@ptsize{1}}
\DeclareOption{12pt}{\renewrobustcmd\@ptsize{2}}
\newcommand\exchangeargs[2]{#2#1}
\ExecuteOptions{11pt}
\ProcessOptions
% It is not relied on \input expanding and putting into correct order
% tokens of its argument.
% Instead \romannumeral-expansion brings all tokens into
% correct order before \input and \input's filename-parsing
% come into action.
% (This way things might sustain more changes to \input's
% filename-parsing.)
\expandafter\input\expandafter{%
\romannumeral
\expandafter\exchangeargs\expandafter{\@ptsize}{\z@ size1}.clo%
}
No meu sistema compilando um arquivo test.tex
:
\documentclass{mwe}
\stop
produz esta saída de console:
$ pdflatex test.tex
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2020-10-01> patch level 2
L3 programming layer <2020-10-27> xparse <2020-03-03> (./mwe.cls
Document Class: mwe
(/usr/local/texlive/2020/texmf-dist/tex/latex/etoolbox/etoolbox.sty)
(/usr/local/texlive/2020/texmf-dist/tex/latex/base/size11.clo)) )
No pages of output.
Transcript written on test.log.
e este arquivo test.log
:
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex 2020.11.23) 4 DEC 2020 19:47
entering extended mode
restricted \write18 enabled.
%&-line parsing enabled.
**test.tex
(./test.tex
LaTeX2e <2020-10-01> patch level 2
L3 programming layer <2020-10-27> xparse <2020-03-03> (./mwe.cls
Document Class: mwe
(/usr/local/texlive/2020/texmf-dist/tex/latex/etoolbox/etoolbox.sty
Package: etoolbox 2020/10/05 v2.5k e-TeX tools for LaTeX (JAW)
\etb@tempcnta=\count175
)
(/usr/local/texlive/2020/texmf-dist/tex/latex/base/size11.clo
File: size11.clo 2020/04/10 v1.4m Standard LaTeX file (size option)
)) )
Here is how much of TeX's memory you used:
364 strings out of 479485
4393 string characters out of 5871962
273140 words of memory out of 5000000
17462 multiletter control sequences out of 15000+600000
535388 words of font info for 30 fonts, out of 8000000 for 9000
1141 hyphenation exceptions out of 8191
52i,1n,59p,208b,36s stack positions out of 5000i,500n,10000p,200000b,80000s
No pages of output.
PDF statistics:
0 PDF objects out of 1000 (max. 8388607)
0 named destinations out of 1000 (max. 500000)
1 words of extra memory for PDF output out of 10000 (max. 10000000)
Para suas perguntas:
a) explicar por que isso está acontecendo (até onde eu sei, esse arquivo .cls funciona bem para outras pessoas na minha organização)
Mudanças significativas foram introduzidas no kernel 2ε do LaTeX. Uma das mudanças mais recentes é que dentro do argumento da \input{...}
robustez as macros não são expandidas.
Essas mudanças são boas e irritantes ao mesmo tempo: são boas porque, com muitas coisas, a maneira como funcionam agora me parece mais rigorosa. Eles são irritantes porque tenho que olhar o código novamente e me acostumar. ;-)
Provavelmente as outras pessoas em sua organização não usam uma das versões mais recentes do kernel LaTeX 2ε e, portanto, as alterações introduzidas nas versões mais recentes do kernel LaTeX 2ε não afetam a maneira como as coisas funcionam em suas máquinas .
b) qual seria a abordagem de melhores práticas para este problema?
Não sei se essas são "melhores práticas", mas como houve tantas mudanças nos últimos dois anos, parei de depender das macros LaTeX 2ε-kernel para funcionar da maneira que estava acostumado há mais de duas décadas. ;-)
Especialmente, não confio mais no código mantido por outras pessoas que fazem a expansão da mesma maneira que fazia há dois dias e, portanto, muitas vezes tenho meu próprio código para fazer todo o trabalho de expansão antes que as coisas sejam entregues como argumentos para as macros de outras pessoas.
Não faço isso porque ficaria insatisfeito com as mudanças e inovações.
Faço isso para tornar meu próprio código compatível com o maior número possível de versões diferentes do LaTeX 2ε.