具有两个目标和单独构建文件夹的 Makefile

Makefile with two targets and separate build folders

我正在尝试将一个 Makefile 与两个相似的目标和两个单独的构建文件夹一起使用。目标之间的唯一区别是添加了 CFLAG 定义。

这是我所拥有的片段,但是我无法让构建文件夹根据目标评估不同的内容。我使用 foobar 来表示不同的目标。

...
foo_BUILD_DIR := build_foo/
bar_BUILD_DIR := build_bar/

C_SRCS := main.c

CFLAGS := -std=c99 -Os -Wall
foo_CFLAGS := $(CFLAGS) -DBLE=1

C_OBJS := $(addprefix $(BUILD_DIR),$(subst .c,.o,$(C_SRCS)))

$(BUILD_DIR)%.o: %.c
    @mkdir -p $(@D)
    $(CC) $(CFLAGS) $^ -o $@

foo:$(OBJS)
    $(CC) $(OBJS) $(LDFLAGS) -o $@ 

bar:$(OBJS)
    $(CC) $(OBJS) $(LDFLAGS) -o $@ 

这里有3个问题需要解决。

首先是在构建目录中构建目标文件。首先我们编写一个模式规则来构建 foo 对象:

foo_BUILD_DIR := build_foo # Don't put the trailing slash in the dir name, it's a pain.

CFLAGS := -std=c99 -Os -Wall
foo_CFLAGS := $(CFLAGS) -DBLE=1

$(foo_BUILD_DIR)/%.o: %.c
    @mkdir -p $(@D)
    $(CC) $(foo_CFLAGS) $^ -o $@

一旦一切正常,我们就为条形对象编写另一个规则:

$(bar_BUILD_DIR)/%.o: %.c
    @mkdir -p $(@D)
    $(CC) $(CFLAGS) $^ -o $@

第二个问题是整理我们到目前为止所写的内容。 foo_CFLAGS 变量现在是唯一让这两个食谱不同的东西,所以让我们用 target-specific variable assignment:

来摆脱它
$(foo_BUILD_DIR)/%.o: CFLAGS += -DBLE=1

$(foo_BUILD_DIR)/%.o: %.c
    @mkdir -p $(@D)
    $(CC) $(CFLAGS) $^ -o $@

现在我们可以将规则组合成一个具有两个目标的模式规则:

$(foo_BUILD_DIR)/%.o: CFLAGS += -DBLE=1

$(foo_BUILD_DIR)/%.o $(bar_BUILD_DIR)/%.o: %.c
    @mkdir -p $(@D)
    $(CC) $(CFLAGS) $^ -o $@

第三个问题是让 foobar 规则要求正确的对象。显然这个规则:

foo:$(OBJS)
    ...

行不通,我们需要一些特定于 foo 的东西:

foo: $(addprefix $(foo_BUILD_DIR)/, $(OBJS))
    ...

这行得通,但它需要我们编写一个指定 $(foo_BUILD_DIR)foo 规则,一个指定 $(bar_BUILD_DIR)bar 规则,等等。有没有更懒的方法?我们所需要做的就是获取目标(例如 foo)并将其放入先决条件列表中。如您所知,automatic variable $@ contains the target, but it isn't available in the prerequisite list, because the prerequisite list is expanded before a value is assigned to that variable-- unless we use Secondary Expansion。这是一种高级技术,但它允许我们在后期进行第二次扩展(使用额外的 $ 转义我们的变量以保护它们免受第一次扩展):

.SECONDEXPANSION:

foo: $(addprefix $$($$@_BUILD_DIR)/, $(OBJS))
    ...

一旦成功,我们就可以添加另一个目标,或者添加任意数量的目标:

foo bar: $(addprefix $$($$@_BUILD_DIR)/, $(OBJS))
    ...

还有一两个可能的改进,但这已经足够了。