如何制作将相同命令应用于子目录的单个 makefile?

How to make a single makefile that applies the same command to sub-directories?

为清楚起见,我在 windows 上 运行 使用 GnuWin32 make.

我有一组目录,其中有几个不同级别的降价文件 - 理论上它们可以在分支节点中,但我认为目前它们只在叶节点中。我有一组 pandoc/LaTeX 命令 运行 将 markdown 文件转换为 PDF - 显然只想在 markdown 文件已更新时重新创建 PDF,所以 makefile 似乎是合适的。

我想要的是根目录中的单个 makefile,它遍历任何和所有子目录(任何深度)并应用我将为 运行 指定的 make 规则pandoc.

据我所知,recursive makefiles 要求您在每个子目录中都有一个 makefile(这似乎是我想避免的管理开销)and/or 要求您列出 makefile 开头的所有子目录(同样,希望避免这种情况)。

理论文件夹结构:

root
|-make
|-Folder AB
|   |-File1.md
|   \-File2.md
|-Folder C
| \-File3.md
\-Folder D
  |-Folder E
  | \-File4.md
  |-Folder F
    \-File5.md

如何编写 makefile 来处理这种情况?

这里有一小部分 Makefile 规则,希望能助您一臂之力

%.pdf : %.md
        pandoc -o $@ --pdf-engine=xelatex $^

PDF_FILES=FolderA/File1.pdf FolderA/File2.pdf \
   FolderC/File3.pdf FolderD/FolderE/File4.pdf FolderD/FolderF/File5.pdf

all: ${PDF_FILES}

让我解释一下这里发生了什么。首先,我们有一个模式规则告诉 make 如何将 Markdown 文件转换为 PDF 文件。 --pdf-engine=xelatex 选项仅用于说明目的。

然后我们需要告诉Make要考虑哪些文件。我们将这些名称放在一个变量 PDF_FILES 中。这个变量的这个值可以通过一个单独的脚本来构建,该脚本扫描所有子目录以查找 .md 文件。

注意如果文件名或目录名包含空格,则必须格外小心。

然后我们要求 Make 检查是否有任何 PDF_FILES 应该被更新。

如果您的 makefile 中有其他目标,请确保 all 是第一个非模式目标,或者将 make 调用为 make all

更新 Makefile

如果 shell 函数适合您,并且基本实用程序(如 sed 和 find)可用,您可以使用一行使您的 makefile 动态化。

%.pdf : %.md
        pandoc -o $@ --pdf-engine=xelatex $^

PDF_FILES:=$(shell find -name "*.md" | xargs echo | sed 's/\.md/\.pdf/g' )
all: ${PDF_FILES}

MadScientist 在评论中只是建议

否则,您可以使用操作系统上可用的工具实现一个脚本,并添加一个额外的目标 update: 来计算文件列表,并将以 PDF_FILES 开头的行替换为更新的文件列表。

根据@DmitiChubarov 和@MadScientist 的建议,适用于 Windows 的代码的最终版本如下:

%.pdf: %.md
    pandoc $^ -o $@

PDF_FILES:=$(shell dir /s /b *.md | sed "s/\.md/\.pdf/g")

all: ${PDF_FILES}