I'm trying to set up a makefile which consists of a debug and release target.
There are some target specific variables, mainly folder names, which are set properly in the different cases, but do not apply correctly for the $@
automatic variable. Folowing code:
SRC_DIR = src
OBJ_ROOT_DIR = obj
REL_DIR = release
DBG_DIR = debug
TGT_DIR = $(REL_DIR)
SRC_LIST = main.cc prime.cc
SRC_SUFF = cc
SRCS = $(patsubst %.cc, $(SRC_DIR)/%.$(SRC_SUFF), $(SRC_LIST))
OBJ_DIR = $(OBJ_ROOT_DIR)/$(TGT_DIR)
OBJS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(SRC_LIST))
all: $(OBJS)
release: all
debug: TGT_DIR = $(DBG_DIR)
debug: OBJ_DIR = $(OBJ_ROOT_DIR)/$(TGT_DIR)
debug: OBJS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(SRC_LIST))
debug: $(OBJS)
$(OBJS):$(OBJ_DIR)/%.o: $(SRC_DIR)/%.$(SRC_SUFF)
@echo "TGT_DIR: $(TGT_DIR) OBJ_DIR: $(OBJ_DIR) OBJS: $(OBJS)"
@echo "Compiling $< to $@ ..."
@echo "... done !"
@echo "."
Running make release produces the following expected output:
TGT_DIR: release OBJ_DIR: obj/release OBJS: obj/release/main.o obj/release/prime.o Compiling src/main.cc to obj/release/main.o ... ... done ! .
TGT_DIR: release OBJ_DIR: obj/release OBJS: obj/release/main.o obj/release/prime.o Compiling src/prime.cc to obj/release/prime.o ... ... done !
Wheras make debug leads to the following unexpected:
TGT_DIR: debug OBJ_DIR: obj/debug OBJS: obj/debug/main.o obj/debug/prime.o Compiling src/main.cc to obj/release/main.o ... ... done ! .
TGT_DIR: debug OBJ_DIR: obj/debug OBJS: obj/debug/main.o obj/debug/prime.o Compiling src/prime.cc to obj/release/prime.o ... ... done !
I cannot figure out, why $@
doesn't evaluate to the desired debug version in the second case. The variables seem to be set correctly though. How can I achieve to have the correct directory name when executing the recipe?
Thanks in advance!
You have quite a few options / ways to do this.
MAKECMDGOALS
(these are the words after make
e.g. release or debug). Note: there can be more then one - but if your makefile is simple and just has one the following will work:eg:
ifneq ($(MAKECMDGOALS),debug)
TGT_DIR = $(DBG_DIR)
OBJ_DIR = $(OBJ_ROOT_DIR)/$(TGT_DIR)
OBJS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(SRC_LIST))
endif
Another option is to use second expansion, I am just going to put a link: secondary expansion
Yet another option is to setup some variables in your rule, then export them and call make again (recursively), perhaps something like this:
eg (incomplete):
# Note you can just export the ones you want but... for ease of the example:
.EXPORT_ALL_VARIABLES
debug: TGT_DIR = $(DBG_DIR)
debug: OBJ_DIR = $(OBJ_ROOT_DIR)/$(TGT_DIR)
debug: OBJS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(SRC_LIST))
debug:
$(MAKE) do_build
do_build: $(OBJS)
...etc...
Where in your first call to make it setup up some variables in the debug rule. In the second it calls do_build directly and the variables are setup already. Recursive make is generally frowned upon - but I found many times its the easiest way to get certain things done.
I'd probably err towards option 1. for its simplicity. There are even more ways to do this, but it sort of depends how you want to roll - I am just setting out some options that keep your makefile structure more or less the same...