首页 > 解决方案 > 具有两个目标和单独的构建文件夹的 Makefile

问题描述

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

这是我所拥有的一个片段,但是我无法让构建文件夹根据目标评估不同的东西。我用fooandbar来表示不同的目标。

...
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 $@ 

标签: makefilegnu

解决方案


您需要在这里解决三个问题。

首先是在构建目录中构建目标文件。首先我们编写一个模式规则来构建 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 对象编写另一个规则:

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

第二个问题是整理我们到目前为止所写的内容。该foo_CFLAGS变量现在是使这两个配方不同的唯一因素,因此让我们通过特定于目标的变量赋值来摆脱它:

$(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指定的规则$(foo_BUILD_DIR),一个指定的bar规则,$(bar_BUILD_DIR)等等。有没有更懒的方法?我们所需要的只是获取目标(例如foo)并将其放入先决条件列表中。如您所知,自动变量 $@包含目标,但它在先决条件列表中不可用,因为先决条件列表在为该变量分配值之前已展开 -除非我们使用Secondary Expansion。这是一种先进的技术,但它允许我们在后期进行第二次扩展(使用额外的转义变量$以保护它们免受第一次扩展的影响):

.SECONDEXPANSION:

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

一旦它起作用了,我们可以添加另一个目标,或者我们想要的任意多个:

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

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


推荐阅读