覆盖 Makefile 中的静态模式规则(不发出警告)

Override static pattern rule in Makefile (without it giving a warning)

我想使用静态模式规则为 class 个目标指定默认配方,但为一些特定目标覆盖该配方。

这里有一个简单的例子来说明我正在尝试做的事情。对于包含文件 "test.py" 的每个目录,我想调用命令 "run_test.py",除非目录名为 "one" 我想调用一组不同的命令:

TESTS := $(shell find * -name "test.py" | xargs -I {} dirname {})

.PHONY: $(TESTS)

all: $(TESTS)

$(TESTS): %:
    python run_test.py $@

one:
    python run_test.py $@ mode=1
    python run_test.py $@ mode=2
    python check_results.py $@

这有效,但会发出警告:

$ make
Makefile:12: warning: overriding commands for target `one'
Makefile:9: warning: ignoring old commands for target `one'

是否有其他方法可以做到这一点,或者消除警告?

不,你不能那样做。静态模式规则实际上不是模式规则:相反,它只是用于编写大量显式规则的 shorthand。

如果你想让大多数目标使用一个配方,而少数目标使用另一个配方,你应该为 "most" 目标定义一个真实的模式规则,而不是静态模式规则,然后使用显式规则来覆盖:

%.o: %.cc
        g++ -c $< -o $@

test.o: test.cc
        g++ -Wall -c $< -o $@

为什么要使用静态模式规则而不是常规模式规则?

ETA 你也可以使用特定于目标的变量:

CFLAGS =

test.o: CFLAGS = -Wall

$(OBJS): %.o: %.cc
        g++ $(CFLAGS) -c $< -o $@

ETA2 好的,这与您原来的示例有很大不同。

我可以看到你有两个明显的选择。首先是从列表中删除特殊目标;类似于:

SPECIAL_TESTS := one

TESTS := $(patsubst %/test.py,%,$(shell find * -name "test.py"))

.PHONY: all $(TESTS)

all: $(TESTS)

$(filter-out $(SPECIAL_TESTS),$(TESTS)):
        python run_test.py $@

$(SPECIAL_TESTS):
        python run_test.py $@ mode=1
        python run_test.py $@ mode=2
        python check_results.py $@

另一种方法是使用定义整个配方的特定于目标的变量,如下所示:

TEST_RECIPE = python run_test.py $@

one: TEST_RECIPE = python run_test.py $@ mode=1 \
        && python run_test.py $@ mode=2 \
        && python check_results.py $@

TESTS := $(patsubst %/test.py,%,$(shell find * -name "test.py"))

.PHONY: all $(TESTS)

all: $(TESTS)

$(TESTS):
        $(TEST_RECIPE)