我的 Makefile 中的一条规则将整个目录 (
res/
) 压缩为 ZIP 文件。显然,当res/
目录下的any文件发生变化时,需要执行这条规则。因此,我希望该规则将该目录下的所有文件作为先决条件。我该如何实施这个规则?
在 Bash 中启用
globstar
选项,您可以使用通配符模式 res/**/*
获取该目录中所有文件的列表。然而,如果你在 Makefile 中指定它作为先决条件,它似乎不起作用:
filename.jar: res/**/*
即使在
touch
中创建文件后res/
,仍然可以生成报告
make: `filename.jar' is up to date.
很明显它没有识别出该模式。
如果我将目录本身声明为先决条件:
filename.jar: res
那么当文件被修改时,Make将不会重新执行(我认为
make
只查看目录本身的修改日期,只有在添加、删除或重命名直接子级时才会更改)。
这个:
filename.jar: $(wildcard res/**/*)
似乎有效,至少在某些平台上。
编辑:
或者更好,直接解开这个结:
filename.jar: $(shell find res -type f)
之前的答案不正确。您不能使用双 glob
**
并期望它递归。遵循这个规则:
filename.jar: $(wildcard res/**/*.java) # does not work as expected
该行实际上与此行的行为相同:
filename.jar: $(wildcard res/*/*.java)
它将匹配
res/foo/bar.java
,但不会匹配 res/foo/bar/example.java
。
感谢名为 “2023 年 6 月辞职”的用户指点,
**
实际上并不能递归地工作。 wildcard
的手册页清楚地表明,唯一支持的魔术字符是*
(不是**
)、?
和[
]
。
shell
函数 和 find
命令。这样做的困难在于它不能很好地处理带有空格或换行符的文件名。这是一个根据需要转义空格的解决方案,但不处理文件名中的换行符:
filename.jar: $(shell find res -name '*.java' | sed 's@ @\\ @g')