user3228136
user3228136

Reputation: 167

How to associate list of prerequisites with list of targets in Make?

Say I have:

TARGETS = a.o b.o c.o
SOURCES = F1/a.c F2/F3/b.c c.c

I want to obtain:

a.o: F1/a.c
  gcc $< -c
b.o: F2/F3/b.c
  gcc $< -c
c.o: c.c
  gcc $< -c

I would like a compact expression to do the job, something like:

$(TARGETS): $(SOURCES)
   #Appropriate compile command

Upvotes: 3

Views: 536

Answers (1)

Andrea Biondo
Andrea Biondo

Reputation: 1686

You could use VPATH to tell make about source directories and then use a simple pattern rule:

TARGETS := a.o b.o c.o
VPATH := F1:F2/F3 # Use ; instead of : on Windows

%.o: %.c
    $(CC) -c $< -o $@

(or even omit the rule altogether, make implicit rules will work fine in this case)

But if you have files that are named in the same way in different paths that's not going to work (it'd just pick the first one it finds). This works by zipping the lists like you asked:

TARGETS := a.o b.o c.o
SOURCES := F1/a.c F2/F3/b.c c.c

$(TARGETS):
    $(CC) -c $< -o $@

list-rem = $(wordlist 2,$(words $1),$1)
pairmap = $(and $(strip $2),$(strip $3),$(call \
        $1,$(firstword $2),$(firstword $3))$(call \
        pairmap,$1,$(call list-rem,$2),$(call list-rem,$3)))
gen-prereq = $(eval $1: $2)

$(call pairmap,gen-prereq,$(TARGETS),$(SOURCES))

I defined an explicit rule which compiles its prerequisite, but I didn't give it any prerequisites. I then defined a pairmap that takes a function name and two lists and calls the function for each pair of elements. It's recursive and is helped by list-rem, which takes the first element out of a list. gen-prereq sets its second argument as a prerequisite of the target specified by its first one. All that's left then is calling pairmap over gen-prereq, passing the targets as the first list and the sources as the second.

Another feasible and simpler way is:

TARGETS := a.o b.o c.o
SOURCES := F1/a.c F2/F3/b.c c.c

$(TARGETS):
    gcc -c $< -o $@

$(foreach x,$(join $(addsuffix :,$(TARGETS)),$(SOURCES)),$(eval $x))

Which works by joining targets and sources together with a : in between them (prerequisite) and eval'ing each one.

Upvotes: 3

Related Questions