GNU make со многими целевыми каталогами - PullRequest
4 голосов
/ 01 июня 2009

Я должен интегрировать генерацию многих 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, поиск правил работает следующим образом:

  1. Разделите t на часть каталога с именем d, а остальные с именем n. За Например, если t равно src/foo.o', then d is src / ', а n равно `foo.o'.
  2. Составьте список всех шаблонных правил, одно из целей которых соответствует 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)

Ответы [ 4 ]

4 голосов
/ 19 июня 2009

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

4 голосов
/ 01 июня 2009

Лучшее решение, которое я нашел до сих пор, - это создать неявное правило для целевого каталога с помощью 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)
4 голосов
/ 01 июня 2009

Ваше активное неявное правило делает $(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))))
3 голосов
/ 01 июня 2009

Другая возможность состоит в том, чтобы команда make рекурсивно вызывала себя с аргументом -C для каждого выходного каталога. Рекурсивный make является в некоторой степени стандартным способом работы с подкаталогами, но остерегайтесь последствий, упомянутых в статье «Рекурсивное использование считается вредным»

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...