【问题标题】:GNU make with many target directories具有许多目标目录的 GNU make
【发布时间】:2009-06-01 09:30:16
【问题描述】:

我必须在现有的Makefile 中集成许多 HTML 文件的生成。 问题是 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 手册中的 Implicit Rule Search Algorithm,规则搜索的工作方式如下:

  1. 将整个目标名称 t 拆分为目录部分,称为 d,其余部分称为 n。为了 例如,如果 tsrc/foo.o, 那么 dsrc/nfoo.o
  2. 列出所有目标匹配tn 的模式规则。 如果目标模式包含斜线, 它与 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)

【问题讨论】:

    标签: makefile release-management gnu-make build-management


    【解决方案1】:

    到目前为止,我发现的最佳解决方案是通过foreach-eval-call 为每个目标目录生成一个隐式规则,如GNU make manual 中所述。我不知道这如何扩展到几千个目标目录,但我们会看到......

    如果您有更好的解决方案,请发布!

    代码如下:

    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)
    

    【讨论】:

    • 除了使用某种形式的 call-foreach-eval 之外,我看不到任何其他解决方案。 GNU make 不能很好地处理这种目录布局。 (事实上​​,最初的 make 或多或少假设您将所有源代码都放在一个目录中。)
    【解决方案2】:

    和 Maria Shalnova 一样,我喜欢递归制作(尽管我不同意“递归制作被认为是有害的”),而且总的来说,最好从那里的来源制作一些东西,而不是相反。但如果必须的话,我建议稍微改进一下:让 generateHtml 只生成 RULE,而不是 COMMANDS。

    【讨论】:

      【解决方案3】:

      您的主动隐式规则使$(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))))
      

      【讨论】:

      • 可以,但不幸的是源布局是固定的,真正的 Makefile 使用 VPATH。
      【解决方案4】:

      另一种可能性是让突击队make 在每个输出目录中使用参数 -C 递归调用自身。 递归make 在某种程度上是处理子目录的标准方法,但请注意文章“递归使认为有害”中提到的含义

      【讨论】:

      • 好的,递归 make 没有出现在我的脑海中。您的解决方案将非常便携。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多