makefile - 多次编译目标
问题描述
我有一个生成两个精灵文件的 Makefile 设置。elf 文件有两个输入,一个是通用的,一个是唯一的。我正在尝试让公共输入(main.c)只编译一次。
我有以下示例模仿我的设置:
Makefile
proj
- main.c
- print.c
- Makefile
根 Makefile:
.PHONY: all
all: proj/build/0/0.elf proj/build/1/1.elf
proj/build/0/0.elf:
$(MAKE) -C proj VARIANT=0 all
proj/build/1/1.elf:
$(MAKE) -C proj VARIANT=1 all
项目/制作文件:
COMMON_SRCS = main.c
VARIANT_SRCS = print.c
BUILD_DIR_COMMON = build/common
BUILD_DIR_VARIANT= build/$(VARIANT)
OBJECTS += $(addprefix $(BUILD_DIR_COMMON)/,$(COMMON_SRCS:.c=.o))
OBJECTS += $(addprefix $(BUILD_DIR_VARIANT)/,$(VARIANT_SRCS:.c=.o))
.PHONY: all
all: $(BUILD_DIR_VARIANT)/$(VARIANT).elf
$(BUILD_DIR_COMMON)/%.o: %.c
@mkdir -p $(BUILD_DIR_COMMON)
$(CC) -c $< -o $@
$(BUILD_DIR_VARIANT)/%.o: %.c
@mkdir -p $(BUILD_DIR_VARIANT)
$(CC) -DVARIANT=$(VARIANT) -c $< -o $@
$(BUILD_DIR_VARIANT)/$(VARIANT).elf: $(OBJECTS)
$(CC) $(OBJECTS) -o $@
.c 文件并不重要,只要知道 print.c 使用 VARIANT 定义即可。
当我make
在根目录中运行时,我得到以下输出:
make -C proj VARIANT=0 all
make -C proj VARIANT=1 all
make[1]: Entering directory '/home/phil/dev/make_test/proj'
make[1]: Entering directory '/home/phil/dev/make_test/proj'
cc -c main.c -o build/common/main.o
cc -c main.c -o build/common/main.o
cc -DVARIANT=0 -c print.c -o build/0/print.o
cc build/common/main.o build/0/print.o -o build/0/0.elf
cc -DVARIANT=1 -c print.c -o build/1/print.o
cc build/common/main.o build/1/print.o -o build/1/1.elf
make[1]: Leaving directory '/home/phil/dev/make_test/proj'
make[1]: Leaving directory '/home/phil/dev/make_test/proj'
从输出中可以看出,main.c 被编译了两次。我正在寻找一些选项,使其只编译一次而不完全改变我的项目结构
解决方案
您不能将构建委托给两个不同的 make 调用并期望它们合作。如果您的两个构建有共同点,最好将其放在您的顶级 Makefile 中:
# Makefile
.PHONY: all
all: proj/build/0/0.elf proj/build/1/1.elf
COMMON_SRCS = main.c
BUILD_DIR_COMMON = build/common
OBJECTS += $(addprefix $(BUILD_DIR_COMMON)/,$(COMMON_SRCS:.c=.o))
$(BUILD_DIR_COMMON)/%.o: %.c
@mkdir -p $(BUILD_DIR_COMMON)
$(CC) -c $< -o $@
proj/build/0/0.elf: $(OBJECTS)
$(MAKE) -C proj VARIANT=0 all
proj/build/1/1.elf: $(OBJECTS)
$(MAKE) -C proj VARIANT=1 all
和:
# proj/Makefile
COMMON_SRCS = main.c
VARIANT_SRCS = print.c
BUILD_DIR_COMMON = build/common
BUILD_DIR_VARIANT= build/$(VARIANT)
OBJECTS += $(addprefix $(BUILD_DIR_COMMON)/,$(COMMON_SRCS:.c=.o))
OBJECTS += $(addprefix $(BUILD_DIR_VARIANT)/,$(VARIANT_SRCS:.c=.o))
.PHONY: all
all: $(BUILD_DIR_VARIANT)/$(VARIANT).elf
$(BUILD_DIR_VARIANT)/%.o: %.c
@mkdir -p $(BUILD_DIR_VARIANT)
$(CC) -DVARIANT=$(VARIANT) -c $< -o $@
$(BUILD_DIR_VARIANT)/$(VARIANT).elf: $(OBJECTS)
$(CC) $(OBJECTS) -o $@
这种重组的一个缺点是您不能再从头开始构建单个变体。由于它们依赖于外部组件,您必须首先构建这些外部组件。当子部分是真正独立的、自包含的项目时,递归制作很好。非递归的 make 方法可能会更好。例子:
# Makefile
VARIANTS := 0 1 2 3
COMMON_SRCS := main.c
VARIANT_SRCS := print.c
BUILD_DIR_COMMON := proj/build/common
.PHONY: all
$(BUILD_DIR_COMMON)/%.o: proj/%.c | $(BUILD_DIR_COMMON)
$(CC) -c $< -o $@
$(BUILD_DIR_COMMON):
@mkdir -p $(BUILD_DIR_COMMON)
define VARIANT_rule
.PHONY: V$(1)
BUILD_DIR_VARIANT_$(1) := proj/build/$(1)
OBJECTS_$(1) := $$(patsubst %.c,$$(BUILD_DIR_COMMON)/%.o,$$(COMMON_SRCS))
OBJECTS_$(1) += $$(patsubst %.c,$$(BUILD_DIR_VARIANT_$(1))/%.o,$$(VARIANT_SRCS))
all V$(1): $$(BUILD_DIR_VARIANT_$(1))/$(1).elf
$$(BUILD_DIR_VARIANT_$(1))/%.o: proj/%.c | $$(BUILD_DIR_VARIANT_$(1))
$$(CC) -DVARIANT=$(1) -c $$< -o $$@
$$(BUILD_DIR_VARIANT_$(1)):
@mkdir -p $$@
$$(BUILD_DIR_VARIANT_$(1))/$(1).elf: $$(OBJECTS_$(1))
$$(CC) $$^ -o $$@
endef
$(foreach v,$(VARIANTS),$(eval $(call VARIANT_rule,$(v))))
然后,构建所有变体:
$ make all
虽然只构建变体 1 和 3:
$ make V1 V3