我有一个带有详尽文档的模板。(参见模板文档.pdf)。几个月前它就编译过了。现在有了更新的软件包,它就不能再编译了,因为著名的没有空间容纳新的 \write 问题。
之前,所有东西都已经调整好了,所有写入都已使用。我不得不禁用包才能进行编译(从而放弃功能)。现在我可以测试禁用例如 pgf/tikz 是否可以解决原始问题。但我宁愿不在我的模板中放弃 pgf/tikz...请注意,我不使用 tikz 的外部包。
因此,基本问题是如何找出哪些包实际在使用 \write。有些包肯定引入了文件输出或消耗了比以前更多的资源。
filecontents
第一次使用该包时代码失败。
目前还没有针对此问题的最小示例,而且创建起来非常困难,主要是因为代码基础太庞大。
我使用这段代码来减少写入问题,但它并没有真正解决任何问题
\usepackage{morewrites}
% see https://texfaq.org/FAQ-noroom
\usepackage{etex}
\reserveinserts{28}
我知道使用 \write 并且我加载的软件包是
- tikz/pgf
- 伊玛克
- 词汇表
- 列表
- 标题目录
完整的软件包列表可以在我的文档(参见链接)第 240 页中找到。
答案1
没有最小工作示例(MWE)这只是猜测,但如果您的文档在环境中定义了首字母缩略词或词汇表条目document
,并且您升级到 4.0 版本,则需要额外写入。原因如下:
3.07¹ 及以下版本将name
、description
和symbol
字段写入外部词汇表文件(除了 字段sort
)。这存在多个问题:
这些字段中的脆弱命令需要保护,否则在将命令写入文件时会发生错误。为了克服这个问题,
glossaries
有一个sanitize
包选项,它基本上将这些字段的内容转换为字母列表,因此例如,如果您\cite
在description
字段中有,它将从宏转换为五个字符\
c
i
t
和e
。现在可以安全地将其写入词汇表文件,但如果您尝试description
在文档的其他地方显示,您实际上会在 PDF 中得到“\cite”(或者,更常见的是“—cite”,因为默认的衬线字体将字符显示\
为长破折号)。任何出现的
makeindex
或xindy
特殊字符都需要转义。这是通过 完成的,但是、和字段glossaries
越长,执行此操作所需的时间就越长,因此会减慢文档构建速度。name
description
symbol
makeindex
缓冲区有限,长描述可能会超出此范围。可能需要自定义词汇表样式来显示其他字段,但如果尚未定义条目,则无法访问这些字段。
为了解决这些问题,版本 4.0 改变了将条目信息写入词汇表文件的方式。现在只有字段sort
和\glossentry{
标签}
写入文件。然后由词汇表样式定义,\glossentry
以便它使用诸如 之类的命令访问相关信息\glsentrydesc
。这意味着不再担心使用脆弱命令,因为它们不会写入文件。(默认情况下,该值会自动清理,并且标签无论如何都不能包含脆弱命令。)由于索引信息现在位于较短的字符串中,因此对/字符sort
进行任何转义的速度要快得多(以防它们出现在字段或条目标签中)。并且无需担心超出 的缓冲区(除非您的排序值或标签过长)。xindy
makeindex
sort
makeindex
但是,这种方法有一个缺点:显示词汇表时必须定义所有条目,以便\glossentry
访问相关字段。如果词汇表显示在文档末尾,这不是问题,但用户通常喜欢在前言中列出首字母缩略词或符号。为了解决这个问题,并确保向后兼容性,在环境开始时glossaries
修改了定义,以便将词汇表信息写入临时文件,然后在下次运行 LaTeX 时将其输入到文档的开头。\newglossaryentry
document
\jobname.glsdefs
这可确保在显示词汇表时条目信息可用,但存在额外写入的缺点,可能会出现扩展问题,并且对定义的任何更改直到下次运行才会生效。密钥see
也不起作用,因为它没有保存在字段中(它只是在定义条目时触发交叉引用),因此不会写入文件.glsdefs
。这也意味着使用定义的术语\newacronym
将转换为常规条目定义,这可能会给缩写机制带来问题。
也可以看看在文档环境中定义条目的缺点在glossaries
用户手册中。
MWE1:
\documentclass{article}
\usepackage{glossaries}
\makeglossaries
\newglossaryentry{sample}{name={sample},description={an example}}
\begin{document}
\gls{sample}.
\printglossaries
\end{document}
这里glossaries
定义了两次写入:一次是针对.ist
文件的写入,一次是针对.glo
文件的写入。
MWE2:
\documentclass{article}
\usepackage[acronym]{glossaries}
\makeglossaries
\newglossaryentry{sample}{name={sample},description={an example}}
\newacronym{xyz}{XYZ}{long form}
\begin{document}
\gls{sample}. \gls{xyz}.
\printglossaries
\end{document}
这里glossaries
定义了三次写入:一次针对.ist
文件,一次针对glo
文件,一次针对.acn
文件。
MWE3:
\documentclass{article}
\usepackage[acronym]{glossaries}
\makeglossaries
\begin{document}
\newglossaryentry{sample}{name={sample},description={an example}}
\newacronym{xyz}{XYZ}{long form}
\gls{sample}. \gls{xyz}.
\printglossaries
\end{document}
这里glossaries
定义了四次写入:一次针对.ist
文件,一次针对.glo
文件,一次针对.acn
文件,一次针对.glsdefs
文件。
MWE4:
\documentclass{article}
\usepackage[acronym,index,symbols,numbers]{glossaries}
\makeglossaries
\begin{document}
\newacronym{xyz}{XYZ}{long form}
\gls{xyz}.
\printglossaries
\end{document}
这里glossaries
定义了七种写入:.ist
,.glo
,.acn
,.idx
(来自index
选项),.nlo
(来自numbers
选项),.slo
(来自symbols
选项)和.glsdefs
(因为\newacronym
在环境中document
)。
这glossaries-extra
docdef=restricted
软件包提供了允许文档定义但不创建文件的选项.glsdefs
。这意味着必须在显示词汇表之前定义术语,但这意味着\write
不需要额外的操作。
MWE5:
\documentclass{article}
\usepackage[acronym,docdef=restricted]{glossaries-extra}
\makeglossaries
\setabbreviationstyle[acronym]{long-short}
\begin{document}
\newglossaryentry{sample}{name={sample},description={an example}}
\newacronym{xyz}{XYZ}{long form}
\gls{sample}. \gls{xyz}.
\printglossaries
\end{document}
现在有三次写入:一次针对.ist
文件,一次针对.glo
文件,一次针对.acn
文件。
如何最大限度地减少\write
新
\newglossaryentry
将(以及\newacronym
使用)的所有实例移动到前导码或通过或\newglossaryentry
加载到前导码中的文件中(\input
\loadglsentries
不要使用\include
)。确保您没有定义不打算使用的词汇表。例如:
\documentclass{article} \usepackage[acronym]{glossaries} \makeglossaries \newacronym{xyz}{XYZ}{long form} \begin{document} \gls{xyz}. \printglossaries \end{document}
这里
glossaries
定义了三个新的写入:一个用于文件.ist
,一个用于文件.glo
,一个用于文件.acn
,但其中一个(.glo
)未被使用。这很浪费,因此使用包选项\write
抑制词汇表:main
nomain
\usepackage[nomain,acronym]{glossaries}
如果您不需要对该
.ist
文件进行任何进一步的修改,请允许glossaries
在第一次构建时生成它:\documentclass{article} \usepackage[nomain,acronym]{glossaries} \makeglossaries \newacronym{xyz}{XYZ}{long form} \begin{document} \gls{xyz}. \printglossaries \end{document}
\noist
然后通过添加到您的文档来抑制它的创建:\documentclass{article} \usepackage[nomain,acronym]{glossaries} \noist \makeglossaries \newacronym{xyz}{XYZ}{long form} \begin{document} \gls{xyz}. \printglossaries \end{document}
现在
glossaries
仅为该文件定义一个新的写入.acn
。使用
savewrites
包选项。这只对.ist
和所有.glo
等.acn
文件(但不对 文件.glsdefs
)使用一次写入。使用此选项将glossaries
所有词汇表信息存储在标记中,直到文档结束,然后遍历每个词汇表并重复使用相同的写入寄存器写入每个词汇表文件。这会减慢文档构建速度,但前提是您在序言中定义所有条目,glossaries
仅定义一个写入寄存器。此方法易受 TeX 异步输出程序的影响,并可能导致位置不正确。
此选项会减慢构建速度,因为每当您引用条目(使用
\gls
或等命令\glsadd
)时,信息都会附加到令牌寄存器中。在文档末尾,然后遍历每个定义的词汇表并将相关令牌寄存器的内容写入外部词汇表文件。这比每次使用或glossaries
等命令时简单地写入一行要花费更长的时间。所需时间取决于您引用每个条目的次数。\gls
\glsadd
从glossaries
4.04 版本开始,还有另一个不创建任何新文件的选项,因为排序和索引是由 TeX 完成的,而不是使用外部索引应用程序:
\documentclass{article}
\usepackage[acronym]{glossaries}
\makenoidxglossaries
\newglossaryentry{sample}{name={sample},description={an example}}
\newacronym{xyz}{XYZ}{long form}
\begin{document}
\gls{xyz}. \gls{sample}.
\printnoidxglossaries
\end{document}
这只会创建标准.log
和.aux
文件(以及.pdf
/.dvi
文件)。在这种情况下,\newglossaryentry
和\newacronym
被设为仅前导命令,因此没有.glsdefs
文件。但是,这种方法效率很低,难以处理分层条目,并且只能根据基本拉丁语集进行排序。因此,除非万不得已,否则不建议使用这种方法。
该glossaries-extra
包提供了另外两种不使用任何\write
寄存器的方法:
只需使用\printunsrtglossary
(或\printunsrtglossaries
) 即可显示词汇表。这只会遍历所有已定义的条目(因此需要先定义它们)。没有排序,也没有位置列表。
\documentclass{article}
\usepackage{glossaries-extra}
\newglossaryentry{zoo}{name={zoo},description={sample description}}
\newglossaryentry{aardvark}{name={aardvark},description={sample description}}
\begin{document}
\gls{aardvark}.
\printunsrtglossaries
\end{document}
这里没有\write
创建寄存器,但是词汇表是按照定义的顺序排列的,并且包含两个条目,尽管在文档中只使用了一个条目。
另一个选择是glossaries-extra
使用bib2gls
。这涉及对上述内容的轻微修改。条目现在在文件中定义.bib
。例如entries.bib
:
@entry{zoo,name={zoo},description={sample description}}
@entry{aardvark,name={aardvark},description={sample description}}
文档文件现在需要record
选项并\GlsXtrLoadResources
指定.bib
文件:
\documentclass{article}
\usepackage[record]{glossaries-extra}
\GlsXtrLoadResources[src=entries]% terms defined in entries.bib
\begin{document}
\gls{aardvark}.
\printunsrtglossaries
\end{document}
这没有定义任何\write
寄存器(所有信息都写入文件.aux
),但现在词汇表中只出现索引条目(aardvark),词汇表已排序,条目有位置列表。(尽管在这种情况下只有一个条目。)
文档构建过程(假设文档文件名为myDoc.tex
)是:
pdflatex myDoc
bib2gls myDoc
pdflatex myDoc
(根据需要,pdflatex
用etc 替换。)如果您想要字母组,您将需要(或)开关:xelatex
--group
-g
bib2gls --group myDoc
makeindex
这与/方法的工作方式不同xindy
。bib2gls
从文件中读取所需信息.aux
,并创建一个包含输入的条目定义的文件\GlsXtrLoadResources
。在写入条目定义之前,首先对条目进行排序,并且只包含文档中索引的条目。这意味着可以使用 简单地显示词汇表\printunsrtglossaries
,如上例所示。bib2gls
创建一个转录文件(.glg
)和.glstex
每个资源命令一个文件(\GlsXtrLoadResources
),但\write
不需要为任何词汇表文件分配寄存器。
有各种方法的比较表在glossaries
用户手册中。
相比之下bib2gls
,一些示例文档, 包括sample-multi2.tex
其中包含 14 个词汇表和 1 个索引。main
词汇表使用 隐藏nomain
,索引词汇表使用包选项创建index
,其余词汇表使用 创建\newglossary*
:
\usepackage[record,% use bib2gls
section,% use \section* for glossary headings
postdot,% insert dot after descriptions in glossaries
nomain,% don't create 'main' glossary
index,% create 'index' glossary
nostyles,% don't load default styles
% load and patch required style packages:
stylemods={list,mcols,tree,bookindex}
]{glossaries-extra}
\newglossary*{bacteria}{Bacteria}
\newglossary*{markuplanguage}{Markup Languages}
\newglossary*{vegetable}{Vegetables}
\newglossary*{mineral}{Minerals}
\newglossary*{animal}{Animals}
\newglossary*{chemical}{Chemical Formula}
\newglossary*{baseunit}{SI Units}
\newglossary*{measurement}{Measurements}
\newglossary*{film}{Films}
\newglossary*{book}{Books}
\newglossary*{person}{People}
\newglossary*{mediacontrol}{Media Control Symbols}
\newglossary*{information}{Information Symbols}
\newglossary*{weather}{Weather Symbols}
文档加载hyperref
,这意味着除了标准写入寄存器之外,还会为文件创建\@outlinefile
一个写入寄存器(),该寄存器由 LaTeX 内核定义。(如果添加了目录,这将为文件创建一个额外的写入寄存器。)hyperref
.out
\@mainaux
\@partaux
.toc
如果将文档改为使用makeindex
/ xindy
,则将需要 1 个用于样式文件的写入寄存器和每个词汇表(包括索引)各一个写入寄存器 = 1 + 15 = 16。加上内核定义的 2 个寄存器和hyperref
PDF 书签的寄存器,这意味着该文档将需要19写入寄存器(.glsdefs
如果将任何词汇表定义移动到document
环境中,则创建文件,则为 20)。
仅使用bib2gls
内核定义的 2 个寄存器和hyperref
的.out
寄存器,总共创建了3写入寄存器,这可以节省大量成本。
就相关临时文件而言,有标准.aux
和.log
文件以及hyperref
文件.out
。makeindex
/xindy
还包含样式文件和每个词汇表(输入、输出和转录)的三个文件,总共 2(.aux
和.log
)+ 1(.out
)+ 1(.ist
/ .xdy
)+ 3 × 15 = 49。
对于bib2gls
,每个 都有一个转录.glg
文件和 1 个.glstex
文件\GlsXtrLoadResources
。资源命令的数量与词汇表的数量无关。一个资源命令可能处理多个词汇表(如果它们具有相同的设置),或者一个词汇表可能需要多个资源命令(如果它被分成独立排序的块)。在sample-multi2.tex
有 9 个资源命令,因此关联的临时文件总数 = 2(.aux
和.log
)+ 1(.out
)+ 1(.glg
)+ 9(.glstex
)= 13。(结果sample-multi2.pdf
也可在 CTAN 上使用。)
因此,使用bib2gls
不仅可以消除与词汇表相关的写入寄存器的需要,而且还可以减少临时文件的总数。
¹ 3.07 到 4.0 之间的版本是实验性的,未上传到 CTAN。
答案2
morewrites
该包的问题在于定义 使用和绕过机制的filecontents
方式。filecontents
\newwrite
\ch@ck7\reserved@c\write
morewrites
这里,是我使用的破解版本,可以绕过这个问题。Bruno 或 Scott Pakin 需要在软件包级别修复它。