我有一组目录,其中一些包含 makefile,一些 makefile 有clean
目标。在父目录中,我有一个简单的脚本:
#!/bin/bash
for f in *; do
if [[ -d $f && -f $f/makefile ]]; then
echo "Making clean in $f..."
make -f $f/makefile clean
fi
done
当它使用没有(定义的)“干净”目标的 makefile 访问目录时,这会做一件奇怪的事情。例如,给定两个目录one
和two
,包含;
一个/makefile
clean:
-rm *.x
两个/makefile
clean:
在第二种情况下,“clean”在没有指令的情况下出现,因此如果您运行“make clean”,two
您会得到:
make: Nothing to be done for `clean'.
与没有“干净”的情况相比:
make: *** No rule to make target `clean'. Stop.
但是,对于我要描述的问题,无论目标存在但未定义还是不存在,结果都是相同的。clean.sh
从父目录运行;
Making clean in one...
rm *.x
rm: cannot remove `*.x': No such file or directory
make: [clean] Error 1 (ignored)
所以one
不需要清洗。没什么大不了的,这是意料之中的。但是之后:
Making clean in two...
cat clean.sh >clean
chmod a+x clean
为什么cat clean.sh>clean
等等?请注意,我确实创建了一个完全如上所示的最小示例 - 周围没有其他文件或目录(只有 clean.sh、目录一和目录二以及非常小的 makefile)。但在 clean.sh 运行后,make
已复制clean.sh > clean
并使其可执行。如果我再次运行 clean.sh:
Making clean in one...
make: `clean' is up to date.
Making clean in two...
make: `clean' is up to date.
Press any key to continue...
更奇怪的是,因为现在它根本不使用指定的 makefile——它使用一些“最新”的神秘目标。
我注意到一个可能相关的现象:如果删除 clean.sh 中的一个测试子句,如下所示:
# if [[ -d $f && -f $f/makefile ]]; then
if [[ -d $f ]]; then
并创建一个没有makefile的目录three
,部分输出包括:
Making clean in three...
make: three/makefile: No such file or directory
make: *** No rule to make target `three/makefile'. Stop.
据我所知,没有这样的文件或目录,但为什么还要make
继续寻找具有该名称的目标呢?手册页看起来非常简单:
-f 文件,--file=文件,--makefile=文件
Use file as a makefile.
答案1
这种行为不是错误。这是一个特点。准确地说,是一项功能和可能的用户错误。
所讨论的功能是 Make 的隐含规则之一。在您的情况下,“构建”文件的隐含规则*.sh
。用户错误,您的错误,是在调用子目录中的 makefile 之前没有更改工作目录。
TL; DR:要解决此问题,您可以执行以下一项或多项操作:
修复 shell 脚本以更改工作目录:
#!/bin/bash for f in *; do if [[ -d $f && -f $f/makefile ]]; then echo "Making clean in $f..." (cd $f; make clean) fi done
明确空规则:
clean: ;
让
clean
目标变得虚假:.PHONY: clean
详细解释:
Make 有很多隐含的规则。这允许人们在简单的项目上调用 make,甚至无需编写 makefile。
尝试一下这个演示:
- 创建一个空目录并切换到该目录
- 创建一个名为
clean.sh
. - 跑步
make clean
输出:
$ make clean
cat clean.sh >clean
chmod a+x clean
嘭!这就是隐含的制造规则的力量。请参阅制定有关隐含规则的手册了解更多信息。
我将尝试回答剩下的悬而未决的问题:
为什么它不调用第一个 makefile 的隐式规则?因为您用显式规则覆盖了隐式clean
规则。
为什么clean
第二个 makefile 中的规则不会覆盖隐式规则?因为它没有食谱。没有配方的规则不会覆盖隐式规则,而只是附加先决条件。请参阅制定关于多个规则的手册了解更多信息。另请参阅使用明确的空食谱制作有关规则的手册。
为什么在调用子目录中的 makefile 之前不更改工作目录会出错?因为make不会改变工作目录。 Make 将在继承的工作目录中工作。从技术上来说,这不一定是错误,但大多数时候都是错误。您希望子目录中的 makefile 在子目录中工作吗?或者您希望它们在父目录中工作?
为什么 makeclean
在第二次调用中忽略第一个 makefile 中的显式规则clean.sh
?因为现在目标文件clean
已经存在。由于该规则clean
没有先决条件,因此无需重建目标。请参阅制作有关虚假目标的手册这准确地描述了这个问题。
three/makefile
为什么 make在第三次调用时会搜索目标?因为 make 总是在做其他事情之前尝试重新创建 makefile。如果明确请求使用 makefile-f
但它不存在,则尤其如此。请参阅有关重新制作 makefile 的 make 手册了解更多信息。