Reputation: 118
I am trying to use one Makefile with two similar targets and two separate build folders. The only difference between the targets is the addition of a CFLAG
define.
Here is a snippet of what I have, however I can't get the build folder to evaluate to something different depending on the target. I used foo
and bar
to represent the different targets.
...
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 $@
Upvotes: 0
Views: 134
Reputation: 99084
You have three problems to solve here.
The first is building object files in the build directories. First we write a pattern rule to build foo objects:
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 $@
Once that's working perfectly, we write another rule for the bar objects:
$(bar_BUILD_DIR)/%.o: %.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) $^ -o $@
The second problem is tidying up what we've written so far. That foo_CFLAGS
variable is now the only thing making these two recipes different, so let's get rid of it with a target-specific variable assignment:
$(foo_BUILD_DIR)/%.o: CFLAGS += -DBLE=1
$(foo_BUILD_DIR)/%.o: %.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) $^ -o $@
Now we can combine the rules into one pattern rule with two targets:
$(foo_BUILD_DIR)/%.o: CFLAGS += -DBLE=1
$(foo_BUILD_DIR)/%.o $(bar_BUILD_DIR)/%.o: %.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) $^ -o $@
The third problem is getting the foo
and bar
rules to require the right objects. Obviously this rule:
foo:$(OBJS)
...
won't work, we need something specific to foo
:
foo: $(addprefix $(foo_BUILD_DIR)/, $(OBJS))
...
This works, but it requires us to write a foo
rule that specifies $(foo_BUILD_DIR)
, a bar
rule that specifies $(bar_BUILD_DIR)
, and so on. Is there a lazier way? All we need is to take the target (e.g. foo
) and get it into the prerequisite list. As you know, the 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. This is an advanced technique, but it lets us do a second expansion in the later phase (escaping our variables with an extra $
to protect them from the first expansion):
.SECONDEXPANSION:
foo: $(addprefix $$($$@_BUILD_DIR)/, $(OBJS))
...
And once that's working, we can add another target, or as many as we want:
foo bar: $(addprefix $$($$@_BUILD_DIR)/, $(OBJS))
...
There are one or two more refinements possible, but this is enough to start with.
Upvotes: 2