【问题标题】:replacement in makefile pattern rulemakefile 模式规则中的替换
【发布时间】:2018-06-25 21:27:14
【问题描述】:

我有这样的文件:

IMAGES=img_some_name_1.png img_somename_2.png img_some_other_name_1.png ...

前两个是由脚本构建的

some_name.py

第三个由

some_other_name.py

等等。我想写这样的makefile规则

%.png: $(remove 'img_' and replace '_?.png' with '.py')
    python $<

如何在依赖项中进行替换?我认为这个answer 是在正确的轨道上,但是如何用通配符进行更复杂的替换?

【问题讨论】:

    标签: makefile


    【解决方案1】:

    Make 的主要缺点之一是它无法以合理的方式处理通配符。

    这是一种粗略但有效的方法。使用 Make 的 string manipulation functions 将目标拆分为多个部分(例如“img somename 1”)并选择第二个,然后添加“.py”。并且不要忘记使用.SECONDEXPANSION 将所有这些推迟到通配符实际具有值为止。

    .SECONDEXPANSION:
    %.png: $$(word 2,$$(subst _, ,%)).py
        python $<
    

    编辑:如果目标名称可以包含下划线,那么模式规则方法会变得非常笨拙。这是一个更好的方法。假设我们只有一个目标,img_some_name_1.png,那么我们可以这样写规则:

    img_some_name_1.png: some_name.py
        python $<
    

    现在我们想变得聪明(和懒惰),让 Make 从目标名称构造脚本名称:

    IMAGE := img_some_name_1.png
    SCRAP := $(lastword $(subst _, ,$(IMAGE))) # this is 1.png
    SCRIPT := $(patsubst img_%_$(SCRAP),%.py, $(IMAGE)) # this is some_name.py
    
    $(IMAGE): $(SCRIPT)
        @echo python $<
    

    我们不想为每个目标都输入所有这些,所以我们定义了一个模板:

    define thing
    IMAGE := $(1)
    SCRAP := $$(lastword $$(subst _, ,$$(IMAGE)))
    SCRIPT := $$(patsubst img_%_$$(SCRAP),%.py, $$(IMAGE))
    
    $$(IMAGE): $$(SCRIPT)
        python $$<
    endef
    
    $(eval $(call thing, img_some_name_1.png))
    

    一旦我们确认了这么多工作(在我们的 Make 版本上),我们就会遍历目标列表:

    IMAGES=img_some_name_1.png img_somename_2.png img_some_other_name_1.png
    
    allImages: $(IMAGES)
    
    $(foreach IMAGE, $(IMAGES), $(eval $(call thing, $(IMAGE))))
    

    【讨论】:

    • 谢谢,但实际上名称中有更多(可变数字)下划线 - 我更新了我原来的问题。
    • @JohnSmith:这极大地改变了问题。我可以看到一个解决方案,但需要一些时间才能写出来......
    • 是的,我是这么认为的。我应该从一开始就更清楚。谢谢!我想最好再添加一个新答案,因为这个答案也非常有用。
    • 逐步尝试最新答案,我在第三个代码块中遇到问题。使用@echo 给了我SCRIPT=img_myscript_1_1.png,所以patsubst 显然什么都不做,而是将其更改为some_name.py。但是SCRAP 有效,这给了我1.png
    • @JohnSmith:你确定它会给你img_myscript_1_1.png吗?字符串myscript 没有出现在该代码块中。你到底做了什么?
    【解决方案2】:

    如果您愿意动态构建规则,您可以使用glob-match function from gmtt。您可以尝试按照@Beta 的建议将所有内容都塞进.SECONDEXPANSIONexpression,但我认为这会变得非常难看。

    include gmtt.mk
    IMAGES = img_some_name_1.png img_somename_2.png img_some_other_name_1.png
    $(info $(foreach fname,$(IMAGES),$(call glob-match,$(fname),img_*_?.png)))
    

    输出:

    img_ some_name _ 1 .png img_ somename _ 2 .png img_ some_other_name _ 1 .png
    

    现在我试过了,毕竟看起来没那么难看(*):

    %.png: $$(word 2,$$(call glob-match,%,img_*_?)).py
    

    但是,如果您的字符串构建约定涉及更多,它仍然会变得令人讨厌。

    (*) 从 GNUmake 编程的角度来看“丑陋”的任何定义。

    【讨论】:

    • 这似乎对我不起作用。 make img_myscript_1_1.png 只是说make: Nothing to be done for 'img_myscript_1_1.png'. 如果我删除它,它会说No rule to make target img_myscript_1_1.png'。`
    • 抱歉,将多余的.png% 匹配。由于 % 仅在词干中,因此不会为先决条件提供文件扩展名。编辑答案。
    • 好的,现在它会构建它,但是每次都会构建它。为什么在我更改 python 脚本之前它不会停止重建它?我有规则all: $(IMAGES)
    • 作为一个非常基本的“制定”判断,每次执行规则,直到其先决条件被人为地更新到新的日期,这意味着规则目标不会得到更新。当他们的规则执行时,'.png's 是否会获得新的构建时间?如果在配方中添加touch $@ 会有什么反应?
    • 是的,他们是。但我认为重新运行它与另一条规则有关。我现在解决了另一个问题并接受了这个问题,因为它不需要额外的文件 (gmat.mk),但无论如何谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多