GNU make со многими целевыми каталогами
Я должен интегрировать генерацию многих файлов HTML в существующий Makefile
, Проблема в том, что файлы HTML должны находиться во многих разных каталогах. Моя идея состоит в том, чтобы написать неявное правило, которое преобразует исходный файл (*.st) в соответствующий HTML-файл
%.html: %.st
$(HPC) -o $@ $<
и правило, которое зависит от всех HTML-файлов
all: $(html)
Если файл HTML отсутствует в builddir make
не находит неявное правило: *** No rule to make target
, Если я изменю неявное правило так
$(rootdir)/build/doc/2009/06/01/%.html: %.st
$(HPC) -o $@ $<
это найдено, но тогда я должен иметь неявное правило почти для каждого файла в проекте. Согласно алгоритму поиска неявных правил в GNU make
ручной поиск правил работает так:
- Разделите t на часть каталога, называемую d, а остальные - n. Например, если т
src/foo.o', then d is
src/'и n это `foo.o'.- Составьте список всех шаблонных правил, одно из которых соответствует целям t или n. Если целевой шаблон содержит косую черту, он сопоставляется с t; в противном случае против п.
Почему неявное правило не найдено, и что было бы наиболее элегантным решением, если принять GNU make
используется?
Вот урезанная версия моего Makefile
:
rootdir = /home/user/project/doc
HPC = /usr/local/bin/hpc
html = $(rootdir)/build/doc/2009/06/01/some.html
%.html: %.st
$(HPC) -o $@ $<
#This works, but requires a rule for every output dir
#$(rootdir)/build/doc/2009/06/01/%.html: %.st
# $(HPC) -o $@ $<
.PHONY: all
all: $(html)
4 ответа
Как и Мария Шальнова, мне нравится рекурсивная сборка (хотя я не согласен с "Рекурсивной сборкой, считающейся вредной"), и вообще лучше сделать что-то ЗДЕСЬ из источника ТАМ, а не наоборот. Но если вы должны, я предлагаю небольшое улучшение: генерировать generateHtml только ПРАВИЛО, а не КОМАНДЫ.
Наилучшее решение, которое я нашел до сих пор, - это генерировать неявное правило для целевого каталога с помощью foreach-eval-call, как объяснено в GNU. make
ручной. Я понятия не имею, как это масштабируется до нескольких тысяч целевых каталогов, но мы увидим...
Если у вас есть лучшее решение, пожалуйста, опубликуйте его!
Вот код:
rootdir = /home/user/project/doc
HPC = /usr/local/bin/hpc
html = $(rootdir)/build/doc/2009/06/01/some.html \
$(rootdir)/build/doc/2009/06/02/some.html
targetdirs = $(rootdir)/build/doc/2009/06/01 \
$(rootdir)/build/doc/2009/06/02
define generateHtml
$(1)/%.html: %.st
-mkdir -p $(1)
$(HPC) -o $$@ $$<
endef
$(foreach targetdir, $(targetdirs), $(eval $(call generateHtml, $(targetdir))))
.PHONY: all
all: $(html)
Ваше активное неявное правило делает $(rootdir)/build/doc/2009/06/01/some.html
зависит от $(rootdir)/build/doc/2009/06/01/some.st
, Если $(rootdir)/build/doc/2009/06/01/some.st
не существует, тогда правило не будет использоваться / найдено.
Закомментированное правило делает $(rootdir)/build/doc/2009/06/01/some.html
зависит от some.st
,
Одно из решений - сделать так, чтобы исходный макет соответствовал макету назначения / результата.
Другой вариант - создать правила в соответствии с требованиями eval
, Но это будет довольно сложно:
define HTML_template
$(1) : $(basename $(1))
cp $< $@
endef
$(foreach htmlfile,$(html),$(eval $(call HTML_template,$(htmlfile))))
Другая возможность состоит в том, чтобы иметь коммандос make
рекурсивно вызывать себя с аргументом -C для каждого выходного каталога. рекурсивный make
в некоторой степени стандартный способ работы с подкаталогами, но остерегайтесь последствий, упомянутых в статье "Рекурсивное использование считается вредным"