目录树中具有多个依赖项的 Makefile

Makefile with multiple dependencies in directory tree

即使有很多这方面的主题,我也找不到解决方案。 我想在 GNU make Makefile 中结合两种技术,以使用文件从目录树中创建几个 Debian 软件包:

  1. 根据相应目录中的文件树创建 Debian 软件包,例如a.deb 依赖于目录 a/ 内的所有文件,所以如果 a/foo/bar 被更改,将生成 a.deb
  2. 对具有相同构建规则和操作的多个包执行此操作,例如目标 a.deb 取决于目录 a/ 中的文件树,b.deb 来自 b/ 直到 z.deb 来自 z/

以下看起来不错,但没有找到先决条件文件:

TARGETS = a.deb b.deb z.deb
all: $(TARGETS)
%.deb: $(shell find % -type f)
$(TARGETS):
   @echo "#### Building $@ due to \"$?\" ####"

仅出于测试目的,我用简单的 "echo" 而不是 "find" 测试了规则,这工作正常(但当然只依赖于目录中的目标,而不是完整的文件树):

TARGETS = a.deb b.deb z.deb
all: $(TARGETS)
%.deb: $(shell echo %/ )
$(TARGETS):
   @echo "#### Building $@ due to \"$?\" ####"

如果我将目标文件名硬编码到 "find" 内的规则中,它会起作用:

TARGETS = a.deb b.deb z.deb
all: $(TARGETS)
a.deb: $(shell find a/ -type f)
b.deb: $(shell find b/ -type f)
z.deb: $(shell find z/ -type f)
$(TARGETS):
   @echo "#### Building $@ due to \"$?\" ####"

但现在我必须维护包名称的更改或在文件中的 3 个位置添加新包以保持一致。

维护makefile既烦人又危险,有没有更好的办法?

`

您的解决方案揭示了对 make 如何计算变量和函数的误解。您必须了解 make 分两个不同的步骤进行:首先,它解析所有的 makefile 并为已定义的变量和规则构建一个内部数据库。其次,在解析所有 makefile 后,它会遍历相关目标并尝试构建过时的目标。重要的是,规则的 targetprerequisite 部分中的所有变量和函数扩展都发生在第一步:解析 makefile。另一方面,模式直到第二步才会扩展:构建目标(因为直到我们尝试构建目标,我们才真正可以将模式与我们想要构建的内容相匹配)。

所以,这个:

%.deb: $(shell find % -type f)

将 运行 文字 shell 函数 find % -type f,然后使用该函数的输出作为模式 %.dep 的先决条件列表。由于您几乎可以肯定没有任何文件或目录的字面意思是 %,此查找命令的结果是空的,并且没有定义先决条件。

同时这:

%.deb: $(shell echo %/ )

只是一种非常慢、性能很差的写入方式:

%.deb: %/

为什么调用 shell 只是为了回显静态字符串?

要完成这项工作,您需要使用 metaprogramming. For example, you can use secondary expansion:

的某些方面
TARGETS = a.deb b.deb z.deb

all: $(TARGETS)

.SECONDEXPANSION:
$(TARGETS): $$(shell find $$(patsubst %.deb,%,$$@)/ -type f)
        @echo "#### Building $@ due to \"$?\" ####"