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

Posted

技术标签:

【中文标题】如何制作将相同命令应用于子目录的单个makefile?【英文标题】:How to make a single makefile that applies the same command to sub-directories? 【发布时间】:2018-07-08 12:56:21 【问题描述】:

为了清楚起见,我使用 GnuWin32 make 在 Windows 上运行它。

我有一组目录,其中包含多个不同级别的降价文件-理论上它们可能位于分支节点中,但我认为目前它们仅位于叶节点中。我有一组 pandoc/LaTeX 命令可以运行以将降价文件转换为 PDF - 显然,如果降价文件已更新,则只想重新创建 PDF,因此 makefile 似乎合适。

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

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

理论文件夹结构:

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

我该如何编写一个makefile来处理这种情况?

【问题讨论】:

【参考方案1】:

这里有一小部分 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 只是在 cmets 中提出了这个建议

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

【讨论】:

感谢@dmitrichubarov 的起点,但我专门寻找一个不需要在makefile 中按名称指定子目录的版本,以便makefile 保留随着项目的发展和变化而保持不变。您提到另一个脚本可以建立子目录列表 - 您建议如何处理该部分? 如果您使用的是基于 POSIX 的系统,例如 GNU/Linux,这将是微不足道的;使用:PDF_FILES := $(shell find . -name \*.pdf)。也许了解 Windows 的人可以为您提供适用于那里的类似答案。 @Vecna vonder 如果 MadScientist 的建议对您有用。我已经用一些细节更新了帖子。 @DmitriChubarov - 谢谢。我已经取得了一些进展,但遇到了 make 似乎真的不喜欢文件路径中的空格的问题。有什么简单的方法吗?不确定重命名项目中的所有文件夹和文件是否可行。 @Vecna 对于 Makefile 中的文件名中的空格,恐怕没有好的解决方案(请参阅 ***.com/q/9838384/1328439 并在那里回答以了解任务的复杂性)。【参考方案2】:

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

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

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

all: $PDF_FILES

【讨论】:

以上是关于如何制作将相同命令应用于子目录的单个makefile?的主要内容,如果未能解决你的问题,请参考以下文章

Makefile:可以将 VPATH 变量应用于分配 Makefile 变量吗?

Makefile的制作

makefile教程

如何将不同的模式应用于单个数据集中的 csvs?

如何将后缀应用于makefile中的多个文件?

将单个触发器应用于相同的表