I have to integrate the generation of many HTML files in an existing Makefile
.
The problem is that the HTML files need to reside in many different directories.
My idea is to write an implicit rule that converts the source file (*.st) to the corresponding html file
%.html: %.st
$(HPC) -o $@ $<
and a rule that depends on all html files
all: $(html)
If the HTML file is not in the builddir make
doesn't find the implicit rule: *** No rule to make target
.
If I change the implicit rule like so
$(rootdir)/build/doc/2009/06/01/%.html: %.st
$(HPC) -o $@ $<
it's found, but then I have to have an implicit rule for nearly every file in the project.
According to Implicit Rule Search Algorithm in the GNU make
manual, rule search works like this:
- Split t into a directory part, called d, and the rest, called n. For example, if t is
src/foo.o', then d is
src/' and n is `foo.o'.- Make a list of all the pattern rules one of whose targets matches t or n. If the target pattern contains a slash, it is matched against t; otherwise, against n.
Why is the implicit rule not found, and what would be the most elegant solution, assuming GNU make
is used?
Here is a stripped down version of my 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)
Like Maria Shalnova I like recursive make (though I disagree with "Recursive Make Considered Harmful"), and in general it's better to make something HERE from a source THERE, not the reverse. But if you must, I suggest a slight improvement: have generateHtml generate only the RULE, not the COMMANDS.
Your active implicit rule makes
$(rootdir)/build/doc/2009/06/01/some.html
depend on$(rootdir)/build/doc/2009/06/01/some.st
. If$(rootdir)/build/doc/2009/06/01/some.st
doesn't exist then the rule won't be used/found.The commented out rule makes
$(rootdir)/build/doc/2009/06/01/some.html
depend onsome.st
.One solution is to make you're source layout match your destination/result layout.
Another option is to create the rules as required with
eval
. But that will be quite complicated:An other possibility is to have the commando
make
call itself recursively with the argument -C with every output directory. Recursivemake
is somewhat the standard way to deal with subdirectories, but beware of the implications mentioned in the article "Recursive Make Considered Harmful"The best solution I found so far is to generate an implicit rule per target directory via foreach-eval-call, as explained in the GNU
make
manual. I have no idea how this scales to a few thousand target directories, but we will see...If you have a better solution, please post it!
Here is the code: