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

moo*_*f2k 5 makefile

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

这是一个简单的例子,说明了我正在尝试做的事情。对于包含文件“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 $@
Run Code Online (Sandbox Code Playgroud)

这有效,但会发出警告:

$ make
Makefile:12: warning: overriding commands for target `one'
Makefile:9: warning: ignoring old commands for target `one'
Run Code Online (Sandbox Code Playgroud)

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

Mad*_*ist 5

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

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

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

test.o: test.cc
        g++ -Wall -c $< -o $@
Run Code Online (Sandbox Code Playgroud)

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

ETA您还可以使用特定于目标的变量:

CFLAGS =

test.o: CFLAGS = -Wall

$(OBJS): %.o: %.cc
        g++ $(CFLAGS) -c $< -o $@
Run Code Online (Sandbox Code Playgroud)

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 $@
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)