Makefile 为什么要将一个文件复制到另一个文件上?(目标取决于整个文件夹。)

Makefile 为什么要将一个文件复制到另一个文件上?(目标取决于整个文件夹。),makefile,Makefile,我有一个带有测试输入和输出的目录。为了方便起见,我希望make在构建后根据这个目录自动测试我的程序。因此,我需要以某种方式强制Makefile的test目标依赖于整个测试目录(它被称为good,因为它包含程序的有效输入和输出) 我阅读了这个问题和接受的答案,以及这个答案下关于删除文件的评论:结合这个答案和评论中的建议,我得出以下结论: my@comp:~/wtfdir$ cat Makefile test : test.sh $(shell find good) ./test.sh my

我有一个带有测试输入和输出的目录。为了方便起见,我希望
make
在构建后根据这个目录自动测试我的程序。因此,我需要以某种方式强制
Makefile
test
目标依赖于整个测试目录(它被称为
good
,因为它包含程序的有效输入和输出)

我阅读了这个问题和接受的答案,以及这个答案下关于删除文件的评论:结合这个答案和评论中的建议,我得出以下结论:

my@comp:~/wtfdir$ cat Makefile
test : test.sh $(shell find good)
    ./test.sh
my@comp:~/wtfdir$ 
为了实现MCVE,
test.sh
非常简单:

my@comp:~/wtfdir$ cat test.sh
echo "blah"
my@comp:~/wtfdir$
然而,我注意到,这表现出一种相当出乎意料的方式:

my@comp:~/wtfdir$ ls good
test1  test1.out
my@comp:~/wtfdir$ make
./test.sh
blah
my@comp:~/wtfdir$ touch good/test1
my@comp:~/wtfdir$ make
cp good/test1 good/test1.out
./test.sh
blah
my@comp:~/wtfdir$ 
为什么修改
test1
会导致
make
test1
覆盖
test1.out
???你知道,我不太喜欢数据丢失


这是怎么回事?

您的品牌似乎是GNU品牌。这就是为什么会发生这种情况。你的食谱:

test : test.sh $(shell find good)
    ./test.sh
将列出的每个文件和目录添加到
test
的先决条件中 通过
在当前目录中查找好的
,它恰好是:

good
good/test1
good/test1.out
因此,要使目标
测试
,make首先确定 或内置配方要求其重建任何预需求业务:

test.sh good good/test1 good/test1.out
在其内置配方中,它发现:

%.out: %
#  recipe to execute (built-in):
    @rm -f $@
     cp $< $@
此配方的规则符合以下条件:

good/test1.out: good/test1
通过这样做:

$ touch good/test1
关于
good/test1
,您已使
good/test1.out
过时

因此,make执行以下操作:

    @rm -f good/test1.out
     cp good/test1 good/test1.out
其可见输出是您观察到的:

cp good/test1 good/test1.out
然后继续进行
测试的配方

./test.sh
blah
如果你盲目地编写一个makefile,那么总是会有这种陷阱的风险 在运行时生成一组您事先不知道的预请求站点或目标

您可以通过显式删除有问题的 在makefile中写入隐式模式规则:

%.out: %
没有配方。而且你可以通过禁用所有可能的诱杀装置来避免这类诱杀 内置配方,具有:

$ make --no-builtin-rules ...
但这将需要你为自己写下任何你喜欢的内置食谱 makefile依赖于

最好的解决方案可能是修改makefile,如下所示:

PREREQS := $(shell find good)

test : test.sh $(PREREQS)
    ./test.sh

$(PREREQS): ;
然后,最后一行显式指定 对于每个
$(PREREQS)
,和Make都不会参考目标的任何模式规则 有明确的食谱

您还应进行
test
a:


为了避免诱杀陷阱,某些东西在build目录中创建了一个名为
test
的文件。

您的Make似乎是GNU Make。这就是为什么会发生这种情况。你的食谱:

test : test.sh $(shell find good)
    ./test.sh
将列出的每个文件和目录添加到
test
的先决条件中 通过
在当前目录中查找好的
,它恰好是:

good
good/test1
good/test1.out
因此,要使目标
测试
,make首先确定 或内置配方要求其重建任何预需求业务:

test.sh good good/test1 good/test1.out
在其内置配方中,它发现:

%.out: %
#  recipe to execute (built-in):
    @rm -f $@
     cp $< $@
此配方的规则符合以下条件:

good/test1.out: good/test1
通过这样做:

$ touch good/test1
关于
good/test1
,您已使
good/test1.out
过时

因此,make执行以下操作:

    @rm -f good/test1.out
     cp good/test1 good/test1.out
其可见输出是您观察到的:

cp good/test1 good/test1.out
然后继续进行
测试的配方

./test.sh
blah
如果你盲目地编写一个makefile,那么总是会有这种陷阱的风险 在运行时生成一组您事先不知道的预请求站点或目标

您可以通过显式删除有问题的 在makefile中写入隐式模式规则:

%.out: %
没有配方。而且你可以通过禁用所有可能的诱杀装置来避免这类诱杀 内置配方,具有:

$ make --no-builtin-rules ...
但这将需要你为自己写下任何你喜欢的内置食谱 makefile依赖于

最好的解决方案可能是修改makefile,如下所示:

PREREQS := $(shell find good)

test : test.sh $(PREREQS)
    ./test.sh

$(PREREQS): ;
然后,最后一行显式指定 对于每个
$(PREREQS)
,和Make都不会参考目标的任何模式规则 有明确的食谱

您还应进行
test
a:

为了避免诱杀陷阱,某些东西在构建目录中创建了一个名为
test
的文件