根据目标依赖项创建包含子目录的目标

时间:2013-12-22 18:00:59

标签: static makefile target rules substitution

假设我有一个源文件列表,每个文件都要编译为单独的二进制文件:

SRCS = abcd.c efgh.c ijkl.c

我想根据文件名将输出文件放在不同的子目录中:

  • 构建/ ABCD / ABCD
  • 构建/ EFGH / EFGH
  • 构建/ IJKL / IJKL

我认为静态模式规则是要走的路。伪制规则可以是:

$(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

1 个答案:

答案 0 :(得分:3)

我相信这可以做你想要的:

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,以便为每个目标构建规则。您最初是一个包含两个%but the docs say

的模式
  

模式规则看起来像普通规则,除了它的目标包含字符'%'(其中只有一个)。

(强调补充。)

我使用假文件abcd.c efgh.cijkl.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