具有通用中间规则的 Makefile

Makefile with generic intermediate rules

我有一个看起来像这样的 makefile:

TARGET:=prog
SOURCES:=a.c b.c
CFLAGS:=-Wall -g -O2

OBJECTS:=$(SOURCES:%.c=%.o)

$(TARGET): $(OBJECTS)
    gcc -o $@ $^

%.o: %.c
    gcc $(CFLAGS) -c -o $@ $<

clean:
    rm -f $(TARGET) $(OBJECTS)

用户需要更改的唯一变量是目标名称和构建它所需的源。需要生成的对象是根据源自动确定的。我想扩展它以支持多个目标,每个目标都有自己的源列表。不过,我在正确使用语法时遇到了麻烦。这是总体思路:

TARGETS:=prog1 prog2
SOURCES_prog1:=a.c b.c
SOURCES_prog2:=a.c c.c
CFLAGS:=-Wall -g -O2

OBJECTS_$@=$(SOURCES_$@:%.c=%.o)

$(TARGETS): $(OBJECTS_$@)
    gcc -o $@ $^

%.o: %.c
    gcc $(CFLAGS) -c -o $@ $<

clean:
    rm -f $(TARGET) $(OBJECTS)

但是我无法正确生成对象列表。我也不确定如何编写 clean 规则来清除所有对象。这可能吗?

我认为有两种主要方法可以做到这一点。

第一个涉及使用 $(eval) function.

动态创建 target/prerequisite 映射
TARGETS:=prog1 prog2
SOURCES_prog1:=a.c b.c
SOURCES_prog2:=a.c c.c
CFLAGS:=-Wall -g -O2

$(TARGETS):
        gcc -o $@ $^

$(foreach t,$(TARGETS),$(eval OBJECTS_$t := $(SOURCES_$t:.c=.o))$(eval $t: $(OBJECTS_$t)))

第二个涉及使用 Secondary Expansion

TARGETS:=prog1 prog2
SOURCES_prog1:=a.c b.c
SOURCES_prog2:=a.c c.c
CFLAGS:=-Wall -g -O2

.SECONDEXPANSION:

$(TARGETS): $$(OBJECTS_$$@)
        gcc -o $@ $^

$(foreach t,$(TARGETS),$(eval OBJECTS_$t := $(SOURCES_$t:.c=.o)))

在任一情况下,clean 目标变为:

clean:
        rm -f $(TARGETS) $(foreach t,$(TARGETS),$(OBJECTS_$t))