如何用 Makefile 在源码目录编译所有 LaTeX 文件?
可以用 GNU Make 的模式规则,让每个 PDF 目标依赖同一路径下的 .tex 文件。运行 latexmk 前先切换到源码目录,生成的文件就会留在该目录中。
Makefile
LATEXMK = latexmk -pdf -pdflatex="pdflatex --shell-escape %O %S"
SRCS := $(shell find . -type f -name '*.tex')
PDFS := $(SRCS:.tex=.pdf)
.PHONY: all
all: $(PDFS)
%.pdf: %.tex
cd "$(@D)" && $(LATEXMK) "$(@F)"
运行 make 时,find 会从当前目录递归查找 .tex 文件。模式规则 %.pdf: %.tex 会为每个源码文件建立对应目标。例如,./foo/baz.tex 对应 ./foo/baz.pdf,./bar/baz.tex 对应 ./bar/baz.pdf。模式中的 % 可以匹配带斜杠的路径,因此子目录层数不受限制。
配方中的 $(@D) 表示目标文件所在目录,$(@F) 表示目标文件名。以 ./foo/baz.pdf 为例,命令会先进入 ./foo,再让 latexmk 编译 baz.tex。PDF 和 latexmk 生成的中间文件都会写入源码目录。不同目录中的同名文件也会分别构建。
为什么原来的规则不合适
原规则让所有 PDF 目标都依赖整个 $(SRCS) 列表,配方则使用 $<,也就是当前规则的第一个先决条件。这样一来,配方没有逐个选取与 PDF 对应的源码,可能会反复处理同一个先决条件。模式规则会为每个目标自动匹配同路径下的 .tex 文件。
从仓库根目录直接把带子目录路径的源码传给 latexmk,默认输出目录可能是当前工作目录。配方先切换到源码目录后,默认输出位置就与源码目录一致。
增量构建
每个 PDF 只依赖对应的 .tex 文件。PDF 不存在,或源码比 PDF 更新时,Make 会执行编译;如果源码没有变化且 PDF 已存在,Make 通常会跳过该目标。latexmk 仍会按自身规则处理 TeX 文件引用的其他依赖。
这种写法用 find 生成构建列表。文件路径包含空格时,GNU Make 的空白分隔列表会带来问题;如果仓库中的源码路径可能含空格,就需要改用能妥善处理这类路径的构建方式。
备注:内容仅供参考。
