【问题标题】:Extract the part of string matched by % in Makefile提取Makefile中与%匹配的部分字符串
【发布时间】:2018-04-02 10:21:41
【问题描述】:

我正在做我的 CS 作业,其中包含许多单文件程序。我的工作目录如下所示:

133.c 134.c 220.c 281.c 337.c 338.c 339.c makefile

我写了一个这样的 Makefile:

%: %.c
    ${CC} ${CFLAGS} -o $@ $^

所以当我想编译第 220 题的程序时,我输入:

ibug@wsl:~ $ make 220
gcc  -o 220 220.c
ibug@wsl:~ $

问题

我想写一个 clean-% 规则,这样当我在 shell 中运行它时,结果应该如下所示

ibug@wsl:~ $ make clean-133
rm -f 133
ibug@wsl:~ $ make clean-281
rm -f 281
ibug@wsl:~ $ make clean-337
rm -f 337

我已经做到了这一点:

.PHONY: clean-%

SRC = $(wildcard %.c)
BIN = $(patsubst %.c,%,$(SRC))

clean-%:
    rm -f ??????

问号应该用什么代替?

我正在使用 GNU Make 4.1(在适用于 Linux 的 Windows 子系统上)。

【问题讨论】:

    标签: linux makefile gnu-make


    【解决方案1】:

    您正在寻找包含词干automatic variable $*(即与%匹配的部分):

    clean-%:
        rm -f $*
    

    但是,请继续阅读。


    虚假目标、模式和隐含规则

    将先决条件clean-% 添加到.PHONY 目标:

    .PHONY: clean-%
    

    不会将模式规则clean-%变成假目标,而是将显式规则,其实际目标名称是clean-%(不是模式),变成虚假目标。

    原因是只有显式规则的目标才能成为伪目标,模式不能成为伪目标。因此,看起来像模式(即包含 %)的虚假目标并不是真正的模式(即,% 实际上是 %)。

    添加所有可能的值 clean-% 可以匹配到 .PHONY 也无济于事,因为 假目标 匹配 隐式模式规则。所以,如果你这样做:

    .PHONY: clean-foo
    

    clean-foo 永远不会匹配隐式模式规则(即,它永远不会匹配您的 clean-% 模式规则)。


    clean-xxx 定义为虚假目标

    我猜你实际上希望这些clean-xxx 目标是虚假目标,因为这些目标并不代表文件系统上的实际文件。

    使用静态模式规则

    与隐式模式规则不同,static pattern rules 可以匹配虚假目标。以下方法包括定义一个可以匹配那些 clean-xxx 虚假目标的静态模式规则:

    list := $(patsubst %.c,%,$(wildcard *.c))
    
    # list of clean-xxx targets
    clean-targets := $(addprefix clean-,$(list))
    
    .PHONY: $(clean-targets)
    
    $(clean-targets): clean-%:
        rm -f $*
    

    上面的静态模式规则将匹配其目标列表中指定的任何clean-xxx 虚假目标(即$(clean-targets)

    使用显式规则

    以下方法包括将这些clean-xxx 规则动态生成为显式规则,而不是单个模式规则:

    list := $(patsubst %.c,%,$(wildcard *.c))
    
    define create-clean-target
        $(eval .PHONY: clean-$1);
        $(eval clean-$1:; rm -f $1)
    endef
    
    
    # dynamically generate the clean-xxx targets
    $(foreach t,$(list),$(call create-clean-target,$t))
    

    用户定义函数create-target 定义了一个显式 目标clean-xxx,即xxx 传递给函数的参数。由于这个要定义的目标是一个显式目标,所以它也可以是一个目标。

    【讨论】:

    • 你为什么要做所有这些调用和评估的东西?我真的认为应该避免这些高级主题,除非真正需要它们,尤其是对于刚刚学习的人。即使是有经验的 makefile 编写者也很难理解这些主题。 OP 想要的东西可以在不需要任何这些的情况下轻松完成,只需编写 .PHONY: $(addprefix clean-,$(list)) 和他们已经拥有的干净模式规则(使用 $*
    • @MadScientist 这是我最初的方法,但似乎在执行.PHONY: $(addprefix clean-,$(list) 之后,模式规则clean-% 不再匹配这些目标(模式规则似乎不匹配虚假目标)。我在这里遗漏了一些更基本的东西吗?
    • 您可能需要使用静态模式规则而不是普通模式规则:$(addprefix clean-,$(list)): clean-%: ; echo clean $*IMO 这仍然比 call/eval 更简单...
    • @MadScientist 太棒了!我同意,您使用静态模式规则的方法是最简单的方法。谢谢!
    【解决方案2】:

    使用您的文件命名约定您不需要任何makefile,因为GNU Make's built-in rules 已经可以满足您的需求。试试这个:

    $ mv Makefile Makefile.bak
    $ rm -f 220
    $ make 220       # make magic happening here!
    $ rm -f 220
    $ make CC=cc CFLAGS="-Wall -O2" 220
    

    如您所见,make 知道如何使用 C 编译器将 foo.c 转换为 foo 可执行文件。

    要检索内置规则列表,请在不存在 Makefile 的情况下运行 make -p

    至于清理您的可执行文件,为什么要如此冗长并在 rm -f NNNrm -f [0-9]?? 的输入量差不多时输入 make clean-NNN

    【讨论】:

    • make -p 给了我所需的一切。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 2015-12-31
    • 1970-01-01
    • 2017-04-11
    • 2021-09-29
    相关资源
    最近更新 更多