说我有:
TARGETS = a.o b.o c.o
SOURCES = F1/a.c F2/F3/b.c c.c
我想获得:
a.o: F1/a.c
gcc $< -c
b.o: F2/F3/b.c
gcc $< -c
c.o: c.c
gcc $< -c
我想要一个紧凑的表达来完成这项工作,例如:
$(TARGETS): $(SOURCES)
#Appropriate compile command
答案 0 :(得分:2)
您可以使用VPATH
告诉make有关源目录的内容,然后使用简单的模式规则:
TARGETS := a.o b.o c.o
VPATH := F1:F2/F3 # Use ; instead of : on Windows
%.o: %.c
$(CC) -c $< -o $@
(或者甚至完全省略规则,在这种情况下使隐式规则正常工作)
但是如果你有不同路径中以相同方式命名的文件无法正常工作(它只选择它找到的第一个文件)。这可以通过像你问的那样压缩列表来实现:
TARGETS := a.o b.o c.o
SOURCES := F1/a.c F2/F3/b.c c.c
$(TARGETS):
$(CC) -c $< -o $@
list-rem = $(wordlist 2,$(words $1),$1)
pairmap = $(and $(strip $2),$(strip $3),$(call \
$1,$(firstword $2),$(firstword $3))$(call \
pairmap,$1,$(call list-rem,$2),$(call list-rem,$3)))
gen-prereq = $(eval $1: $2)
$(call pairmap,gen-prereq,$(TARGETS),$(SOURCES))
我定义了一个明确的规则来编译它的先决条件,但我没有给它任何先决条件。然后我定义了一个pairmap
,它带有一个函数名和两个列表,并为每对元素调用该函数。它是递归的,由list-rem
帮助,它从列表中取出第一个元素。 gen-prereq
将其第二个参数设置为其第一个参数指定的目标的先决条件。剩下的就是在pairmap
上调用gen-prereq
,将目标作为第一个列表传递,将源作为第二个列表。
另一种可行且更简单的方法是:
TARGETS := a.o b.o c.o
SOURCES := F1/a.c F2/F3/b.c c.c
$(TARGETS):
gcc -c $< -o $@
$(foreach x,$(join $(addsuffix :,$(TARGETS)),$(SOURCES)),$(eval $x))
通过将目标和来源与:
加在一起(先决条件)和评估每个目标和来源,可以起作用。