Makefile 只执行第一个目标

Makefile executes only the first target

我有这样的文件

1_0_fa.bam  1_1_fa.bam  1_2_fa.bam  1_3_fa.bam  1_4_fa.bam  1_5_fa.bam
1_6_fa.bam  1_7_fa.bam  1_8_fa.bam  1_9_fa.bam  1_0_mo.bam  1_1_mo.bam
1_2_mo.bam  1_3_mo.bam  1_4_mo.bam  1_5_mo.bam  1_6_mo.bam  1_7_mo.bam
1_8_mo.bam  1_9_mo.bam  1_0_p1.bam  1_1_p1.bam  1_2_p1.bam  1_3_p1.bam
1_4_p1.bam  1_5_p1.bam  1_6_p1.bam  1_7_p1.bam  1_8_p1.bam  1_9_p1.bam

我想按 bin 组合它们,这是名称中的第二个数字。这是我的 Makefile (GNU make 3.81)

SHELL = /bin/sh
bins = 0 1 2 3 4 5 6 7 8 9
$(info $(bins))
code = 1

define buildVCF

$(info $(1))
$(eval targ = $(code)_$(1)_bin.vcf)
$(info $(targ))
targs += $(targ)
$(eval deps = $(wildcard $(code)_$(1)_*.bam))
$(info $(deps))

$(targ): $(deps)
    cat $$^ > $$@

endef

$(foreach bin,$(bins),$(eval $(call buildVCF,$(bin))))

all: $(targs)

如果我这样做 make -n,它会产生

0 1 2 3 4 5 6 7 8 9
0
1_0_bin.vcf
1_0_p1.bam 1_0_mo.bam 1_0_fa.bam
1
1_1_bin.vcf
1_1_fa.bam 1_1_p1.bam 1_1_mo.bam
2
1_2_bin.vcf
1_2_mo.bam 1_2_p1.bam 1_2_fa.bam
3
1_3_bin.vcf
1_3_fa.bam 1_3_mo.bam 1_3_p1.bam
4
1_4_bin.vcf
1_4_mo.bam 1_4_fa.bam 1_4_p1.bam
5
1_5_bin.vcf
1_5_fa.bam 1_5_mo.bam 1_5_p1.bam
6
1_6_bin.vcf
1_6_p1.bam 1_6_fa.bam 1_6_mo.bam
7
1_7_bin.vcf
1_7_fa.bam 1_7_p1.bam 1_7_mo.bam
8
1_8_bin.vcf
1_8_fa.bam 1_8_mo.bam 1_8_p1.bam
9
1_9_bin.vcf
1_9_mo.bam 1_9_p1.bam 1_9_fa.bam
cat 1_0_p1.bam 1_0_mo.bam 1_0_fa.bam > 1_0_bin.vcf

为什么不构建其余目标?

当命令行上没有指定目标时,make 构建 default goal

默认目标是

the first target (not targets whose names start with ‘.’)

在您的 makefile 中,第一个目标是由 buildVCF 定义创建的第一个目标。

正如 Wintermute 指出的那样,您不能简单地将 all: $(targs) 行移动到循环上方,因为 targs 还没有正确的值。

话虽这么说,您可以将 all: 放在循环上方 "reserve" 默认目标(在这种情况下 all: $(targs) 将先决条件附加到保留目标),或者您可以 manually set the default goal.DEFAULT_GOAL := all 在 makefile 中的任意位置。

另一方面,我还没有完全理解您的设置,但我想您可以使用一组更简单的通用模式(或静态模式)规则来做到这一点。

因为 all 目标不是 Makefile 中的第一个目标。当您在没有目标的情况下调用 make 时,将构建 Makefile 中的第一条规则,在本例中是用于 1_0_bin.vcf 的规则(因为它首先生成)。如果您调用 make -n all,它将按您预期的那样工作。

要使其在没有明确规则的情况下工作,仅将 all 目标移动到顶部是行不通的,因为此时 targs 没有正确的值,但您可以使用间接级别使其工作:

all: dummy

define buildVCF
...
endef

$(foreach bin,$(bins),$(eval $(call buildVCF,$(bin))))

dummy: $(targs)

然而,这似乎是一种相当迂回的做事方式。如果我是你,我会尝试使用静态模式规则来解决问题,例如

targs = $(foreach bin,$(bins),$(code)_$(bin)_bin.vcf)

all: $(targs)

$(targs) : $(code)_%_bin.vcf : $(foreach i,fa mo p1,$(code)_%_$(i).bam)
    cat $^ > $@