Reputation: 43
I'd like to create a set of output files from multiple input files where the output format is specified as a target. E.g., for a single format:
svg: svg/file1.svg svg/file2.svg
svg/file1.svg svg/file2.svg: %.svg: %.dot
@dot -T svg -o $@ $<
Now how can I add more formats without duplicating rules and prerequisites? My approach was something like this:
input := file1 file2
formats := svg png
output := $(foreach format, ${formats}, $(foreach name, ${input}, ${format}/${name}.${format}))
# output := svg/file1.svg svg/file2.svg png/file1.png png/file2.png
all: ${formats}
${formats}: [somehow filter ${output} based on chosen format?]
${output}: [somehow filter out just the file name?]: %.dot
@dot -T svg -o $@ $<
I haven't been able to figure this out with variables and patterns. I did find a way using a variable for the format; e.g., make format=svg
, but I'd rather use target names.
Using GNU Make 4.3.
Upvotes: 1
Views: 81
Reputation: 6387
You're going to want to use a macro/eval for this -- but beware, by doing so, you may cross that line where your makefile can be easily understood/maintained by others.,,
input := file1 file2
formats := svg png
output := $(foreach format, ${formats}, $(foreach name, ${input}, ${name}.${format}))
all: $(foreach file,$(input),$(foreach format,$(foramts),$(file).$(format)))
define dot_rules
# $$1 is the basenames,
# $$2 is the input extension,
# $$3 is the target extension
$(1:=.$3) : %.$3 : %.$2
@echo dot -T $3 -o $3/$$@ $$<
endef
# just to be suure you got it right:
$(info $(foreach format,$(formats),\
$(call dot_rules,$(input),dot,$(format))))
# expand the calls into the makefile
$(eval $(foreach format,$(formats),\
$(call dot_rules,$(input),dot,$(format))))
Upvotes: 2