ndr
ndr

Reputation: 1437

Makefile executes only the first target

I have files that look like this

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

I'd like to combine them by bin, which is the second number in the name. Here is my 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)

If i do make -n, it produces

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

Why is not building the rest of the targets?

Upvotes: 2

Views: 2641

Answers (2)

Etan Reisner
Etan Reisner

Reputation: 81052

When no target is specified on the command line make builds the default goal.

The default goal is

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

In your makefile the first target is the first target created by the buildVCF define.

As Wintermute points out you can't simply move the all: $(targs) line above the loop as targs doesn't have the correct value yet.

That being said you can either put all: above the loop to "reserve" the default target (in which case all: $(targs) appends prerequisites to the reserved target) or you can manually set the default goal with .DEFAULT_GOAL := all anywhere in the makefile.

On a different not I haven't fully understood the setup you have but I would imagine you could do this with a simpler set of general pattern (or static pattern) rules.

Upvotes: 1

Wintermute
Wintermute

Reputation: 44063

Because the all target isn't the first in the Makefile. When you call make without a target, the first rule in the Makefile is built, which in this case is the one for 1_0_bin.vcf (because it is generated first). If you call make -n all, it'll work as you expect.

To make it work without an explicit rule, just moving the all target to the top won't work because targs doesn't have the correct value at that point, but you can make it work using a level of indirection:

all: dummy

define buildVCF
...
endef

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

dummy: $(targs)

However, this does seem like a rather roundabout way of doing things. If I were you, I'd attempt to solve the problem with a static pattern rule, such as

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

all: $(targs)

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

Upvotes: 4

Related Questions