elespike
elespike

Reputation: 43

How can I specify different file extensions as targets for multiple output files?

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

Answers (1)

HardcoreHenry
HardcoreHenry

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

Related Questions