Makefile:如何为所有与模式匹配的目标声明依赖项?

时间:2019-03-28 21:37:24

标签: makefile

我的目标中的某些文件依赖于其他目标。我可以通过添加像这样的显式规则来确保正确的构建:

static/app.mjs: js2/.legacy_app.built.mjs
static/admin_unit.mjs: js2/.legacy_admin.built.mjs
static/admin_source.mjs: js2/.legacy_admin.built.mjs
static/admin_module.mjs: js2/.legacy_admin.built.mjs

但这意味着每次我向项目中添加新的“ admin_X”源时都要更改Makefile。我想做的是制定一个全面的模式规则,例如:

static/app.mjs: js2/.legacy_app.built.mjs
static/admin_%.mjs: js2/.legacy_admin.built.mjs

但这不起作用,如https://stackoverflow.com/a/3734705/179583所述:

  

完全没有配方的模式规则被记录为含义完全不同的东西[...:],它们取消了任何预先存在的隐式规则

是否有一种干净的方法来指定“与特定模式匹配的任何目标”取决于某个特定的其他目标?

3 个答案:

答案 0 :(得分:1)

如果所有这些文件已存在于文件系统中(即不应该由make从头开始构建),则可以使用$(wildcard ...)

$(wildcard static/admin_*.mjs): js2/.legacy_admin.built.mjs

答案 1 :(得分:0)

您知道,模式规则如下:

static/admin_%.mjs: js2/.legacy_admin.built.mjs
    recipe...

不指定任何目标,仅用于发现的模板 您指定否则的目标的先决条件, 并附有根据前提条件制定这些目标的方法。

因此,您的makefile中必须有 else 来确定 目标是什么。假设它只是一个列表,如:

$ cat Makefile
MJS_STEMS := app admin_unit admin_source admin_module
MJS_FILES := $(addprefix static/,$(MJS_STEMS:%=%.mjs))

.PHONY: all clean
all: $(MJS_FILES)

$(MJS_FILES): js2/.legacy_admin.built.mjs

static/%.mjs: | static
    @echo $< > $@
    @echo "$@ depends on $<"

js2/.legacy_admin.built.mjs: | js2
    touch $@

static js2:
    mkdir -p $@

clean:
    $(RM) $(MJS_FILES) js2/.legacy_admin.built.mjs

在这里

$(MJS_FILES): js2/.legacy_admin.built.mjs

$(MJS_FILES)中的每一个都取决于js2/.legacy_admin.built.mjs。 这是没有模式规则的最简洁方法。 make运行如下:

$ make
mkdir -p static
mkdir -p js2
touch js2/.legacy_admin.built.mjs
static/app.mjs depends on js2/.legacy_admin.built.mjs
static/admin_unit.mjs depends on js2/.legacy_admin.built.mjs
static/admin_source.mjs depends on js2/.legacy_admin.built.mjs
static/admin_module.mjs depends on js2/.legacy_admin.built.mjs

如果需要,可以将MJS_STEMS列表的维护移出 将makefile转换为另一个文件:

$ cat ./mjs_stems
app
admin_unit
admin_source
admin_module

$ cat Makefile
MJS_STEMS := $(shell cat ./mjs_stems)
MJS_FILES := $(addprefix static/,$(MJS_STEMS:%=%.mjs))

.PHONY: all clean
all: $(MJS_FILES)

$(MJS_FILES): js2/.legacy_admin.built.mjs

static/%.mjs: | static
    @echo $< > $@
    @echo "$@ depends on $<"

js2/.legacy_admin.built.mjs: | js2
    touch $@

static js2:
    mkdir -p $@

clean:
    $(RM) $(MJS_FILES) js2/.legacy_admin.built.mjs


$ make clean
rm -f static/app.mjs static/admin_unit.mjs static/admin_source.mjs static/admin_module.mjs js2/.legacy_admin.built.mjs

$ echo "admin_foobar" >> mjs_stems
$ make
touch js2/.legacy_admin.built.mjs
static/app.mjs depends on js2/.legacy_admin.built.mjs
static/admin_unit.mjs depends on js2/.legacy_admin.built.mjs
static/admin_source.mjs depends on js2/.legacy_admin.built.mjs
static/admin_module.mjs depends on js2/.legacy_admin.built.mjs
static/admin_foobar.mjs depends on js2/.legacy_admin.built.mjs

或者您也可以从环境中获取MJS_STEMS列表:

$ cat Makefile
MJS_STEMS := $(strip $(MJS_STEMS))
MJS_FILES := $(addprefix static/,$(MJS_STEMS:%=%.mjs))

.PHONY: all clean
all: $(MJS_FILES)

$(MJS_FILES): js2/.legacy_admin.built.mjs

static/%.mjs: | static
    @echo $< > $@
    @echo "$@ depends on $<"

js2/.legacy_admin.built.mjs: | js2
    touch $@

static js2:
    mkdir -p $@

clean:
    $(RM) $(MJS_FILES) js2/.legacy_admin.built.mjs


$ make clean
rm -f static/app.mjs static/admin_unit.mjs static/admin_source.mjs static/admin_module.mjs static/admin_foobar.mjs js2/.legacy_admin.built.mjs

$ export MJS_STEMS=$(cat ./mjs_stems)
$ make
touch js2/.legacy_admin.built.mjs
static/app.mjs depends on js2/.legacy_admin.built.mjs
static/admin_unit.mjs depends on js2/.legacy_admin.built.mjs
static/admin_source.mjs depends on js2/.legacy_admin.built.mjs
static/admin_module.mjs depends on js2/.legacy_admin.built.mjs
static/admin_foobar.mjs depends on js2/.legacy_admin.built.mjs

$ make clean
rm -f static/app.mjs static/admin_unit.mjs static/admin_source.mjs static/admin_module.mjs static/admin_foobar.mjs js2/.legacy_admin.built.mjs

$ export MJS_STEMS="aa bb cc"
$ make
touch js2/.legacy_admin.built.mjs
static/aa.mjs depends on js2/.legacy_admin.built.mjs
static/bb.mjs depends on js2/.legacy_admin.built.mjs
static/cc.mjs depends on js2/.legacy_admin.built.mjs

$ make clean
rm -f static/aa.mjs static/bb.mjs static/cc.mjs js2/.legacy_admin.built.mjs

但是在某处,您必须指定目标列表,并且 要添加新目标,您必须进行更新。

答案 2 :(得分:0)

在所有相关文件都是通过自己的特定配方构建的特殊情况下,我发现了另一种技巧。即在通常情况下,此操作无效不起作用,除非您已拆分或可以为所讨论的目标重复单独的配方。

当然,通过虚假目标绑定公共依赖关系很简单。此ADMIN目标取决于共享的中间文件,然后依次将其指定为模式匹配配方的先决条件:

.PHONY: ADMIN
ADMIN: js2/.legacy_admin.built.mjs

static/admin_%.mjs static/admin_%.mjs.map: js2/admin_%.build.mjs ADMIN FORCE
    node_modules/.bin/rollup --config rollup.config.js $< --format esm --sourcemap -o $@

# …also contains recipe to build "js2/.legacy_admin.built.mjs" itself

现在在构建任何 static/admin_%.mjs文件之前,请确保已创建公共js2/.legacy_admin.built.mjs帮助文件。

(请参见when multiple pattern rules match a target,了解Make的各种版本如何选择要使用的食谱。)