GNU make with many target directories

南楼画角 提交于 2019-12-04 13:47:53

问题


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:

  1. Split t into a directory part, called d, and the rest, called n. For example, if t is src/foo.o', then d issrc/' and n is `foo.o'.
  2. 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)

回答1:


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.




回答2:


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:

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)



回答3:


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 on some.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:

define HTML_template
 $(1) : $(basename $(1))
      cp $< $@
endef

$(foreach htmlfile,$(html),$(eval $(call HTML_template,$(htmlfile))))



回答4:


An other possibility is to have the commando make call itself recursively with the argument -C with every output directory. Recursive make is somewhat the standard way to deal with subdirectories, but beware of the implications mentioned in the article "Recursive Make Considered Harmful"



来源:https://stackoverflow.com/questions/934127/gnu-make-with-many-target-directories

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!