即使这方面有很多主题,我也找不到解决方案。我想在 GNU make Makefile 中结合两种技术,从带有文件的目录树中创建多个 Debian 软件包:
以下看起来不错,但没有找到必备文件:
TARGETS = a.deb b.deb z.deb
all: $(TARGETS)
%.deb: $(shell find % -type f)
$(TARGETS):
@echo "#### Building $@ due to \"$?\" ####"
Run Code Online (Sandbox Code Playgroud)
仅出于测试目的,我使用简单的“echo”而不是“find”测试了规则,这工作得很好(但当然仅取决于目录中的目标,而不是完整的文件树):
TARGETS = a.deb b.deb z.deb
all: $(TARGETS)
%.deb: $(shell echo %/ )
$(TARGETS):
@echo "#### Building $@ due to \"$?\" ####"
Run Code Online (Sandbox Code Playgroud)
如果我将目标文件名硬编码到“查找”内的规则中,它会起作用:
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 \"$?\" ####"
Run Code Online (Sandbox Code Playgroud)
但现在我必须维护包名称的更改或在文件中的 3 个位置添加新包以保持一致。
维护makefile既烦人又危险,有更好的方法吗?
`
您的解决方案揭示了对 make 如何评估变量和函数的误解。您必须了解 make 分为两个不同的步骤:首先,它解析所有 makefile 并构建所定义的变量和规则的内部数据库。其次,在解析所有 makefile 后,它会遍历相关目标并尝试构建过时的目标。重要的是,规则的目标部分和先决条件部分中的变量和函数的所有扩展都发生在第一步:解析 makefile。另一方面,直到第二步:构建目标时,模式才会扩展(因为直到我们尝试构建目标时,我们才能真正将模式与我们想要构建的内容进行匹配)。
所以这:
%.deb: $(shell find % -type f)
Run Code Online (Sandbox Code Playgroud)
将运行文字 shell 函数find % -type f,然后使用该函数的输出作为模式的先决条件列表%.dep。由于几乎可以肯定您没有任何名为 的文件或目录,因此%此 find 命令的结果为空,并且没有定义任何先决条件。
同时这个:
%.deb: $(shell echo %/ )
Run Code Online (Sandbox Code Playgroud)
只是一种非常慢、性能很差的编写方式:
%.deb: %/
Run Code Online (Sandbox Code Playgroud)
为什么调用 shell 只是为了回显静态字符串?
为了完成这项工作,您需要使用元编程的某些方面。例如,您可以使用二次扩展:
TARGETS = a.deb b.deb z.deb
all: $(TARGETS)
.SECONDEXPANSION:
$(TARGETS): $$(shell find $$(patsubst %.deb,%,$$@)/ -type f)
@echo "#### Building $@ due to \"$?\" ####"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1378 次 |
| 最近记录: |