您可能应该查看 GNU make 手册的介绍部分,其中描述了 make 的工作原理。
让我们看看你的makefile;首先你定义一些变量。假设您有文件SOMATIC/foo.vcf、SOMATIC/bar.vcf 和SOMATIC/baz.vcf。然后,您创建的变量在展开后将具有这些值:
OUTSOMATIC = SOMATIC
FINAL = FINAL
INPUT = SOMATIC/foo.vcf SOMATIC/bar.vcf SOMATIC/baz.vcf
现在您的 patsubst 会在 INPUT 中找到与模式 SOMATIC/%.vcf 匹配的所有单词,并将其替换为 FINAL/%somatic.ensemble.gz,其中与输入中的 % 匹配的部分将替换为输出:
OUTSORT2 = FINAL/foosomatic.ensemble.gz FINAL/barsomatic.ensemble.gz FINAL/bazsomatic.ensemble.gz
现在,make 发现您已经定义了一个 all 目标。因为它是 makefile 中的第一个目标,所以这是默认运行的目标。展开后是这样的:
all: SOMATIC/foo.vcf SOMATIC/bar.vcf SOMATIC/baz.vcf SOMATIC FINAL/foosomatic.ensemble.gz FINAL/barsomatic.ensemble.gz FINAL/bazsomatic.ensemble.gz FINAL
因此,make 将尝试构建 all 目标的所有先决条件,以确保它是最新的。首先它尝试构建SOMATIC/*.vcf 文件。这些文件已经存在,并且 make 没有关于如何重建它们的任何规则,因此它假定它们是最新的。
接下来它会尝试构建SOMATIC 文件。这是一个目录,它也没有要构建的规则,所以 make 假设它也是最新的。
接下来 make 尝试构建目标 FINAL/foosomatic.ensemble.gz。让确实有一个可以构建它的规则,你已经创建了一个:
$(FINAL)/%somatic.ensemble.gz: $(OUTSOMATIC)/%.vcf $(INPUT)
~/jdk1.8.0_121/bin/java ...
这与您要构建的目标相匹配,% 值为 foo,因此 make 将先决条件中的 % 替换为 foo 并发现 SOMATIC/foo.vcf 存在且不需要被重建,所以它运行你的食谱。但是,您的配方实际上并没有创建目标FINAL/foosomatic.ensemble.gz;它创建目标FINAL/somatic_ensemble.gz。所以这条规则被打破了,因为它告诉 make 它会做一件事,但它会做另一件事。
您应该始终确保您的所有配方都构建由自动变量$@ 表示的文件;这将确保您同意您的规则的含义。如果您希望您的配方构建其他文件,那么您的规则编写不正确。
下一个 make 对 all 的下一个先决条件做同样的事情:FINAL/barsomatic.ensemble.gz。由于该文件不存在,make 尝试使用模式规则构建它,但同样会创建相同的输出文件。
对于第三个 .gz 文件 FINAL/bazsomatic.ensemble.gz。这就是为什么事情会运行 3 次。
如果您将模式规则更改为构建 FINAL/somatic.ensemble.gz 的显式规则,这是您想要的,那么 make 无法找到任何方法来构建 all 目标的先决条件,因此会出现此错误。
您的问题是OUTSORT2 的创建。您只想创建一个输出文件,但您已将OUTSORT2 设置为包含三个不同的文件,因此 make 会尝试创建所有三个文件。你想要这个:
OUTSOMATIC = SOMATIC
FINAL = FINAL
INPUT = $(wildcard $(OUTSOMATIC)/*.vcf)
OUTSORT2 = $(FINAL)/somatic.ensemble.gz
.PHONY: all
all: $(OUTSORT2)
$(OUTSORT2): $(INPUT)
~/jdk1.8.0_121/bin/java -XX:+UseSerialGC -Xms1g -Xmx10g -jar /illumina/software/PROG2/bcbio-variation-recall-0.1.7 ensemble -n 1 $@ /illumina/software/database/database_2016/hg19_primary.fa $^