首页 > 解决方案 > 多次编译目标

问题描述

我有一个生成两个精灵文件的 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 被编译了两次。我正在寻找一些选项,使其只编译一次而不完全改变我的项目结构

标签: makefile

解决方案


您不能将构建委托给两个不同的 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

推荐阅读