I'm trying to write a makefile where I have a list of .asy files which are each generating a .png or .pdf.

I'm getting the correct extension by looking into the file, so I have the list of sources and objects they generate:

asy_to_ext = $(shell sed -n \
    's#^settings.outformat *= *"\([a-z]*\)" *;#\1#p' \
    $(file) | tail -1)
ASY_SRC := $(wildcard *.asy)
ASY_EXT := $(foreach file,$(ASY_SRC),$(asy_to_ext))
ASY_OBJ := $(ASY_SRC:.asy=.$(ASY_EXT))

My question is: now, how to I tell make that every object depends on the corresponding source? With a single extension a static pattern rule is fine:

$(ASY_OBJ) : %.png: %.asy
    asy -noView -nointeractiveView $<

But I could't find anything in the manual ressembling a pattern rule with a wildcard like $(ASY_OBJ) : %.*: %.asy or using the source list I have like $(ASY_OBJ) : $(ASY_SRC).

I also tried double-colon rules but they only process the first object until one of the rules doesn't match, and also ideally I'm looking for something that would work even is ASY_OBJ ends up having a different extension than .pdf or .png.

$(ASY_OBJ) :: %.png: %.asy
    asy -noView -nointeractiveView $<
$(ASY_OBJ) :: %.pdf: %.asy
    asy -noView -nointeractiveView $<

1 Answer 1


Going to answer myself since I ended up finding the way: the solution is with secondary expansion, which allows to use automatic variables in the prerequisite list. This way, whatever the extension of the target ends up being, it can be stripped and replaced with .asy.

It had also escaped me that my function to obtain ASY_EXT wasn't working properly, and that was solved by using the map function given in the manual.

# function returning the extension of the generated file
asy_to_ext = $(shell sed -n \
    's#^settings.outformat *= *"\([a-z]*\)" *;#\1#p' \
    $(1) | tail -1)
map = $(foreach a,$(2),$(call $(1),$(a)))

ASY_SRC := $(wildcard *.asy)
ASY_EXT := $(call map,asy_to_ext,$(ASY_SRC))
# build the target list by adding the computed extension to the basename of the sources
ASY_OBJ := $(join $(basename $(ASY_SRC)),$(addprefix .,$(ASY_EXT)))

.PHONY: asy
asy : $(ASY_OBJ)

# compute the prerequisite by adding .asy to the basename of the target
$(ASY_OBJ) : $$(addsuffix .asy,$$(basename $$@))
    asy -noView -nointeractiveView $<

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.