如何在GNU Makefile中遍历嵌套目录下的TeX文件并实现增量PDF构建
使用GNU Make批量编译TeX文件并保持目录结构
需求回顾
你有这样的TeX文件目录结构:
input/ | |-- one.tex |-- two.tex |-- sub1/ | | | |-- three.tex | |-- four.tex |-- sub2/ | | | |-- five.tex | |-- six.tex
想要用pdflatex把每个.tex文件编译成xxx_out.pdf,并且在output目录下保持和input完全一致的子目录结构,最终得到:
output/ | |-- one_out.pdf |-- two_out.pdf |-- sub1/ | | | |-- three_out.pdf | |-- four_out.pdf |-- sub2/ | | | |-- five_out.pdf | |-- six_out.pdf
同时希望Make能自动检测.tex文件的修改,只更新对应的PDF。你写的Makefile只处理了第一个文件,核心问题是目标文件定义和实际输出不匹配,且缺少目录创建步骤。
原Makefile的问题分析
- 目标与实际输出不匹配:你定义的
PDF_FILES是output/%.pdf,但实际用-jobname生成的是xxx_out.pdf,Make找不到预期目标文件,会出现重复执行或无法追踪所有文件的情况。 - 缺少输出目录创建:当
output/sub1这类子目录不存在时,pdflatex无法生成文件到对应目录,导致编译失败。 - Jobname路径处理错误:
$(addsuffix _out,$(basename $@))会生成类似output/one_out的路径,pdflatex会把文件生成在当前目录而非output下,进一步导致目标文件缺失。
修正后的Makefile
SOURCE_DIR := input BUILD_DIR := output # 递归查找所有.tex源文件 TEX_FILES := $(shell find $(SOURCE_DIR) -type f -name "*.tex") # 生成对应的目标PDF路径:将input/xxx.tex映射为output/xxx_out.pdf PDF_FILES := $(patsubst $(SOURCE_DIR)/%.tex, $(BUILD_DIR)/%_out.pdf, $(TEX_FILES)) .PHONY: all clean all: $(PDF_FILES) # 编译规则:每个output/xxx_out.pdf依赖于对应的input/xxx.tex $(BUILD_DIR)/%_out.pdf: $(SOURCE_DIR)/%.tex # 自动创建目标文件所在的目录(多级目录也能一次性创建) mkdir -p $(@D) # 指定输出目录到目标文件路径,jobname取不带路径的文件名(比如three_out) pdflatex -output-directory=$(dir $@) -jobname=$(notdir $(basename $@)) $< # 清理所有生成的PDF文件 clean: rm -rf $(BUILD_DIR)
关键说明
$(patsubst ...):精准映射源文件到目标文件,确保Make能正确追踪每个文件的依赖关系,实现增量编译。mkdir -p $(@D):$(@D)代表目标文件所在的目录,-p参数自动创建多级目录,解决子目录不存在的问题。pdflatex参数:-output-directory指定输出文件的存放目录,-jobname只取纯文件名,编译后的PDF会直接生成在预期的路径下,完美匹配目标文件。
其他可选方案(供参考)
如果你想简化流程,也可以试试这些工具:
- latexmk:专门的TeX编译工具,支持自动处理依赖和目录结构,一行命令就能实现需求:
find input -name "*.tex" -exec sh -c ' texfile="$1" outdir="output/$(dirname "${texfile#input/}")" mkdir -p "$outdir" latexmk -pdf -jobname="${outdir}/$(basename "${texfile%.tex}_out")" "$texfile" ' sh {} \; - Shell脚本:用循环遍历所有
.tex文件,手动处理目录和编译,适合简单场景,但没有Make的增量编译优势。
内容的提问来源于stack exchange,提问作者J...S
相关产品推荐
相关产品推荐

