动态Makefile目标

时间:2014-03-31 06:21:50

标签: makefile

这是我正在使用的GNU Makefile的片段。基本上,我有一个图像目录,我想在运行make时将其复制到dist目录中,但我不想单独列出每个图像。

DISTDIR := dist
IMG := $(shell find app/img -type f)
$(subst app/img, $(DISTDIR), $(filter-out %.svg, $(IMG)))): $(filter-out %.svg, $(IMG))
        @cp $? $(DISTDIR)

除了更改源文件(在app/img中)之外,此类工作会使始终重新生成目标文件。处理这种情况的正确方法是什么?

1 个答案:

答案 0 :(得分:2)

如果您为查找提供了一些示例结果,则会更容易回答。我们假设查找操作返回文件:app/img/foo.svgapp/img/bar.jpgapp/img/baz.png

在这种情况下,filter-out函数将返回文件app/img/bar.jpgapp/img/baz.png。这意味着生成的规则将如下所示:

$(DISTDIR)/bar.jpg $(DISTDIR)/baz.png: app/img/bar.jpg app/img/baz.png
        @cp $? $(DISTDIR)

事情就是这样:当您在显式规则中定义N个目标时,它就像定义N个规则,每个目标一个,具有所有相同的先决条件。所以上面的内容与写这个相同:

$(DISTDIR)/bar.jpg: app/img/bar.jpg app/img/baz.png
        @cp $? $(DISTDIR)
$(DISTDIR)/baz.png: app/img/bar.jpg app/img/baz.png
        @cp $? $(DISTDIR)

现在您可以看到为什么会得到您所执行的操作:每个目标都将 ALL 文件列为先决条件,因此每当 ANY 文件发生更改时,目标都会重建。

答案是,在make中,您通常应该尝试编写仅从该目标的先决条件中创建一个目标的规则。一种简单的方法是使用模式规则;上面的模式规则可能如下所示:

DISTDIR := dist

$(DISTDIR)/% : app/img/%
    @cp $< $@

之后,您所要做的就是声明一个取决于您想要创建的文件的目标:

IMG := $(shell find app/img -type f)

all: $(IMG:app/img/%=$(DISTDIR)/%)

并且make会弄明白其余的!