我需要帮助修改makefile中的依赖项

时间:2011-10-30 21:23:02

标签: makefile gnu-make

我创建了一个用于生成简单网页的makefile。 makefile背后的想法是:

  • 我们正在编制一个网页index.html
  • index.html需要必须编译的手写笔css main.sty
  • 页面中使用了许多示例
    • 例如one的代码位于lib/examples/one
    • 每个示例包含三个部分
      • 标记(.jade模板文件)
      • 部分代码(.coffee脚本文件)
      • 说明(.md降价文件)
  • 构建脚本必须将每个示例呈现为单个html文件
    • Jade,Pygments和Markdown用于生成三个html文件
    • example.jade模板用于将这些模板合并为一个示例文件
        必须将
      • example.jade复制到正确的构建示例目录,因为模板语言只能执行相对导入。因此,为了导入example/one/code.html,我们必须将模板复制到example/one并将其包含code.html
    • 完成后,每个示例x都会编译为tbuild/examples/x.html
  • lib/index.jade模板已移至build(以便其中包含示例文件)
  • 然后使用Jade将index.jade模板编译为html

这是一个简化,但这种方式更容易理解。简化的是每个示例中实际上有两个标记文件(left.html和right.html),并且代码文件都通过用作的pygments运行一个脚本,所以code.html和code.coffee都需要进行构建。

现在,makefile看起来像这样:

LIB = lib
BUILD = build
LIBEX = $(LIB)/examples
BUILDEX = $(BUILD)/examples
EXAMPLES = $(addsuffix .html,$(addprefix $(BUILDEX)/,$(shell ls $(LIBEX) | grep -v '.jade')))

all: $(BUILD)/main.css index.html

index.html: $(BUILD)/index.jade $(EXAMPLES)
    jade < $< --path $< > $@

$(BUILD)/index.jade: $(LIB)/index.jade
    mkdir -p $(@D)
    cp $< $@

$(BUILD)/main.css: $(LIB)/main.sty
    mkdir -p $(@D)
    stylus -u nib < $< > $@

$(BUILDEX)/%.html: $(BUILDEX)/%/template.jade $(BUILDEX)/%/left.html $(BUILDEX)/%/right.html $(BUILDEX)/%/code.html $(BUILDEX)/%/code.coffee $(BUILDEX)/%/text.html
    jade < $< --path $< > $@

$(BUILDEX)/%/template.jade: $(LIBEX)/template.jade
    mkdir -p $(@D)
    cp $< $@

$(BUILDEX)/%/left.html: $(LIBEX)/%/left.jade
    jade < $< --path $< > $@

$(BUILDEX)/%/right.html: $(LIBEX)/%/right.jade
    jade < $< --path $< > $@

$(BUILDEX)/%/code.html: $(LIBEX)/%/code.coffee
    pygmentize -f html -o $@ $<

$(BUILDEX)/%/code.coffee: $(LIBEX)/%/code.coffee
    mkdir -p $(@D)
    cp $< $@

$(BUILDEX)/%/text.html: $(LIBEX)/%/text.md
    markdown < $< > $@

clean:
    rm index.html -f
    rm $(BUILD) -rf

这样可行,但问题是当我触摸“lib / examples / intro / code.coffee”并重新运行make时,我会得到以下结果:

mkdir -p build/examples/intro
cp lib/examples/template.jade build/examples/intro/template.jade
jade < lib/examples/intro/left.jade --path lib/examples/intro/left.jade > build/examples/intro/left.html
jade < lib/examples/intro/right.jade --path lib/examples/intro/right.jade > build/examples/intro/right.html
pygmentize -f html -o build/examples/intro/code.html lib/examples/intro/code.coffee
mkdir -p build/examples/intro
cp lib/examples/intro/code.coffee build/examples/intro/code.coffee
markdown < lib/examples/intro/text.md > build/examples/intro/text.html
jade < build/examples/intro/template.jade --path build/examples/intro/template.jade > build/examples/intro.html
jade < build/index.jade --path build/index.jade > index.html
rm build/examples/intro/right.html build/examples/intro/code.coffee build/examples/intro/code.html build/examples/intro/left.html build/examples/intro/text.html build/examples/intro/template.jade

正如您将注意到的那样,重新生成示例的方式远不止这些。我希望的是更像这样的东西:

mkdir -p build/examples/intro
pygmentize -f html -o build/examples/intro/code.html lib/examples/intro/code.coffee
cp lib/examples/intro/code.coffee build/examples/intro/code.coffee
jade < build/examples/intro/template.jade --path build/examples/intro/template.jade > build/examples/intro.html
jade < build/index.jade --path build/index.jade > index.html

换句话说,我要问的是:

  1. 当我改变一些小东西时,我需要做什么才能使makefile不会重建太多?
    • 在上面的示例中,当我触摸code.coffee时,都会重建left.html,right.html和text.html。我该如何防止这种情况?
  2. 为什么make将rm命令放在输出的末尾?这似乎可能导致一些不必要的重建。
  3. 感谢您一直阅读这个问题的野兽!我知道我的make-fu缺乏,所以关于如何清理makefile和减少冗余的任何提示都非常受欢迎!

3 个答案:

答案 0 :(得分:4)

这个构建系统太大而且很复杂,无法轻松复制 - 我讨厌发布我没有测试过的解决方案 - 但是尝试添加这一行:

.SECONDARY:

修改:
我无法重现你描述的行为,但我可以提供一些指示。

.SECONDARY:是一条规则;它可以在makefile中的任何地方。基本上,如果Make检测到一系列隐式规则链,A-> B-> C,其中A是存在的文件而C是目标,则它认为B是中间文件和一旦工作完成,将删除它。 .SECONDARY:规则会阻止删除。

您可以组合具有相同命令的规则。这样:

foo: bar
    do something $< $@

baz: quartz
    do something $< $@

quince: geef
    do something $< $@

可以改写为:

foo: bar

baz: quartz

quince: geef

foo baz quince:
    do something $< $@

这将消除makefile中的大量冗余,并且可能会使事情变得更清晰。

答案 1 :(得分:2)

就像@Beta提到的那样,你在这里遇到了中间文件的麻烦。

Makefile中未明确提及的每个文件,而是通过模式规则(具有%的规则)推断的,是中间文件,并在make run后立即删除。然后在下一次运行中重新制作。

这是您“问题”的核心:立即删除left.html和right.html文件。 Beta已经提到将它们声明为.SECONDARY可以修复此问题,例如the make manual tells you

通过在Makefile中的任何地方声明目标.SECONDARY而没有任何先决条件(确实:在任何地方),您将所有目标声明为辅助目标 - 因此,不会自动删除。

答案 2 :(得分:1)

您还可以将PHONY用于非文件的目标,以提高性能。与allclean一样。有关详细信息,请参阅此处:What is the purpose of .PHONY in a makefile?