【问题标题】:Makefile: how to declare a dependency for all targets that match a pattern?Makefile:如何为与模式匹配的所有目标声明依赖关系?
【发布时间】:2019-03-28 21:37:24
【问题描述】:

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

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所解释的那样:

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

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

【问题讨论】:

    标签: makefile


    【解决方案1】:

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

    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
    

    但无论如何,您必须在某处指定目标列表,并且 要添加新目标,您必须更新一些内容。

    【讨论】:

    • 谢谢。我不认为它直接回答了我的问题,但如果不是,那部分原因是我遗漏了一些背景:我已经通过appfiles = $(shell ls -1 js2/*.build.mjs)js2: $(appfiles:js2/%.build.mjs=static/%.mjs) 生成了目标文件列表[我忘记是否有原因将其拆分为超出可读性。] 因此,在这种情况下,我只是试图干净地“调出”其中一些具有额外依赖关系。正如@Matt 下面提醒的那样,我应该能够使用类似的ls -1/substitution 技巧来生成子列表。
    【解决方案2】:

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

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

    【讨论】:

    • 不幸的是,在我的情况下,static/admin_*.mjs 目标是这个 Makefile 的一些最终产品,并且不会总是存在,例如在我的make clean之后。
    • 啊,但正如@MikeKinghan 在他的回答中提出的那样——我可以根据不同的通配符模式(例如src/admin_*.build.mjs)找出应该存在哪些文件,这样我就可以可能将其与替换结合起来。
    【解决方案3】:

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

    当然,通过虚假目标绑定公共依赖项是一件简单的事情。这个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 文件被构建之前,make 确保公共的js2/.legacy_admin.built.mjs 帮助文件已经被创建。

    (请参阅when multiple pattern rules match a target 了解有关不同版本的 Make 如何选择要使用的配方的背景信息。)

    【讨论】:

      猜你喜欢
      • 2013-05-25
      • 2020-01-19
      • 1970-01-01
      • 2019-08-16
      • 1970-01-01
      • 1970-01-01
      • 2013-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多