问题描述

问题描述

问题描述

我正在尝试latexmk使用.latexmkrc配置文件来设置“预编译”我的文档的序言,并在重新运行期间重复使用它。

根据大卫·卡莱尔的评论,使用预编译并没有真正节省足够的时间,不值得这么麻烦,他mylatex.ltx在 1988 年写道

但是,我的文档中有很多外部化的图形,并且 pgfplots 里面有很多引用,所以在我的情况下加载时间增长得非常快,我想探索预编译可以加快多少整个过程。

要求

我当前的要求是:

  1. 序言和正文必须能够位于同一个文档内,对于这个问题,就让它这样吧mwe.tex
  2. 所有编译都必须通过一次调用来完成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
    

    将是实现这一目标的最新方法。

我的自定义最小非工作示例

利用以前的信息和缺点,考虑到我的要求,我打算按照以下步骤解决这个问题:

  1. 修改$pdflatex中的变量.latexmkrc以要求预编译的前言mwe.fmt文件。
  2. 用于add_cus_dep('tex', 'fmt', 1, 'precompilepreamble');添加依赖项。
  3. 如有必要,定义 perl 子例程precompilepreamble来创建文件。mwe.fmt

我期望程序按照以下方式运行:

  1. 调用latexmk,加载我的自定义.latexmkrc配置。
  2. 第一次运行pdflatex失败,并将记录缺少的所需文件mwe.fmt
  3. latexmk决定需要额外运行,并将查找依赖项.fmt
  4. 因此,latexmk将运行我之前添加的自定义规则来生成mwe.fmt
  5. 之后,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

问题

  1. 我怎样才能阻止latexmk,或者更确切地说,pdflatex试图逃跑mktexfmt
  2. 该行I can't find the format file `mwe.fmt'!仅输出到控制台,没有mwe.log生成任何内容,这使得重新运行变得不可能,并且无法检测到我的自定义依赖项。我该如何改变这种行为?
  3. 我可以将自定义子程序注入到 中$pdflatex,然后检查格式文件是否存在,如果不存在则可能创建它。这甚至可以与哈希过程相结合,以确保仅在需要时重新编译...哦,天哪,我注意到我正在复制 的功能latexmk。那么,有没有办法latexmk首先做到这一点?

我也期待听到其他建议。

答案1

  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 的运行

  1. 我找不到格式文件“mwe.fmt”!这一行仅输出到控制台,并且没有生成 mwe.log,这使得重新运行变得不可能,并且无法检测到我的自定义依赖项。我该如何改变这种行为?

我不认为这是可以改变的

  1. 我可以向 $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;
}

评论

  1. 我的解决方案似乎是在第一次运行时创建 fmt,并在后续运行中重复使用它。
  2. 我的解决方案确实会在文件更改后mwe.fmt每次调用时触发文件重建。它没有区分更改是在文档中还是在序言中。这是一个缺点,但是,在我的用例中可以忽略它,因为latexmkmwe.tex
  • 大多数内容都位于自己的文件中,并使用\input{}
  • 在重新运行图形外部化时,将会节省相应的编译时间。

如果有人想提出改进建议,我很乐意听取。

相关内容