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

时间:2019-05-02 00:20:07

标签: makefile

我有一个包含测试输入和输出的目录。为了方便起见,我希望make在构建后针对该目录自动测试我的程序。因此,我需要以某种方式强制test的{​​{1}}目标依赖于整个测试目录(之所以称为Makefile,是因为它包含程序的有效输入和输出)

我阅读了这个问题,可接受的答案以及该答案下有关已删除文件的评论:Makefile rule that depends on all files under a directory (including within subdirectories),并结合了该答案和评论的建议,我得出了这样的结论:

good

出于MCVE的考虑,my@comp:~/wtfdir$ cat Makefile test : test.sh $(shell find good) ./test.sh my@comp:~/wtfdir$ 非常简单:

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$ ,导致test1make覆盖了test1.out?您知道我不是数据丢失的忠实拥护者。

这是怎么回事?

1 个答案:

答案 0 :(得分:1)

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

test : test.sh $(shell find good)
    ./test.sh

将列出的每个文件和目录添加到test的先决条件中 在当前目录中的find good中,恰好是:

good
good/test1
good/test1.out

因此要确定目标test,请首先确定是否指定了目标 或内置食谱要求它重建任何先决条件:

test.sh good good/test1 good/test1.out

在其内置的食谱中,它发现:

%.out: %
#  recipe to execute (built-in):
    @rm -f $@
     cp $< $@

您可以通过运行以下命令进行验证:

$ make --print-data-base | grep -A4 '%.out'

此食谱的规则与以下项匹配:

good/test1.out: good/test1

并这样做:

$ touch good/test1

您已经使good/test1.out相对于good/test1过期了。

因此make执行配方:

    @rm -f good/test1.out
     cp good/test1 good/test1.out

您所观察到的可见输出

cp good/test1 good/test1.out

然后继续处理test的配方:

./test.sh
blah

如果您盲目编写一个makefile,则总是存在此类陷阱的风险 在运行时生成一些您事先不知道的前提条件或目标。

您可以通过明确删除违规行为来避免这种情况 通过以下方式在makefile中使用隐式模式规则:

%.out: %

没有配方。而且,您可以通过禁用 all 来避免所有可能的此类诱杀装置 内置食谱,其中包括:

$ make --no-builtin-rules ...

但是,这将需要您为自己编写任何内置食谱, makefile依赖。

最适合您的解决方案可能是如下修改makefile:

PREREQS := $(shell find good)

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

$(PREREQS): ;

然后最后一行明确指定一个empty recipe 对于每个$(PREREQS),并且Make不会参考目标的任何模式规则 有明确的食谱。

您还应该将test设为phony target

.PHONY: test

避免在某些情况下会在构建目录中创建名为test的文件的陷阱。