我有一组目录,其中一些包含 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
Run Code Online (Sandbox Code Playgroud)
当它使用没有(定义的)“干净”目标的 makefile 访问目录时,这会做一件奇怪的事情。例如,给定两个目录,one
和two
,包含;
一个/makefile
clean:
-rm *.x
Run Code Online (Sandbox Code Playgroud)
两个/makefile
clean:
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,“clean”没有指令,所以如果你运行“make clean”,two
你会得到:
make: Nothing to be done for `clean'.
Run Code Online (Sandbox Code Playgroud)
对比如果没有“干净”:
make: *** No rule to make target `clean'. Stop.
Run Code Online (Sandbox Code Playgroud)
但是,对于我将要描述的问题,无论目标存在但未定义或不存在,结果都是相同的。clean.sh
从父目录运行;
Making clean in one...
rm *.x
rm: cannot remove `*.x': No such file or directory
make: [clean] Error 1 (ignored)
Run Code Online (Sandbox Code Playgroud)
所以one
不需要清洗。没什么大不了的,这正如预期的那样。但是之后:
Making clean in two...
cat clean.sh >clean
chmod a+x clean
Run Code Online (Sandbox Code Playgroud)
为什么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...
Run Code Online (Sandbox Code Playgroud)
更奇怪的是,因为现在它根本不使用指定的生成文件——它使用了一些“最新”的神秘目标。
我注意到一个可能相关的现象:如果像这样删除 clean.sh 中的一个测试子句:
# if [[ -d $f && -f $f/makefile ]]; then
if [[ -d $f ]]; then
Run Code Online (Sandbox Code Playgroud)
并创建一个three
没有makefile的目录,部分输出包括:
Making clean in three...
make: three/makefile: No such file or directory
make: *** No rule to make target `three/makefile'. Stop.
Run Code Online (Sandbox Code Playgroud)
我理解没有这样的文件或目录,但是为什么make
要继续寻找具有该名称的目标?手册页看起来很简单:
-f 文件, --file=file, --makefile=FILE
Run Code Online (Sandbox Code Playgroud)Use file as a makefile.
这种行为不是错误。这是一个特点。准确地说是一个功能和一个可能的用户错误。
有问题的特征是 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
Run Code Online (Sandbox Code Playgroud)明确空规则:
clean: ;
Run Code Online (Sandbox Code Playgroud)使clean
目标变得虚假:
.PHONY: clean
Run Code Online (Sandbox Code Playgroud)详细解释:
Make 有一堆隐含的规则。这允许人们在不编写 makefile 的情况下对简单项目调用 make。
试试这个进行演示:
clean.sh
.make clean
输出:
$ make clean
cat clean.sh >clean
chmod a+x clean
Run Code Online (Sandbox Code Playgroud)
砰!这就是隐含规则的力量。有关更多信息,请参阅有关隐式规则的make 手册。
我将尝试回答剩下的悬而未决的问题:
为什么它不调用第一个 makefile 的隐式规则?因为您用显式clean
规则覆盖了隐式规则。
为什么clean
第二个 makefile中的规则没有覆盖隐式规则?因为它没有配方。没有配方的规则不会覆盖隐式规则,而只是附加先决条件。有关更多信息,请参阅有关多个规则的make 手册。另请参阅有关具有显式空配方的规则的制作手册。
为什么在调用子目录中的 makefile 之前不更改工作目录会出错?因为 make 不会改变工作目录。Make 将在继承的工作目录中工作。好吧,从技术上讲,这不一定是错误,但大多数情况下是错误的。您希望子目录中的 makefile 在子目录中工作吗?或者您希望它们在父目录中工作?
为什么 makeclean
在第二次调用时忽略第一个 makefile 中的显式规则clean.sh
?因为现在目标文件clean
已经存在。由于规则clean
没有先决条件,因此无需重建目标。请参阅有关虚假目标的制作手册准确描述了此问题。
为什么three/makefile
在第三次调用中搜索目标?因为 make 总是在做任何其他事情之前尝试重新制作 makefile。如果 makefile 被明确请求使用-f
但它不存在,则尤其如此。有关更多信息,请参阅有关重新制作 makefile的make 手册。
归档时间: |
|
查看次数: |
2218 次 |
最近记录: |