假设我有一个源文件列表,每个文件都将编译为单独的二进制文件:
SRCS = abcd.c efgh.c ijkl.c
我希望根据文件名将输出文件放在单独的子目录中,如下所示:
- 构建/abcd/abcd
- 构建/efgh/efgh
- 构建/ijkl/ijkl
我认为静态模式规则是可行的方法。伪 make-rule 可以是这样的:
$(TARGETS): build/%/%: %.c
# stuff ...
我首先根据文件名创建子目录列表:
DIRS = $(SRCS:%.c=build/%)
现在我们有 DIRS = build/abcd build/efgh build/ijkl。我想我现在可以用以下内容列出目标列表:
BLDS = $(DIRS:%=%/$(basename %))
但是这当然不起作用,因为通配符不能在模式中多次使用。因此我现在陷入了 BLDS = build/abcd/% build/efgh/% build/ijkl/%。
显然我的处理方式完全错误。你会怎么做?
现在我正在明确地编写每条规则,这开始变得有点乏味:
compile = # command to do stuff
BD = build
all: $(BD)/abcd/abcd $(BD)/efgh/efgh $(BD)/ijkl/ijkl
$(BD)/abcd/abcd: abcd.c
$(call compile)
$(BD)/efgh/efgh: efgh.c
$(call compile)
$(BD)/ijkl/ijkl: ijkl.c
$(call compile)
clean:
rm -rf build/*
.PHONY: all
最佳答案
我相信这符合您的要求:
SRCS:=abcd.c efgh.c ijkl.c
# We could fold NAMES into BLDS's definition if NAMES is not used elsewhere.
NAMES:=$(SRCS:%.c=%)
BLDS:=$(foreach name,$(NAMES),$(subst foo,$(name),build/foo/foo))
# We don't use DIRS below but the question had this variable.
DIRS:=$(dir $(BLDS))
TARGETS:=$(BLDS)
.PHONY: all
all: $(TARGETS)
.SECONDEXPANSION:
$(TARGETS): $$(notdir $$@).c
@echo Build $@ from $^
mkdir -p $(dir $@)
touch $@
有两个重要的变化。第一个是重新排序变量的创建方式,并使用 subst,它允许多次替换匹配的字符串。第二种是使用secondary expansion这样 make 就会为每个目标构建规则。您最初的模式有两个 %
, but the docs say :
A pattern rule looks like an ordinary rule, except that its target contains the character `%' (exactly one of them).
(强调已添加。)
我已经使用假文件 abcd.c
efgh.c
和 ijkl.c
测试了上述内容,并得到以下输出:
$ make
Build build/abcd/abcd from abcd.c
mkdir -p build/abcd/
touch build/abcd/abcd
Build build/efgh/efgh from efgh.c
mkdir -p build/efgh/
touch build/efgh/efgh
Build build/ijkl/ijkl from ijkl.c
mkdir -p build/ijkl/
touch build/ijkl/ijkl
关于static - 根据目标依赖关系使目标包含子目录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20732357/