如何在Makefile中将先决条件列表与目标列表关联?

3

假设我有以下内容:

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
1个回答

3
您可以使用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将其第二个参数设置为其第一个参数指定的目标的前提条件。然后只需要在gen-prereq上调用pairmap,将目标作为第一个列表传递,源作为第二个列表传递即可。
另一种可行且更简单的方法是:
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))

这个功能通过在目标和源之间使用 : 连接它们(前提条件),并对每个连接进行 eval 处理来实现。


@user3228136 请注意,如果您有常见的文件名(例如dir1/a.c和dir2/a.c),它会出现错误。 - Andrea Biondo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接