我正在尝试将一个Makefile与两个相似的目标以及两个单独的构建文件夹一起使用。目标之间的唯一区别是添加了CFLAG
定义。
这里是我所拥有的摘要,但是我无法获取build文件夹来根据目标评估不同的内容。我用foo
和bar
代表不同的目标。
...
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 $@
您有三个要解决的问题。
首先是在构建目录中构建目标文件。首先,我们编写一个模式规则来构建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 $@
第三个问题是使foo
和bar
规则要求正确的对象。显然,这条规则:
foo:$(OBJS)
...
将无法正常工作,我们需要特定于foo
的内容:
foo: $(addprefix $(foo_BUILD_DIR), $(OBJS))
...
这是可行的,但是它要求我们编写一个指定foo
的$(foo_BUILD_DIR)
规则,指定一个bar
的$(bar_BUILD_DIR)
规则,依此类推。有懒惰的方式吗?我们需要做的就是取得目标(例如foo
)并将其放入先决条件列表。如您所知,automatic variable $@
包含目标,但在先决条件列表中不可用,因为先决条件列表在将值分配给该变量之前已展开-除非我们使用[ C0]。这是一项高级技术,但是它使我们可以在以后的阶段中进行第二次扩展(用额外的Secondary Expansion来转义变量,以保护它们免受第一次扩展的影响):
$
并且一旦可行,我们可以添加另一个目标,或者根据需要添加任意数量:
foo: $(addprefix $$($$@_BUILD_DIR)/, $(OBJS))
...
可以再进行一到两个改进,但这足以开始。