Reputation: 43
I'm building a makefile that will be used to build a release or debug target library. I want to place the object and auto-generated dependancy files into either a debug or release directory structure, depending on the requested makefile goal. I don't want to specify a testable make command-line argument (i.e. DBG=1), but would prefer to run make -f Makefile, or make -f Makefiel dbg for release and debug target goals, respectively. Got that part down. I understand that I can't assign a target-specific variable containing the name of the object dir (either release or debug) that can be used as part of the Target specification in a rule, like I did in the example shown below. In this example, OBJDIR is the target-specific variable I would like to set depending on the build goal. For that reason, in this example, $(OBJDIR) is empty in the target rule $(OBJDIR)/%.o. Any recommendations on how to perform the suggested steps nicely? (The example shown is simply a copy/paste unverified example...syntax is not verified...in fact, I can't get the tabs to appear correctly...I'm hoping to get some implementation ideas). (Also, $(OBJDIR) is not set in the clean target as shown...since it is not in the dbg/all target dependancy heirarchy...thoughts?) Thanks in advance.
Makefile:
OBJS := a.o b.o c.o
SRCS := $(OBJS:.o=.c)
-- Set up the release and the debug directory paths and object filenames
RELEASE_DIR := ./release
RELEASE_OBJ := $(OBJS:%=$(RELEASE_DIR)/%)
DEBUG_DIR := ./debug
DEBUG_OBJ := $(OBJS:%=$(DEBUG_DIR)/%)
.PHONY : all dbg
all: CFLAGS = -O3
all: OBJDIR := RELEASE_DIR
all: df := $(RELEASE_DIR)/$(*F)
all: init_release lib1.so
dbg: CFLAGS = -g -O0
dbg: OBJDIR := DEBUG_DIR
dbg: df := $(DEBUG_DIR)/$(*F)
dbg: init_debug lib1.so
Lib1.so: $(OBJ)
init_release:
-@mkdir -p $(RELEASE_DIR)
init_debug:
-@mkdir -p $(DEBUG_DIR)
lib1.so: $(OBJ)
@echo '--------------------------------------------------------------'
@echo linking $@
@gcc -shared -o lib1.so $(OBJ)
-Compile including advance dependancy generation alg, per Tom Tromey:
# http://make.paulandlesley.org/autodep.html
$(OBJDIR)/%.o: %.c
echo $@
echo $(OBJDIR)
echo compiling $@
$(COMPILE.c) -MD -o $@ $<
cp $(df).d $(df).P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(df).d >> $(df).P; \
rm -f $(df)/$*.d
# If the goal is "clean", don't include these to avoid trying to build them
ifneq($(MAKECMDGOALS),clean)
-include $(SRCS:%.c=$(OBJDIR)/%.P)
endif
clean:
-@rm -f $(OBJDIR)/*.[Pdo] lib1.so
Upvotes: 3
Views: 6079
Reputation: 15483
Target specific variables can be tricky. Use indirection instead. Make has lots of syntax to cut-down on boilerplate text. .SECONDEXPANSION
is often good. A sketch:
.SECONDEXPANSION:
${DEBUG_OBJ} ${RELEASE_OBJ}: $$(patsubst %.o,%.c,$${@F})
gcc ${copts-${@D}} -c $< -o $@
Here we tell make that ./release/a.o
depends on a.c
. When make decides to build ./release/a.o
it expands the shell line. As it does so, ${@D}
is naturally release
, so make carries on and expands ${copts-release}
which you will have defined usefully.
Similarly, when producing ./debug/a.o
make expands ${copts-debug}
.
Copious use of $(warning [blah])
, $(error [blah blah])
and the mandatory --warn-undefined-variables
will help you get this right.
Upvotes: 5
Reputation: 37427
The Makefile you wrote is not valid, and it will not generate your targets as you expect. For instance, you cannot set the CFLAGS
variable in the targets definitions all
and dbg
.
The only solution I can think of is to call make with the same Makefile defining the DBG
variable as you wish. E.g.:
ifdef DBG
CFLAGS = -O0 -ggdb
OBJDIR = dbgdir
else
CFLAGS = -O2
OBJDIR = reldir
endif
all: $(OBJDIR)/target
#Your commands here
dbg:
$(MAKE) DBG=1
With this, if you call make
, you have the release build. If you call make dbg
you have the release build.
Upvotes: 1