具有两个目标和单独生成文件夹的Makefile
我正在尝试使用一个Makefile,其中包含两个相似的目标和两个独立的构建文件夹。目标之间的唯一区别是添加了一个具有两个目标和单独生成文件夹的Makefile,makefile,gnu,Makefile,Gnu,我正在尝试使用一个Makefile,其中包含两个相似的目标和两个独立的构建文件夹。目标之间的唯一区别是添加了一个CFLAGdefine 这里是我所拥有的一个片段,但是我无法让build文件夹根据目标计算出不同的值。我使用foo和bar来表示不同的目标 ... foo_BUILD_DIR := build_foo/ bar_BUILD_DIR := build_bar/ C_SRCS := main.c CFLAGS := -std=c99 -Os -Wall foo_CFLAGS := $(
CFLAG
define
这里是我所拥有的一个片段,但是我无法让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对象编写另一条规则:
$(bar_BUILD_DIR)/%.o: %.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) $^ -o $@
第二个问题是整理我们到目前为止写的东西。这个foo\u CFLAGS
变量现在是唯一使这两个食谱不同的东西,所以让我们用一个:
现在,我们可以将这些规则组合为一个模式规则和两个目标:
$(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\u BUILD\u DIR)
,一个bar
规则来指定$(bar\u BUILD\u DIR)
,等等。有更懒的方法吗?我们所需要的只是将目标(例如,foo
)放入先决条件列表中。正如您所知,$@
包含目标,但它在前提条件列表中不可用,因为前提条件列表是在为该变量赋值之前展开的,除非我们使用。这是一项高级技术,但它允许我们在后期进行第二次扩展(使用额外的$
来转义变量,以保护它们不受第一次扩展的影响):
一旦这起作用,我们可以添加另一个目标,或者添加任意数量的目标:
foo bar: $(addprefix $$($$@_BUILD_DIR)/, $(OBJS))
...
还有一个或两个改进是可能的,但这已经足够开始了。这里有三个问题需要解决 第一个是在构建目录中构建对象文件。首先,我们编写一个模式规则来构建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\u CFLAGS
变量现在是唯一使这两个食谱不同的东西,所以让我们用一个:
现在,我们可以将这些规则组合为一个模式规则和两个目标:
$(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\u BUILD\u DIR)
,一个bar
规则来指定$(bar\u BUILD\u DIR)
,等等。有更懒的方法吗?我们所需要的只是将目标(例如,foo
)放入先决条件列表中。正如您所知,$@
包含目标,但它在前提条件列表中不可用,因为前提条件列表是在为该变量赋值之前展开的,除非我们使用。这是一项高级技术,但它允许我们在后期进行第二次扩展(使用额外的$
来转义变量,以保护它们不受第一次扩展的影响):
一旦这起作用,我们可以添加另一个目标,或者添加任意数量的目标:
foo bar: $(addprefix $$($$@_BUILD_DIR)/, $(OBJS))
...
可能还有一到两个改进,但这已经足够开始了。谢谢!虽然没有这些编辑,
foo:$(addprefix$$($$@\u BUILD\u DIR)/,$(OBJS))
但我无法让它工作:foo:$(addprefix$(foo\u BUILD\u DIR)/,$(OBJS))
。调用make foo
后未进行编辑的错误:make:**。停止。
我还注意到,对LDFLAGS
执行相同的策略由于某种原因不会产生任何效果:$(foo\u BUILD\u DIR)/%.o:LDFLAGS+=-Tmylinkerfile.ld
@User3219:我忘记显示.SECONDEXPANSION:
行。很抱歉,我将编辑。@User3219:…您的行似乎按照您的意愿修改了LDFLAGS
。但是,当您构建对象文件时,为什么要关心LDFLAGS
?谢谢!虽然没有这些编辑,foo:$(addprefix$$($$@\u BUILD\u DIR)/,$(OBJS))
但我无法让它工作:foo:$(addprefix$(foo\u BUILD\u DIR)/,$(OBJS))
。调用make foo
后未进行编辑的错误:make:**。停止。
我还注意到,对LDFLAGS
执行相同的策略由于某种原因不会产生任何效果:$(foo\u BUILD\u DIR)/%.o:LDFLAGS+=-Tmylinkerfile.ld
@User3219:我忘记显示.SECONDEXPANSION:
行。很抱歉,我将编辑。@User3219:…您的行似乎按照您的意愿修改了LDFLAGS
。但是,当您构建一个对象文件时,为什么要关心LDFLAGS
?