问题描述
我正在尝试latexmk
使用.latexmkrc
配置文件来设置“预编译”我的文档的序言,并在重新运行期间重复使用它。
根据大卫·卡莱尔的评论,使用预编译并没有真正节省足够的时间,不值得这么麻烦,他mylatex.ltx
在 1988 年写道。
但是,我的文档中有很多外部化的图形,并且 pgfplots 里面有很多引用,所以在我的情况下加载时间增长得非常快,我想探索预编译可以加快多少整个过程。
要求
我当前的要求是:
- 序言和正文必须能够位于同一个文档内,对于这个问题,就让它这样吧
mwe.tex
。 - 所有编译都必须通过一次调用来完成
latexmk
。
文献综述
我特别研究了以下问题和答案:
https://tex.stackexchange.com/a/37730有点过时了,但一般原则可以应用于较新版本的 LaTeX。这个建议的解决方案的主要问题是,如上所述,您需要
pdflatex -ini ...
第一次手动运行来创建.fmt
文件,这与我的第二个要求相矛盾。https://tex.stackexchange.com/a/269052显示了如何从一个文件中转储前导码,该文件是
pdflatex -ini \&pdflatex mylatex.ltx mwe.tex
尤其是对于要求 1 而言,这很有帮助。
经过自己的研究,我发现一个系统调用
pdflatex -ini \&pdflatex mylatexformat.ltx mwe.tex
将是实现这一目标的最新方法。
我的自定义最小非工作示例
利用以前的信息和缺点,考虑到我的要求,我打算按照以下步骤解决这个问题:
- 修改
$pdflatex
中的变量.latexmkrc
以要求预编译的前言mwe.fmt
文件。 - 用于
add_cus_dep('tex', 'fmt', 1, 'precompilepreamble');
添加依赖项。 - 如有必要,定义 perl 子例程
precompilepreamble
来创建文件。mwe.fmt
我期望程序按照以下方式运行:
- 调用
latexmk
,加载我的自定义.latexmkrc
配置。 - 第一次运行
pdflatex
失败,并将记录缺少的所需文件mwe.fmt
。 latexmk
决定需要额外运行,并将查找依赖项.fmt
。- 因此,
latexmk
将运行我之前添加的自定义规则来生成mwe.fmt
。 - 之后,
latexmk
将再次运行我的修改版本$pdflatex
并成功继续。
附件中有您需要的文件:
mwe.tex
\documentclass{scrbook}
\usepackage{pgfplots}
\usepackage{amsmath}
\usepackage{siunitx}
\usepackage{lipsum}
\begin{document}
\title{Shakespeare's Externalize}
\subtitle{To externalize or not to externalize?}
\subject{Case Studies}
\date{\today}
\maketitle{}
\lipsum[1-20]
\end{document}
.latexmkrc
# ensure_path( 'TEXINPUTS', './src/' );
# ensure_path( 'TEXINPUTS', '../src/' );
# Set the program used to generate the PDF
# 1: pdflatex
# 2: postscript conversion, don't use this
# 3: dvi conversion, don't use this
# 4: lualatex
# 5: xelatex
$pdf_mode = 1;
# Add custom dependency.
# latexmk checks whether a file with ending as given in the 2nd
# argument exists ('toextension'). If yes, check if file with
# ending as in first argument ('fromextension') exists. If yes,
# run subroutine as given in fourth argument.
# Third argument is whether file MUST exist. If 0, no action taken.
add_cus_dep('tex', 'fmt', 1, "compilepreamble");
# show custom dependencies for debugging
show_cus_dep();
# parse missing files
push @file_not_found, '^I can\'t find the format file `(.*)\'\!';
sub compilepreamble {
my ( $base) = @_;
# just output a simple debug string to console
print ("**** compilepreamble: ( $base ) ****\n");
# create the fmt file
$ret = system("pdflatex",
"-jobname", "$base",
"-ini",
"&pdflatex" ,
"mylatexformat.ltx",
$base
);
# if there were errors, return the error codes
return $ret;
}
# modify $pdflatex to use custom format
$pdflatex = 'pdflatex -fmt mwe %B %O %S';
观察到的行为
它不会失败,而是pdflatex
尝试运行mktexfmt
:
$ latexmk -g
Custom dependency list:
tex fmt 1 compilepreamble
Rc files read:
.latexmkrc
Latexmk: This is Latexmk, John Collins, 7 Jan. 2023. Version 4.79.
Force everything to be remade.
Latexmk: applying rule 'pdflatex'...
Rule 'pdflatex': Reasons for rerun
Category 'other':
Rerun of 'pdflatex' forced or previously required
------------
Run number 1 of rule 'pdflatex'
------------
------------
Running 'pdflatex -fmt mwe -recorder "mwe.tex"'
------------
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=mwe)
restricted \write18 enabled.
kpathsea: Running mktexfmt mwe.fmt
mktexfmt: mktexfmt is using the following fmtutil.cnf files (in precedence order):
...
I can't find the format file `mwe.fmt'!
Latexmk: fls file doesn't appear to have been made.
Latexmk: Getting log file 'mwe.log'
Latexmk: Couldn't read log file 'mwe.log':
No such file or directory
问题
- 我怎样才能阻止
latexmk
,或者更确切地说,pdflatex
试图逃跑mktexfmt
? - 该行
I can't find the format file `mwe.fmt'!
仅输出到控制台,没有mwe.log
生成任何内容,这使得重新运行变得不可能,并且无法检测到我的自定义依赖项。我该如何改变这种行为? - 我可以将自定义子程序注入到 中
$pdflatex
,然后检查格式文件是否存在,如果不存在则可能创建它。这甚至可以与哈希过程相结合,以确保仅在需要时重新编译...哦,天哪,我注意到我正在复制 的功能latexmk
。那么,有没有办法latexmk
首先做到这一点?
我也期待听到其他建议。
答案1
- 我怎样才能阻止 latexmk 或者 pdflatex 尝试运行 mktexfmt?
$ pdftex --no-mktex=fmt --fmt mwe file
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=mwe)
restricted \write18 enabled.
I can't find the format file `mwe.fmt'!
显示未触发 mktexfmt 的运行
- 我找不到格式文件“mwe.fmt”!这一行仅输出到控制台,并且没有生成 mwe.log,这使得重新运行变得不可能,并且无法检测到我的自定义依赖项。我该如何改变这种行为?
我不认为这是可以改变的
- 我可以向 $pdflatex 注入一个自定义子程序,然后检查格式文件是否存在,如果不存在则可能创建它。
您可以,但是(没有上面(1.)中的选项)pdftex 已经在进行该检查,并且在文件不存在的情况下调用 mktexfmt,因此更简单的方法可能是配置 mktexfmt,以便在请求时构建 mwe.fmt。(texdoc mktexfmt
有一些关于如何设置 fmtutil 配置的信息)
答案2
大卫卡莱尔 (David Carlisle) 的出色回答让我找到了一种使用纯粹的方法来实现我的目标latexmk
,所以我将分享我的解决方案并看看如何改进它。
解决方案
正如大卫·卡莱尔所指出的,
$ pdftex --no-mktex=fmt --fmt mwe file This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=mwe) restricted \write18 enabled. I can't find the format file `mwe.fmt'!
显示未触发 mktexfmt 的运行
看来我无法正确读取文档并输入选项--no-mktex=fmt
。
正如大卫·卡莱尔 (David Carlisle) 所指出的,这次运行没有记录到相应的日志文件,因此不会latexmk
触发重新运行。
我的解决方案围绕着将输出流从 stdout 转换为日志文件,这完全可以通过以下方式实现.latexmkrc
:
mwe.tex
\documentclass{scrbook}
\usepackage{pgfplots}
\usepackage{amsmath}
\usepackage{siunitx}
\usepackage{lipsum}
\usepackage{geometry}
\begin{document}
\title{Shakespeare's Externalize}
\subtitle{To externalize or not to externalize?}
\subject{Case Studies}
\date{\today}
\maketitle{}
\lipsum[1-30]
\end{document}
.latexmkrc
# Set the program used to generate the PDF
# 1: pdflatex
# 2: postscript conversion, don't use this
# 3: dvi conversion, don't use this
# 4: lualatex
# 5: xelatex
$pdf_mode = 1;
# Add custom dependency.
# latexmk checks whether a file with ending as given in the 2nd
# argument exists ('toextension'). If yes, check if file with
# ending as in first argument ('fromextension') exists. If yes,
# run subroutine as given in fourth argument.
# Third argument is whether file MUST exist. If 0, no action taken.
add_cus_dep('tex', 'fmt', 1, "compilepreamble");
# show custom dependencies for debugging
show_cus_dep();
# parse missing files
push @file_not_found, '^I can\'t find the format file `(.*)\'\!';
# modify all tex engines to run with my customized instruction set
# in particular:
# - suppress mktexfmt using --no-mktexfmt=fmt
# - request use of custom format using --fmt=%B
# - call additional options provided to latexmk using %O
# - call the source file %S
set_tex_cmds("--shell-escape --interaction=batchmode --file-line-error --synctex=1 --no-mktex=fmt --fmt=%B %O %S > %B.log");
# custom sub handling the loading of the preamble and dumping it into $base.fmt
sub compilepreamble {
my ( $base) = @_;
# just output a simple debug string to console
print ("**** compilepreamble: ( $base ) ****\n");
# create the fmt file
$ret = system("pdflatex",
"-jobname", "$base",
"-ini",
"&pdflatex" ,
"mylatexformat.ltx",
$base
);
# if there were errors, return the error codes
return $ret;
}
评论
- 我的解决方案似乎是在第一次运行时创建 fmt,并在后续运行中重复使用它。
- 我的解决方案确实会在文件更改后
mwe.fmt
每次调用时触发文件重建。它没有区分更改是在文档中还是在序言中。这是一个缺点,但是,在我的用例中可以忽略它,因为latexmk
mwe.tex
- 大多数内容都位于自己的文件中,并使用
\input{}
- 在重新运行图形外部化时,将会节省相应的编译时间。
如果有人想提出改进建议,我很乐意听取。