在 makefile 的通配符中使用匹配词干

Use match stem in wildcard in makefile

像这样的 Makefile

list-%: $(wildcard src/modules/%/*.ts)
    echo '?' $? - '@' $@ - '%' $% - '<' $< - '^' $^ - '+' $+ - '|' $| - '*' $*

但是依赖项没有按预期工作。 make list-test 的输出是

echo '?'  - '@' list-test - '%'  - '<'  - '^'  - '+'  - '|'  - '*' test
? - @ list-test - % - < - ^ - + - | - * test

如果改为$(wildcard src/modules/test/*.ts),则输出变为

echo '?' src/modules/test/index.ts - '@' list-test - '%'  - '<' src/modules/test/index.ts - '^' src/modules/test/index.ts - '+' src/modules/test/index.ts - '|'  - '*' test
? src/modules/test/index.ts - @ list-test - % - < src/modules/test/index.ts - ^ src/modules/test/index.ts - + src/modules/test/index.ts - | - * test

我怎样才能让这个 $(wildcard src/modules/%/*.ts) 工作?

How can I make this $(wildcard src/modules/%/*.ts) work ?

遗憾的是,你不能。 % 仅在先决条件中以非常有限的方式工作。在所有 make 函数都已被求值之后,它被用作最后一个伪通配符,因此没有模式和函数的交互——我可能会想到一些递归构造,但这对于这样一个简单的任务。相反,您可以摆脱程序化的依赖关系:

MODULES := a b c

all: $(MODULES:%=list-%)
        @echo DONE

# generate dependencies programmatically:
$(foreach m,$(MODULES),$(eval list-$(m): $(wildcard src/modules/$(m)/*.ts)))

list-%:
        @echo $^
        @echo $@

请注意,对于 vanilla 目标来说,将依赖项列表分布在多个 target:prerequisite 语句和另一个规则中的配方中是完全合法的。唯一需要注意的是,如果您的列表中有一个不存在的模块,那么它会在先决条件列表为空的情况下执行该模块,并失败并显示一条可能难以理解的错误消息。

有一种方法可以做到这一点,使用 Secondary Expansion。它允许在 % 匹配到字符串后 进行第二次扩展:

.SECONDEXPANSION:

list-%: $$(wildcard src/modules/%/*.ts)
    echo '?' $? - '@' $@ - '%' $% - '<' $< - '^' $^ - '+' $+ - '|' $| - '*' $*

注意 $$ 在读入阶段,$$(wildcard src/modules/%/*.ts) 扩展为 $(wildcard src/modules/%/*.ts)。然后 Make 选择此模式规则作为构建 list-foo 的方式,并在第二次扩展中 $(wildcard src/modules/foo/*.ts) 扩展为文件名列表。