【问题标题】:Makefile with multiple dependencies in directory tree目录树中具有多个依赖项的 Makefile
【发布时间】:2015-01-17 15:39:42
【问题描述】:

即使这方面的话题很多,我也找不到解决办法。 我想在 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 \"$?\" ####"

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

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既烦人又危险,有没有更好的方法?

`

【问题讨论】:

  • 一种可能的不同方法是,如果您将所有文件都置于版本控制之下,并且不添加任何新文件。然后你可以设置你的版本控制系统自动提交新的更改,并运行你的 Debian 包构建作为 post-commit 钩子的一部分。
  • 哦,多么好的建议:是的,所有文件也都在 Git 版本控制之下,所以应该有一个选项可以在提交时触发 Debian 包构建。这需要改变工作行为,因为目前我有几个提交,直到一个包发布发生......呃,我必须考虑......无论如何谢谢!
  • 如果你觉得有用,我可以正式回答。我在想象一个场景,你有多个存储库,但这将取决于你想要做什么的细节。
  • 我认为不需要正式的答案,因为它更像是一种解决方法/更好的方法,完全省略了 Makefile。潜在的 Makefile 问题仍然存在

标签: makefile debian


【解决方案1】:

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

所以,这个:

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

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

同时这个:

%.deb: $(shell echo %/ )

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

%.deb: %/

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

要完成这项工作,您需要使用metaprogramming 的某些方面。例如,您可以使用secondary expansion

TARGETS = a.deb b.deb z.deb

all: $(TARGETS)

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

【讨论】:

  • 你作为“疯狂科学家”是怎么知道二次扩展的???我在 IT 领域工作了 20 多年,也经常使用 Makefile,但这对我来说真的很新……我已经尝试过了,它开箱即用 - 非常感谢这个非常好的提示.顺便说一句:使用 $(shell echo %/ ) 当然只是为了测试目的,看看 % 是否会被扩展为 shell 内的命令 - 这很有效。另外,通过您的解释,我学到了很多东西,谢谢
  • % 根本没有在“外壳内部”扩展。 $(shell echo %/) 只是用文字命令echo %/ 调用了一个shell,它打印了文字字符串%/,因此%/ 被用作先决条件。
猜你喜欢
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-26
相关资源
最近更新 更多