【问题标题】:Make compiling target multiple times多次编译目标
【发布时间】:2019-12-23 03:13:04
【问题描述】:

我有一个生成两个 elf 文件的 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 -j2 才能重现此行为。在这种情况下,这是一个简单的竞争条件,可以通过消除make 递归(许多人认为这是邪恶的)来避免。

标签: makefile


【解决方案1】:

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

【讨论】:

  • 你的解释是有道理的,这确实有效,但是现在makefile之间没有很好的分割。我不能再从 proj 运行 VARIANT=3 make。也许我的项目最好尝试组合这些 Makefile
  • 是的,当子部分是真正独立的自包含项目时,递归制作很好。在您的情况下,它们依赖于外部组件。非递归的 make 方法可能会更好。我更新了我的答案以显示非递归 Makefile 的(未经测试的)示例。注意:坦克到内含物,如果你愿意,你仍然可以将你的 Makefile 分割成更小的部分。
猜你喜欢
  • 1970-01-01
  • 2011-01-26
  • 2020-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-12
  • 2011-07-16
  • 1970-01-01
相关资源
最近更新 更多