在Makefile中找不到模式规则

时间:2018-08-12 08:22:04

标签: c makefile

假设我有这个简约的 main.c 程序

int main(void)
{
    return 0;
}

和此 Makefile

.PHONY: %.run

%.run: %
    ./$<

如果我运行以下命令

make main.run

我希望这会

  1. main.c 中使 main 可执行(使用make默认隐式%: %.c规则)
  2. 执行 main
  3. 成功退出。

但是我得到的却是以下错误

make: *** No rule to make target 'main.run'.  Stop.

我尝试禁用默认的隐式规则,并使用设置自己的编译规则

.SUFFIXES:

%: %.c
    $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $<

但这没有帮助。

但是,在两种情况下,如果我先运行make main,然后运行make main.run,它就会按预期运行。但是运行%.run规则正是我要避免的两个命令。

当然,如果我用此显式规则替换模式规则

main.run: main
    ./main

正在工作。

此外,如果我将模式规则更改为带有可执行文件后缀 .x %.x: %.c%.run: %.x,这是可行的,但是我又不想后缀。

当然,我的问题不是要知道这是否是在一个命令中编译和运行程序的正确方法,而是要知道为什么此Makefile不能按我期望的方式执行。

1 个答案:

答案 0 :(得分:0)

Match Anything Rules对目标的类似限制似乎也适用于先决条件,尽管我在任何地方都找不到。

如果可执行文件main 已经存在,则OP的makefile:

%.run: %
    ./$<

完全正常。解决该问题的两种方法是:

  • 添加显式规则以构建main,或
  • 添加目标为main的空规则;这将导致main由隐式模式匹配规则或显式规则构建。

因此以下makefile可以工作(在GNU make上测试):

%.run: %
    ./$<

main:

此处main一词在makefile中进行了硬编码。您可以通过以下方式处理临时目标:

TARGETS = main.run foo.run bar.run $(filter %.run,$(MAKECMDGOALS))

%.run: %
    ./$<

$(TARGETS:.run=) dummy:

(我们需要filter以确保像make claen这样的错字会返回错误消息。dummy用于避免目标列表为空。)

另一种变化是使用静态模式规则,该规则似乎绕过了该错误/功能:

TARGETS = main.run foo.run bar.run $(filter %.run,$(MAKECMDGOALS))

$(TARGETS) dummy.run: %.run: %
    ./$<

还有另一种方法是使用 terminal 任意匹配规则,如果您所有的可执行文件都可以根据内置规则从单个C文件构建。无论出于何种原因,这也会在运行后删除main

%.run: %
    ./$<

%:: %.c  # note double-colon
    cc $< -o $@

最后,解决此问题的一种完全不同的方法是通过递归调用make来显式处理先决条件:

%.run:
    make $*
    ./$*

有关某些问题,请参见GNU make seems to ignore non-terminal match-anything rules for intermediate filesForce make to use a more specific rule。请注意,将main作为不相关规则的前提,例如:

%.run: %
    ./$<

garbage: main

似乎不起作用。