使用“make -f”自动执行奇怪的行为

使用“make -f”自动执行奇怪的行为

我有一组目录,其中一些包含 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 访问目录时,这会做一件奇怪的事情。例如,给定两个目录onetwo,包含;

一个/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:要解决此问题,您可以执行以下一项或多项操作:

  1. 修复 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
    
  2. 明确空规则:

    clean: ;
    
  3. clean目标变得虚假:

    .PHONY: clean
    

详细解释:

Make 有很多隐含的规则。这允许人们在简单的项目上调用 make,甚至无需编写 makefile。

尝试一下这个演示:

  1. 创建一个空目录并切换到该目录
  2. 创建一个名为clean.sh.
  3. 跑步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 手册了解更多信息。

相关内容