Двойной % в GNU Make

Я пытаюсь написать Makefile, который будет генерировать «прямоугольный» набор выходных файлов из одного исходного файла. Представьте, что у нас есть один файл SVG, и мы хотим скомпилировать его во множество файлов PNG. Создание файлов PNG контролируется двумя параметрами (отсюда и слово «прямоугольный») — разрешением (высокое, низкое) и цветом (цветной, черно-белый). Простейший Makefile, который создает такие файлы PNG из файла SVG, может выглядеть так:

img-highres-color.png: img.svg
    convert --highres --color --output img-highres-color.png img.svg

img-highres-bw.png: img.svg
    convert --highres --bw --output img-highres-color.png img.svg

img-lowres-color.png: img.svg
    convert --lowres --color --output img-highres-color.png img.svg

img-lowres-bw.png: img.svg
    convert --lowres --bw --output img-highres-color.png img.svg

Следующим шагом является создание правила статического шаблона, использующего %. Я смог придумать это:

RESOLUTIONS = highres lowres
COLORS = color bw

PNG_FILES = $(foreach r, $(RESOLUTIONS), $(foreach c, $(COLORS), img-$(r)-$(c).png))

$(filter img-highres-%.png, $(PNG_FILES)): img-highres-%.png: img.svg
    convert --highres --$* --output img-highres-$*.png img.svg

$(filter img-lowres-%.png, $(PNG_FILES)): img-lowres-%.png: img.svg
    convert --lowres --$* --output img-lowres-$*.png img.svg

Наконец, я хотел бы создать одно правило статического шаблона, но для этого потребовалось бы использование двойного %, например:

RESOLUTIONS = highres lowres
COLORS = color bw

PNG_FILES = $(foreach r, $(RESOLUTIONS), $(foreach c, $(COLORS), img-$(r)-$(c).png))

$(filter img-%-%.png, $(PNG_FILES)): img-%-%.png: img.svg
    convert --$* --$* --output img-$*-$*.png img.svg

Это, конечно, не работает. Можно ли написать одно правило для достижения этого?

Ситуация выше является упрощенным описанием моей реальной ситуации. Важно то, что значение переменных RESOLUTIONS и COLORS заранее неизвестно. Кроме того, можете ли вы предоставить решение, достаточно общее для работы с более чем двумя измерениями? В приведенном выше примере третьим измерением может быть тип файла — PNG, JPG, GIF и т. д.


person Jasiu    schedule 08.07.2011    source источник


Ответы (2)


Вы можете использовать $(eval) здесь:

RESOLUTIONS=highres lowres
COLORS=color bw
PNG_FILES = $(foreach r, $(RESOLUTIONS), $(foreach c, $(COLORS), img-$(r)-$(c).png))

all: $(PNG_FILES)

# Make the rules for converting the svg into each variant.

define mkrule
img-$1-$2.png: img.svg
    @convert --$1 --$2 --output $$@ $$<
endef
$(foreach color,$(COLORS),$(foreach res,$(RESOLUTIONS),$(eval $(call mkrule,$(res),$(color)))))

$(eval) позволяет вам динамически создавать и вставлять фрагменты make-файла в анализируемый make-файл. Вы должны быть в состоянии расширить это с таким количеством различных измерений, как вам нравится.

person Eric Melski    schedule 08.07.2011

Вы можете использовать один % и «распаковать» $* с помощью функций обработки текста, например:

$(filter img-%.png, $(PNG_FILES)): img-%.png: img.svg
    convert $(addprefix --,$(subst -, ,$*)) --output $@ $<

$(subst) разбивает $* на слова в -, а $(addprefix) воздействует на каждое слово по очереди. Бонус: то же правило будет работать и для более чем двух измерений, если ни один из используемых вами флагов не содержит - :-)

person slowdog    schedule 08.07.2011