调试 没有空间容纳新的 \write 问题

调试 没有空间容纳新的 \write 问题

我有一个带有详尽文档的模板。(参见模板文档.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¹ 及以下版本将namedescriptionsymbol字段写入外部词汇表文件(除了 字段sort)。这存在多个问题:

  1. 这些字段中的脆弱命令需要保护,否则在将命令写入文件时会发生错误。为了克服这个问题,glossaries有一个sanitize包选项,它基本上将这些字段的内容转换为字母列表,因此例如,如果您\citedescription字段中有,它将从宏转换为五个字符\ c i te。现在可以安全地将其写入词汇表文件,但如果您尝试description在文档的其他地方显示,您实际上会在 PDF 中得到“\cite”(或者,更常见的是“—cite”,因为默认的衬线字体将字符显示\为长破折号)。

  2. 任何出现的makeindexxindy特殊字符都需要转义。这是通过 完成的,但是、和字段glossaries越长,执行此操作所需的时间就越长,因此会减慢文档构建速度。namedescriptionsymbol

  3. makeindex缓冲区有限,长描述可能会超出此范围。

  4. 可能需要自定义词汇表样式来显示其他字段,但如果尚未定义条目,则无法访问这些字段。

为了解决这些问题,版本 4.0 改变了将条目信息写入词汇表文件的方式。现在只有字段sort\glossentry{标签}写入文件。然后由词汇表样式定义,\glossentry以便它使用诸如 之类的命令访问相关信息\glsentrydesc。这意味着不再担心使用脆弱命令,因为它们不会写入文件。(默认情况下,该值会自动清理,并且标签无论如何都不能包含脆弱命令。)由于索引信息现在位于较短的字符串中,因此对/字符sort进行任何转义的速度要快得多(以防它们出现在字段或条目标签中)。并且无需担心超出 的缓冲区(除非您的排序值或标签过长)。xindymakeindexsortmakeindex

但是,这种方法有一个缺点:显示词汇表时必须定义所有条目,以便\glossentry访问相关字段。如果词汇表显示在文档末尾,这不是问题,但用户通常喜欢在前言中列出首字母缩略词或符号。为了解决这个问题,并确保向后兼容性,在环境开始时glossaries修改了定义,以便将词汇表信息写入临时文件,然后在下次运行 LaTeX 时将其输入到文档的开头。\newglossaryentrydocument\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-extradocdef=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

  1. \newglossaryentry将(以及\newacronym使用)的所有实例移动到前导码或通过或\newglossaryentry加载到前导码中的文件中(\input\loadglsentries不要使用\include)。
  2. 确保您没有定义不打算使用的词汇表。例如:

    \documentclass{article}
    
    \usepackage[acronym]{glossaries}
    
    \makeglossaries
    
    \newacronym{xyz}{XYZ}{long form}
    
    \begin{document}
    
    \gls{xyz}.
    
    \printglossaries
    
    \end{document}
    

    这里glossaries定义了三个新的写入:一个用于文件.ist,一个用于文件.glo,一个用于文件.acn,但其中一个(.glo)未被使用。这很浪费,因此使用包选项\write抑制词汇表:mainnomain

    \usepackage[nomain,acronym]{glossaries}
    
  3. 如果您不需要对该.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

  4. 使用savewrites包选项。这只对.ist和所有.glo.acn文件(但不对 文件.glsdefs)使用一次写入。使用此选项将glossaries所有词汇表信息存储在标记中,直到文档结束,然后遍历每个词汇表并重复使用相同的写入寄存器写入每个词汇表文件。这会减慢文档构建速度,但前提是您在序言中定义所有条目,glossaries仅定义一个写入寄存器。

    此方法易受 TeX 异步输出程序的影响,并可能导致位置不正确。

    此选项会减慢构建速度,因为每当您引用条目(使用\gls或等命令\glsadd)时,信息都会附加到令牌寄存器中。在文档末尾,然后遍历每个定义的词汇表并将相关令牌寄存器的内容写入外部词汇表文件。这比每次使用或glossaries等命令时简单地写入一行要花费更长的时间。所需时间取决于您引用每个条目的次数。\gls\glsadd

glossaries4.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这与/方法的工作方式不同xindybib2gls从文件中读取所需信息.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 个寄存器和hyperrefPDF 书签的寄存器,这意味着该文档将需要19写入寄存器(.glsdefs如果将任何词汇表定义移动到document环境中,则创建文件,则为 20)。

仅使用bib2gls内核定义的 2 个寄存器和hyperref.out寄存器,总共创建了3写入寄存器,这可以节省大量成本。

就相关临时文件而言,有标准.aux.log文件以及hyperref文件.outmakeindex/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\writemorewrites

这里,是我使用的破解版本,可以绕过这个问题。Bruno 或 Scott Pakin 需要在软件包级别修复它。

相关内容