Reputation: 1095
I have a list of products:
Which depends on a different list of sources:
The dependence is one-to-one (the nth element of the first list has the nth element of the second list as its source), and the recipe is the same in all cases. There is, for all intents and purposes, no structure to the lists - it's not possible to write a simple expression which allows the nth element of the list to be generated from n. The solution that I know will work is
1 : z
[recipe]
2 : y
[identical recipe]
3 : x
[identical recipe]
4 : w
[identical recipe]
...but I don't like this because it makes it easier to make a mistake when modifying the lists or the recipe. I would prefer to take advantage of the correspondence pattern and begin with
SRCLIST = z y x w
DSTLIST = 1 2 3 4
And then somehow have a general rule like
DSTLIST_n : SRCLIST_n
[recipe]
Is there any way of doing something like this?
Upvotes: 1
Views: 401
Reputation: 15493
Nice problem. You didn't mention which version of make you are using, but .SECONDEXPANSION
often works well for these sorts of source lookup tables.
A sketch:
srcs := z x y w
targets := 1 2 3 4
.SECONDEXPANSION:
pairs := $(join ${targets},$(addprefix :,${srcs}))
lookup-src = $(patsubst $1:%,%,$(filter $1:%,${pairs}))
${targets}: $$(call lookup-src,$$@)
echo '[$^] -> [$@]'
Upvotes: 1
Reputation: 80992
This is a bit ugly but I believe it should work. (There are probably slightly better ways but this was the first thing I came up with.)
SRCLIST = z y x w
DSTLIST = 1 2 3 4
# Create a list of : the length of SRCLIST
MIDLIST = $(foreach s,$(SRCLIST),:)
$(info SRCLIST:$(SRCLIST))
$(info DSTLIST:$(DSTLIST))
$(info MIDLIST:$(MIDLIST))
# Join the three lists together (in two passes since $(join) only takes two lists)
JOINLIST = $(join $(join $(DSTLIST),$(MIDLIST)),$(SRCLIST))
$(info joined:$(JOINLIST))
# eval each of the created strings to create the prerequisite entries
$(foreach r,$(JOINLIST),$(eval $r))
# Set the rules to build all the targets.
$(DSTLIST):
echo '$@ for $^'
$ touch z y x w
$ make
SRCLIST:z y x w
DSTLIST:1 2 3 4
MIDLIST:: : : :
joined:1:z 2:y 3:x 4:w
echo '1 for z'
1 for z
echo '2 for y'
2 for y
echo '3 for x'
3 for x
echo '4 for w'
4 for w
I should note that this will not deal with spaces in any of the entries at all well (but that's generally true of make so nothing specific to this solution).
You could also always just create a Canned Recipe and then just stick that in each explicitly written out target as in your original idea.
Upvotes: 1
Reputation: 1095
Inspired by Etan, here is what I found worked:
SRCLIST = z y x w
DSTLIST = 1 2 3 4
# Make a list of ":" for combining
SEPARATOR = $(foreach s,$(SRCLIST),:)
# Define a parameterized rule which accepts the dst:src info as an argument
define dst-src
$1
[rule]
endef
# Define the list of dependencies
DST_SRC_RELNS = $(join $(join $(DSTCLIST),$(SEPARATOR)),$(SRCLIST))
# ^ DST_SRC_RELNS evaluates to z:1 y:2 x:3 w:4
# Print a preview of the rules the makefile generates itself
$(info $(foreach r,$(DST_SRC_RELNS),$(call dst-src,$r)))
# Generate the rules
$(foreach r,$(DST_SRC_RELNS),$(eval $(call dst-src,$r)))
I think that you could get away with not defining the parameterized rule dst-src
by actually writing the rule out inside the $(eval ...)
, but I didn't like this for two reasons:
newline
macro for the result to be something that make will recognize as a rule$(foreach ...)
makes it even harder for a human reader to figure out what's really going onUpvotes: 1