gnu make 中的目标依赖源文件

Target dependent source files in gnu make

我的项目是一个固件,它有一个与设备无关的通用逻辑部分和一个与设备相关的部分。 现在我想要一个(虚假的)目标来构建设备 A 和一个(虚假的)目标来构建设备 B。理想情况下,两个目标都应生成相同的命名二进制文件。 显然,这两个目标都依赖于通用的设备独立代码及其各自的源代码。 target_A: $(COMMON_OBJ) $(A_OBJ)

我尝试设置目标因变量,但它们仅在配方中进行评估,因此无法基于目标之间的共享变量创建依赖列表。

这行不通:

target_A:
    DEV_SRC = foo_a.c bar_a.c
target_A: $(COMMON_OBJ) $(DEV_SRC:.c=.o)

我现在的情况是:我需要为每个目标编写相同的配方,这是我想避免的。可以合二为一吗target/recipe?

target_A: $(COMMON_OBJ) $(A_OBJ)
    <build recipe>
target_B: $(COMMON_OBJ) $(B_OBJ)
    <build recipe>

更多背景信息:我喜欢使 Makefile 足够简单,以便其他工程师可以添加另一个目标,定义它的源,并可能将目标或变量添加到现有列表中。我认为所有这些对于每个程序员都是可行的,但是应该避免编写配方和扩展 Makefiles 逻辑以尽量减少错误的可能性,特别是对于没有 make 经验的人。

secondary expansion 的帮助下,我可以将其简化为:

$ cat Makefile
TARGETS := target_A target_B

target_A_SRC := target_A.c
target_B_SRC := target_B.c

COMMON_OBJ := common.o

$(foreach target,$(TARGETS),$(eval $(target)_OBJ := $(addsuffix .o, $(basename $($(target)_SRC)))))

.SECONDEXPANSION:

.PHONY: all
all: $(TARGETS)

.PHONY: clean
clean:
        -rm -f $(TARGETS) $(foreach target,$(TARGETS),$($(target)_OBJ)) $(COMMON_OBJ)

$(TARGETS): $(COMMON_OBJ) $$($$@_OBJ)
        $(LINK.o) $(OUTPUT_OPTION) $^

为了添加新目标,将新目标添加到 $(TARGETS) 并相应地定义 *_SRC 变量就足够了。所有其余的(构建和清理)将由现有的配方处理。

示例输出:

$ make
cc    -c -o common.o common.c
cc    -c -o target_A.o target_A.c
cc   -o target_A common.o target_A.o
cc    -c -o target_B.o target_B.c
cc   -o target_B common.o target_B.o

$ make clean
rm -f target_A target_B target_A.o target_B.o common.o