GNU make com muitos diretórios de destino
-
06-09-2019 - |
Pergunta
Eu tenho a integrar a geração de muitos arquivos HTML em uma Makefile
existente.
O problema é que os arquivos HTML precisam residir em muitos diretórios diferentes.
Minha idéia é escrever uma regra implícita que converte o arquivo fonte (* .st) para o arquivo html correspondente
%.html: %.st
$(HPC) -o $@ $<
e uma regra que depende de todos os arquivos html
all: $(html)
Se o arquivo HTML não está no make
builddir não encontra a regra implícita: *** No rule to make target
.
Se eu alterar a regra implícita como assim
$(rootdir)/build/doc/2009/06/01/%.html: %.st
$(HPC) -o $@ $<
é encontrado, mas então eu tenho que ter uma regra implícita para quase todos os arquivos no projeto.
De acordo com a implícita Regra Pesquisa Algoritmo na GNU make
Manual, pesquisa regra funciona assim:
- Split t em uma parte do diretório, chamado d, eo resto, chamado n. Para exemplo, se T é
src/foo.o', then d is
src / 'e n é `foo.o'.- Faça uma lista de tudo o padrão governa um de cujos alvos corresponde t ou n. Se o padrão de destino contém uma slash, que é comparado com t; caso contrário, contra o n.
Porque é que a regra implícita não encontrado, e qual seria a solução mais elegante, assumindo GNU make
é usado?
Aqui está uma versão simplificada da minha 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)
Solução
Como Maria Shalnova I como fazer recursiva (embora eu não concordar com "Make recursiva considerada prejudicial") e, em geral, é melhor fazer alguma coisa aqui de uma fonte LÁ, não o inverso. Mas se você deve, eu sugiro uma ligeira melhoria:. Tem generateHtml gerar apenas a regra, não os comandos
Outras dicas
A melhor solução que eu encontrei até agora é para gerar uma regra implícita per diretório de destino através de foreach-eval-call , como explicado na GNU make
manual do . Eu não tenho nenhuma idéia de como isso escalas a alguns milhares de diretórios de destino, mas vamos ver ...
Se você tiver uma solução melhor, por favor, postá-lo!
Aqui está o código:
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)
A sua regra implícita ativo faz $(rootdir)/build/doc/2009/06/01/some.html
dependem $(rootdir)/build/doc/2009/06/01/some.st
. Se $(rootdir)/build/doc/2009/06/01/some.st
não existe, então a regra não será usado / encontrado.
A regra comentada faz $(rootdir)/build/doc/2009/06/01/some.html
dependem some.st
.
Uma solução é fazer com que você está fonte layout corresponde à sua disposição destino / resultado.
Outra opção é criar as regras, conforme necessário com eval
. Mas isso vai ser bastante complicado:
define HTML_template
$(1) : $(basename $(1))
cp $< $@
endef
$(foreach htmlfile,$(html),$(eval $(call HTML_template,$(htmlfile))))
Uma outra possibilidade é ter a própria chamada make
comando recursivamente com o -C discussão com cada diretório de saída.
make
recursiva é um pouco a maneira padrão de lidar com subdiretórios, mas cuidado com as implicações mencionadas no artigo "recursiva Marca considerada prejudicial"