Вопрос

Мне нужно интегрировать создание множества HTML-файлов в существующий Makefile.Проблема в том, что файлы HTML должны находиться во многих разных каталогах.Моя идея состоит в том, чтобы написать неявное правило, которое преобразует исходный файл (*.st) в соответствующий html-файл.

%.html: %.st
    $(HPC) -o $@ $<

и правило, которое зависит от всех html-файлов

all: $(html)

Если HTML-файл отсутствует в каталоге сборки make не находит неявное правило: *** No rule to make target.Если я изменю неявное правило вот так

$(rootdir)/build/doc/2009/06/01/%.html: %.st  
    $(HPC) -o $@ $<

оно найдено, но тогда мне нужно иметь неявное правило почти для каждого файла в проекте.В соответствии с Алгоритм неявного поиска правил в ГНУ make вручную, поиск по правилам работает следующим образом:

  1. Разделите t на часть каталога с именем d и остальную часть с именем n.Например, если T src/foo.o', then d issrc/», а n — «foo.o».
  2. Составьте список всех шаблонных правил, одна из целей которых соответствует t или n.Если целевой шаблон содержит черту, он сочетается с T;в противном случае, против n.

Почему неявное правило не найдено и какое решение было бы наиболее элегантным, если предположить, что 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)
Это было полезно?

Решение

Как и Мария Шальнова, мне нравится рекурсивный make (хотя я не согласен с «Рекурсивный Make считается вредным»), и вообще лучше сделать что-то ЗДЕСЬ из источника ТАМ, а не наоборот.Но если вам необходимо, я предлагаю небольшое улучшение:заставитьgenerHtml генерировать только ПРАВИЛО, а не КОМАНДЫ.

Другие советы

Лучшее решение, которое я нашел на данный момент, — это создать неявное правило для каждого целевого каталога через foreach-eval-вызов, как поясняется в ГНУ 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 это в некоторой степени стандартный способ работы с подкаталогами, но остерегайтесь последствий, упомянутых в статье «Рекурсивное использование считается вредным».

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top