Reputation: 167
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
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