'Makefile with two targets and separate build folders
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 $@
Solution 1:[1]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
