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

Makefile:如何声明与模式匹配的所有目标的依赖关系?,makefile,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 但这意味着每次向项

我的目标中的某些文件依赖于其他目标。我可以通过添加如下明确规则来确保正确的构建:

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”源时都要更改生成文件。我想做的是有一个全面的模式规则,如:

static/app.mjs: js2/.legacy_app.built.mjs
static/admin_%.mjs: js2/.legacy_admin.built.mjs
static/admin_%.mjs: js2/.legacy_admin.built.mjs
    recipe...
但这不起作用,如下所述:

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


是否有一种明确的方法来指定“任何与特定模式匹配的目标”依赖于某个特定的其他目标?

如果文件系统中已经存在所有这些文件(即,不应该由从头开始生成),则可以使用
$(通配符…


如您所知,模式规则如下:

static/app.mjs: js2/.legacy_app.built.mjs
static/admin_%.mjs: js2/.legacy_admin.built.mjs
static/admin_%.mjs: js2/.legacy_admin.built.mjs
    recipe...
不指定任何目标,只是用于发现的模板 您另外指定的目标的先决条件, 根据先决条件制定这些目标的方法

因此,在您的makefile中必须有其他决定 目标是什么。假设它只是一个列表,如中所示:

$ 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\u文件)
依赖于
js2/.legacy\u admin.build.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\u杆的维护从列表中移出
将文件转换为另一个文件:

$ 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
但无论如何,在某个地方,你必须指定目标列表
要添加新的目标,您必须更新一些内容。

我发现了另一个技巧,在特殊情况下,所有相关文件都是通过它们自己的特定配方构建的。也就是说,在一般情况下,这将不起作用,除非您已经拆分或可以为相关目标复制单独的配方

承认这一点,只需通过一个虚假的目标将公共依赖性绑定起来。此
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

.PHONY:ADMIN
ADMIN:js2/.legacy_ADMIN.build.mjs
static/admin\%.mjs static/admin\%.mjs.map:js2/admin\%.build.mjs管理力量
node_modules/.bin/rollup--config rollup.config.js$<--format esm--sourcemap-o$@
#…还包含构建“js2/.legacy_admin.build.mjs”本身的方法
现在,在生成任何
static/admin\uu%.mjs
文件之前,make确保已创建公共
js2/.legacy\u admin.builded.mjs
帮助文件


(有关Make的各种版本如何选择使用哪种配方的一些背景信息,请参阅。)

不幸的是,在我的情况下,
静态/admin_*.mjs
目标是此Make文件的一些最终产品,并且不会始终出现,例如在我的
Make clean
之后。啊,但正如@MikeKinghan在他的回答中所提到的那样,我可以根据不同的通配符模式(例如,
src/admin\u*.build.mjs
)计算出应该存在哪些文件,所以我可以将其与替换结合起来。谢谢。我不认为它直接回答了我的问题,但如果不是这样的话,那一定程度上是因为我遗漏了一些背景:我已经通过
appfiles=$(shell ls-1js2/*.build.mjs)
js2:$(appfiles:js2/%.build.mjs=static/%.mjs)
[我忘了是否有理由将其拆分为可读性以外的内容。]因此,在这种情况下,我只想清楚地“调用”其中一些内容,因为它们具有额外的依赖关系。正如@Matt在下面提醒的那样,我应该能够使用类似的
ls-1
/替换技巧来生成子列表。
.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