我尝试改善 pdflatex 编译我的书所需的时间。
真正有效的例子
书籍
%&preamble
\begin{document}
Hi
\end{document}
和
序言.tex
\documentclass{article}
我在 bash 控制台上运行以下命令:
$ pdflatex -ini -jobname="preamble" "&pdflatex preamble.tex\dump"
$ latexmk -pdf -pvc -e '$latex=q/latex %O -shell-escape %S/' book.tex
打开一个窗口,其中显示(几乎)实时预览,每次文件更改后都会更新book.tex
。更改后,PDF 查看器evince
会自动重新加载.pdf
。
未决问题
我没有成功编写我的书的序言在preamble.tex
文件中。
- 我怎样才能找到我能预编译?
- 我可以预编译
\newcommand
's,\usepackage
's 吗? - 我可以预编译一个没有标题的纯章节吗?
其他加速方法
(我不明白如何结合这些想法才能获得最佳效果)
pdflatex
知道-draftmode
我测量了编译速度快 20%time pdflatex -draftmode 50pagetest.tex
答案1
“预编译”可能是一个有点令人困惑的短语,因为 TeX 不是一个编译器,而(主要是)是一种宏扩展语言,但无论如何......
一般来说,你可以将大多数宏定义和寄存器分配转储到格式中。但你不能将页面发送出去。因此,实际上你可以转储大多数 LaTeX 序言。
而不必编辑文件以便仅有的与预加载的前导格式一起工作,可以将前导保留为正常状态,但定义转储格式以跳过先前在转储中执行的命令。
我mylatex
在 ctan 上的真正古老的文件可以做到这一点,或者有一个更新的版本,具有附加功能并且维护得更好:mylatex格式
您需要注意的主要事项(我怀疑您已经忽略了)是,如果您转储使用任何命令\jobname
(例如打开辅助文件),那么您必须确保转储格式时的作业名称与生成文档时的作业名称相同。此外,如果宏假设在处理文档时序言中的命令打开的文件仍处于打开状态,那么当您使用预加载格式时,您需要重新打开它们,加载格式文件将根据其内部内存重新设置 TeX 的内部状态,但不会将文件句柄重新分配给文件系统。
在此站点上搜索时得到的第一个结果mylatex
显示了在 tikz externalize 上下文中讨论此问题的示例。
上述内容是我在 2012 年写的,如果现在写,我会强调另外两类不能倾倒的东西。
- OpenType 字体(因此会影响任何加载系统字体的 xelatex 或 lualatex 前言),以及
- Lua 状态,因此如果与 luatex 一起使用,则会影响使用的任何包
\directlua
。对于任何特定的 Lua 代码,您通常可以使用\dump
宏定义来执行代码,\everyjob
或者\AtBeginDocument
然而,这通常需要对包代码进行大量重新排列,因此mylatex
在使用 lualatex 时,通常无法使用未更改的 latex 文档。
答案2
为了让使用搜索引擎来到这里寻找如何将永远不变但加载缓慢的序言转换为超快的“预编译”格式的人们受益。
这此处的说明引导您完成一个简单的过程,如下所示。您需要mylatexformat
包来使这个工作。
将你的序言分成“静态”和“可能改变”的内容,先讲静态的内容。
在静态内容的末尾添加命令
\endofdump
从命令行/终端运行以下命令,替换两种情况
foo
与您的文档名称一起:pdftex -ini -jobname="foo" "&pdflatex" mylatexformat.ltx foo.tex
将代码插入到文件
%&foo
顶部.tex
,并替换foo
为文件的名称。
你的编译现在将会发生很多快点。
注意:如果您有任何“可能改变”的前言,您需要保留该\endofdump
命令,否则编译将从\begin{document}
跳过所有前言开始。
答案3
在这个答案中,我将解释“预编译前言”如何工作,如何在 PDFLaTeX/XeLaTeX/LuaLaTeX 中使用它,以及一些陷阱。
通常只需按照说明操作即可。但是,如果出现问题,了解内部情况有助于您诊断问题。
如何使用mylatexformat
?[基本说明]
假设你有一个普通的 LaTeX 文档a.tex
:
\documentclass{article}
\usepackage{amsmath}
\begin{document}
\begin{align*}
1+2 &= 3
\end{align*}
\end{document}
假设a.tex
不包含空格或特殊字符,例如%#{}~
。
首先执行pdftex -ini -jobname=a "&pdflatex" mylatexformat.ltx a.tex
。这将生成a.fmt
。(输出.fmt
文件名由 指定-jobname
,如果未指定则默认为mylatexformat.fmt
,尽管如此,使用-jobname
相同的文件名不太可能导致错误)
然后执行pdftex "&a" a.tex
。这将a.pdf
照常生成。
mylatexformat
阅读软件包文档时的备注
-ini
和-initialize
(如文档中所示mylatexformat
)是同一件事。但是-initialize
在 TeXLive 中不起作用,因此使用-ini
更安全。"""abc.tex"""
其在命令行上 书写的说明仅适用于 Windows,在 Linux/Bash 上你需要"\"abc.tex\""
。(基本上传递包裹在一层双引号转换为 TeX)&a
a.fmt
指定应使用文件中的格式。- 如果 的第一行
a.tex
是%&a
,则第二条命令不需要"&a"
在命令行上明确指定,任何诸如pdftex a.tex
或 之类的命令pdflatex a.tex
都可以。然而此方法不适用于 LuaTeX。
如何使用mylatexformat
?[高级说明]
使用 XeLaTeX/LuaLaTeX 代替 PDFLaTeX
分别替换pdftex
为xetex
或luahbtex
。此外,您还需要将预加载的格式名称替换&pdflatex
为&xelatex
或&lualatex
。
您可以通过查看它在开头打印的内容来判断xelatex
和lualatex
可执行文件只是xetex
和预加载luahbtex
了xelatex.fmt
和格式。lualatex.fmt
还请注意,第一行%&a
(如包文档中所写)在 LuaTeX 中不起作用。
例如:
% a.tex
\documentclass{article}
\usepackage{amsmath}
\csname endofdump\endcsname
\usepackage{unicode-math} % incompatible with precompiled preamble, see below
\begin{document}
\begin{align*}
1+2 &= 3
\end{align*}
\end{document}
然后在 shell 中:
luahbtex -ini -jobname=a "&lualatex" mylatexformat.ltx a.tex
luahbtex "&a" a.tex
这只会加快一点点,根据我的经验,对于一个几乎为空的文档来说,速度是 0.6 秒 → 0.4 秒。
不要预编译整个序言
如果序言的某些部分:
- 经常更改(所以你不想将其纳入格式),或者
- 依赖于
\jobname
(例如\usepackage{currfile}
,或pythontex
), 或者 - 与 TeX 格式不兼容,例如
\usepackage{unicode-math}
或\usepackage{fontspec}
,(请参阅“另外两类无法转储的内容。”大卫·卡莱尔的回答)- 由于某种原因,LuaLaTeX 甚至
tikz
不兼容。 - 我没有看到任何简单的方法可以轻松分辨哪些包兼容以及哪些包不兼容,您只需尝试包含/排除它。
- 由于某种原因,LuaLaTeX 甚至
那么你必须将其从序言中排除。
要做到这一点,请使用\csname endofdump\endcsname
(拼写必须完全一样)——mylatexformat
有关更多详细信息,请参阅文档。如果未使用 /precompiled 前言(即文件以正常方式编译),则使用此方法代替\endofdump
可确保文件可编译(该行将被忽略)mylatexformat
。
什么是预编译前言/格式?
基本上,它只是使用 TeX 的 INITeX 功能来加速固定前导部分的处理。
TeX 支持生成格式稍后可以加载。有关详细信息,请参阅 TeX by Topic 第 33 章“TeX 和外部世界”。
(阅读 TeXbook 可能会有点混乱,只要记住在命令行上输入任何内容都相当于在**
在 TeX 提示符的第一行输入它。)
简而言之:
格式文件(通常以 .fmt 为扩展名)是 TEX 内部结构的紧凑转储。加载格式文件所需的时间比加载字体信息和构成格式的宏所需的时间要短得多。
因此,您可以“定义一些命令,将内部状态转储到文件中”,然后当您“加载”该文件时,就好像命令的定义与转储格式时的方式类似。
例如:
% preamble.tex
\documentclass{article}
\usepackage{amsmath}
\dump
% a.tex
\begin{document}
\begin{align*}
1+2 &= 3
\end{align*}
\end{document}
在 shell 中执行pdftex -ini "&pdflatex" preamble.tex
,这将
- 从现有
pdflatex.fmt
格式开始(可能/var/lib/texmf/web2c/pdftex/pdflatex.fmt
取决于操作系统等) - 从文件执行
preamble.tex
\dump
执行时会生成文件preamble.fmt
。
需要-ini
启用\dump
命令。
此后,如果pdftex "&preamble" a.tex
执行(这意味着“a.tex
以预加载的格式执行preamble.fmt
”),它将生成a.pdf
正确的内容。(对于类似物,pdftex "&pdflatex" a.tex
相当于pdflatex a.tex
)
什么是mylatexformat
包裹
如上所示,将文件拆分成单独的文件非常不方便preamble.tex
。因此mylatexformat
您可以将它们放在同一个文件中,它会自动检测前言和主文件之间的拆分。
如何mylatexformat
工作(关于命令行)?
有两个步骤——生成格式和使用格式。
第一步,除了-jobname
,命令行是:
pdftex -ini "&pdflatex" mylatexformat.ltx a.tex
由于历史原因,命令行中输入的任何内容(几乎)都等同于将其输入到**
提示符的第一行。因此,您也可以运行,pdftex -ini
然后在**
提示符下输入&pdflatex mylatexformat.ltx a.tex
,两者都是等效的。
大部分内容都很熟悉。回想一下,它将pdftex -ini "&pdflatex" mylatexformat.ltx
以预加载的格式启动pdflatex.fmt
并执行文件的内容mylatexformat.ltx
。但是,附加内容a.tex
将是放入输入流。
在 的最后mylatexformat.ltx
,重新定义\begin
等之后,有
%% Trick lookahead to allow mylatex.ltx and the document filename to be
%% given on the same command line. (initex &latex mylatex.ltx {abc.tex})
\expandafter\input\endinput%
\endinput
非常有效(需要一些 TeX 编程知识) \input a.tex
执行wipet 的回答。
这就是为什么在命令行中传递另一对引号很有用。
要了解实施的其他细节(如何将序言与文档分开),请阅读文档。
通过解压格式文件来进一步提高速度
參閱https://tex.stackexchange.com/a/708544/250119。
每次编译可以节省 0.1 到 0.2 秒。