I recently found this piece of example code from the GNU make documentation that refers to the eval function. I really like it, but when I tried to test it on my machine (make 3.81/Debian), all it does is trying to link the server without compiling the c files first ... why? Is make 3.81 not compatible?
Shell output:
$ make
cc -o server
cc: no input files
Code:
PROGRAMS = server client
server_OBJS = server.o server_priv.o server_access.o
server_LIBS = priv protocol
client_OBJS = client.o client_api.o client_mem.o
client_LIBS = protocol
# Everything after this is generic
.PHONY: all
all: $(PROGRAMS)
define PROGRAM_template =
$(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
ALL_OBJS += $$($(1)_OBJS)
endef
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
$(PROGRAMS):
$(LINK.o) $^ $(LDLIBS) -o $#
clean:
rm -f $(ALL_OBJS) $(PROGRAMS)
I think it will work if you remove the = from the define line:
define PROGRAM_template
...
endef
I've tested this with GNUMake 3.81. As for why this works and the version in the manual doesn't, I have no idea.
Related
I am trying to compile a code -
this code uses a few libraries and for starters I am trying to create a makefile to get one library
I am having difficulties.
this is the makefile
HOME = $(shell pwd)
LIBNA = libbv.a
LIBZP = $(HOME)/$(LIBNA)
# FFLAGC = -Mextend -Msave -g -C -Mchkfpstk -Mchkptr -fpic -Ktrap=fp
FC = gfortran
ifeq ($(OSTYPE),linux)
FC = pgf95 -Msave -fpic
endif
# per il gfortran
FFLAGC = -g -Wall-ffixed-line-length-0 -Mextend -Msave -g -C -Mchkfpstk -Mchkptr -fpic -Ktrap=fp
# FC = gfortran
#
SOURCE = \
filename1.f\
filename2.f\
...
filenamen.f
.SUFFIXES: .f
OBJ = $(SRCS:.f=.o)
.f.o:
$(FC) $(FFLAG) -c $< $#
$(LIBZP): $(LIBZP)($(OBJ))
ar -r $(LIBZP) $?
rm -f $?
this is the makefile I am using.
I get the error
make: *** No rule to make target absolutepath/libbv.a()', needed by
absolute_path/libbv.a'. Stop.
I was wondering if any of you can help
Well, your error message shows this:
absolutepath/libbv.a()
with nothing inside the parentheses. But your makefile has this:
$(LIBZP): $(LIBZP)($(OBJ))
with $(OBJ) in the parentheses. So clearly, $(OBJ) is expanding to the empty string. Why is that?
Well, OBJ is set here:
OBJ = $(SRCS:.f=.o)
based on SRCS. Well, what does that variable contain?
Aha. Nothing, because it's never set. You set this though:
SOURCE = \
...
SOURCE != SRCS, so you're modifying an empty variable and OBJ is the empty string.
I'm not sure why you're prefixing the target with the current directory... that's where it will go by default if you don't specify any directory. In any event, you can use $(CURDIR) rather than running $(shell pwd).
If you're going to use GNU make anyway, I recommend you use pattern rules rather than suffix rules: they're much simpler to read/understand:
%.o : %.f
$(FC) $(FFLAG) -c $< $#
Also don't you need a -o here before $#? I don't use Fortran compilers but I would imagine they work more or less the same as C/C++ compilers.
The question is a little vague, because I'm not entirely sure of the best way to ask what I'm trying to achieve in such a short summary.
To explain it best this is what I currently have....
common.mk
DESTDIR = ../../install/
tools.mk
CC = gcc
CFLAGS = -fPIC -Wall -Wextra -O2 -g -I.
LDFLAGS = -shared
RM = rm -f
MAKEDIR = mkdir -p
Makefile
include ../../builder/tools.mk
include ../../builder/common.mk
TEST_RUNNERS = test_foo test_bar
test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c
test_bar_TESTS = tests/test_bar.c
test_bar_SOURCES = bar.c
# Gather lists of ALL sources and objects required to build test_foo
test_foo_ALL_SOURCES = $(test_foo_TESTS) $(test_foo_SOURCES)
test_foo_ALL_OBJECTS = $(test_foo_ALL_SOURCES:.c=.o)
# Compile All the sources required for test_foo
$(test_foo_ALL_SOURCES:.c=.d):%.d:%.c
$(CC) $(CFLAGS) -MM $< >$#
include $(test_foo_ALL_SOURCES:.c=.d)
# Build test_foo and clean up temporary build files
test_foo: $(test_foo_ALL_OBJECTS)
$(CC) -L$(DESTDIR) -o $(strip $(DESTDIR))$(strip $#) $^
-${RM} ${test_foo_ALL_OBJECTS} ${test_foo_ALL_SOURCES:.c=.d}
# Gather lists of ALL sources and objects required to build test_bar
test_bar_ALL_SOURCES = $(test_bar_TESTS) $(test_bar_SOURCES)
test_bar_ALL_OBJECTS = $(test_bar_ALL_SOURCES:.c=.o)
# Compile All the sources required for test_bar
$(test_bar_ALL_SOURCES:.c=.d):%.d:%.c
$(CC) $(CFLAGS) -MM $< >$#
include $(test_bar_ALL_SOURCES:.c=.d)
# Build test_bar and clean up temporary build files
test_bar: $(test_bar_ALL_OBJECTS)
$(CC) -L$(DESTDIR) -o $(strip $(DESTDIR))$(strip $#) $^
-${RM} ${test_bar_ALL_OBJECTS} ${test_bar_ALL_SOURCES:.c=.d}
What I want to do is remove all the complexity in having to manually add rules for each target, and instead "auto-generate" these rules. It's fairly clean and simple in my own mind...
TEST_RUNNERS = test_foo test_bar
So for each TEST_RUNNER that is specified in the list, a list of SOURCES (the code under test) and a list of TESTS (the unit test sources) must be provided...
test_foo_TESTS
test_foo_SOURCES
I've been playing around with foreach but it's not the right approach, and I'm not entirely sure what I need to do to achieve my goal, so after playing around for a few hours I thought I'd try and ask some of you guys because there's some pretty clever guys here that hopefully may be able to help me!
Another idea I was playing around with was to creating templates that I could call upon to generate these rules:
$(foreach runner,$(TEST_RUNNERS),$(eval $(call COMPILE_ALL_TEST_RUNNER_SOURCES, runner)))
$(foreach runner,$(TEST_RUNNERS),$(eval $(call MAKE_TEST_RUNNER_TEMPLATE, runner)))
define COMPILE_ALL_TEST_RUNNER_SOURCES
$($(1)_ALL_SOURCES:.c=.d):%.d:%.c
$(CC) $(CFLAGS) -MM $< >$#
include $($(1)_ALL_SOURCES:.c=.d)
endef
define MAKE_TEST_RUNNER_TEMPLATE
$(1): $($(1)_ALL_OBJECTS)
$(CC) -L$(DESTDIR) -o $(strip $(DESTDIR))$(strip $#) $^
-${RM} ${$(1)_ALL_OBJECTS} ${$(1)_ALL_SOURCES:.c=.d}
endef
After spending a little more time reading the Make manual, I discovered this very useful page.
https://www.gnu.org/software/make/manual/html_node/Eval-Function.html
which has some really useful information on how I can construct my Makefile exactly how I want to. If anyone is interested, I'm using this as my basis for going forward...
TEST_RUNNERS = test_foo test_bar
test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c
test_bar_TESTS = tests/test_bar.c
test_bar_SOURCES = bar.c
.PHONY: test
test: unittest
#
# Template to create rules for each TEST_RUNNER defined within TEST_RUNNERS
#
# $(1) is the name of the test runner
#
define test_TEST_RUNNER_template
THE_$(1)_SOURCES = $$($(1)_TESTS)
.PHONY: unittest unittest_$(1)
unittest: unittest_$(1)
unittest_$(1):
#echo "?(1)=" $(1) "?#=" $$# " THE_$(1)_SOURCES=" $$(THE_$(1)_SOURCES)
endef
# Create a rule for all TEST_RUNNERS when "make test" is invoked...
$(foreach runner,$(TEST_RUNNERS),$(eval $(call test_TEST_RUNNER_template,$(runner))))
If you're willing to add one more line per target:
test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c
test_foo_ALL_OBJECTS := tests/test_foo.o foo.o
then a couple of pattern rules can handle all the rest:
%.o: %.c
$(CC) $(CFLAGS) -MMD -c $< -o $#
-include *.d tests/*.d
.PHONY: $(TEST_RUNNERS)
$(TEST_RUNNERS): test_% : $(DESTDIR)test_%
$(DESTDIR)test_%:
$(CC) -L$(DESTDIR) -o $# $^
(Trust me, this approach to dependency handling is much better than what you had. See here for a detailed explanation.)
If you don't like writing three lines per target, notice that the first two aren't actually used for anything and can be omitted.
If you are fond of the first two and really dislike the the third, yes, you can automate the process of constructing the object list, but it isn't worth the effort for this question.
I would like to use a static pattern rule to specify a default recipe for a class of targets, but override that recipe for a few specific targets.
Here's a trivial example that illustrates what I'm trying to do. For each directory that contains a file "test.py" I want to invoke the command "run_test.py", except when the directory is named "one" I want to invoke a different set of commands:
TESTS := $(shell find * -name "test.py" | xargs -I {} dirname {})
.PHONY: $(TESTS)
all: $(TESTS)
$(TESTS): %:
python run_test.py $#
one:
python run_test.py $# mode=1
python run_test.py $# mode=2
python check_results.py $#
This works, but gives a warning:
$ make
Makefile:12: warning: overriding commands for target `one'
Makefile:9: warning: ignoring old commands for target `one'
Is there another way to do this, or eliminate the warning?
No, you can't do that. A static pattern rule is really not a pattern rule: instead it's just a shorthand for writing a lot of explicit rules.
If you want to have most targets use one recipe but a few use another recipe, you should define a real pattern rule for "most" targets, not a static pattern rule, then use explicit rules to override:
%.o: %.cc
g++ -c $< -o $#
test.o: test.cc
g++ -Wall -c $< -o $#
Why do you want to use a static pattern rule instead of a regular pattern rule?
ETA You could also use target-specific variables:
CFLAGS =
test.o: CFLAGS = -Wall
$(OBJS): %.o: %.cc
g++ $(CFLAGS) -c $< -o $#
ETA2 OK, that's much different than your original example.
You have two obvious choices that I can see. The first is to remove the special targets from the list; something like:
SPECIAL_TESTS := one
TESTS := $(patsubst %/test.py,%,$(shell find * -name "test.py"))
.PHONY: all $(TESTS)
all: $(TESTS)
$(filter-out $(SPECIAL_TESTS),$(TESTS)):
python run_test.py $#
$(SPECIAL_TESTS):
python run_test.py $# mode=1
python run_test.py $# mode=2
python check_results.py $#
The other way to do it is with target-specific variables that define the entire recipe, something like this:
TEST_RECIPE = python run_test.py $#
one: TEST_RECIPE = python run_test.py $# mode=1 \
&& python run_test.py $# mode=2 \
&& python check_results.py $#
TESTS := $(patsubst %/test.py,%,$(shell find * -name "test.py"))
.PHONY: all $(TESTS)
all: $(TESTS)
$(TESTS):
$(TEST_RECIPE)
I am getting make file error on line 139 below at $(eval $(RULES))
I am really inexperienced in make file syntax.
This is is error it is giving me when I enter make command.
common.mak:139: *** missing separator. Stop.
I tried to removed the tab by single space, \t nothing works.
Do you know what can be the reason?
Thanks
#
# common bits used by all libraries
#
# first so "all" becomes default target
all: all-yes
ifndef SUBDIR
ifndef V
Q = #
ECHO = printf "$(1)\t%s\n" $(2)
BRIEF = CC CXX HOSTCC HOSTLD AS YASM AR LD STRIP CP
SILENT = DEPCC DEPHOSTCC DEPAS DEPYASM RANLIB RM
MSG = $#
M = #$(call ECHO,$(TAG),$#);
$(foreach VAR,$(BRIEF), \
$(eval override $(VAR) = #$$(call ECHO,$(VAR),$$(MSG)); $($(VAR))))
$(foreach VAR,$(SILENT),$(eval override $(VAR) = #$($(VAR))))
$(eval INSTALL = #$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
endif
ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample
# NASM requires -I path terminated with /
IFLAGS := -I. -I$(SRC_PATH)/
CPPFLAGS := $(IFLAGS) $(CPPFLAGS)
CFLAGS += $(ECFLAGS)
CCFLAGS = $(CPPFLAGS) $(CFLAGS)
ASFLAGS := $(CPPFLAGS) $(ASFLAGS)
CXXFLAGS += $(CPPFLAGS) $(CFLAGS)
YASMFLAGS += $(IFLAGS:%=%/) -Pconfig.asm
HOSTCCFLAGS = $(IFLAGS) $(HOSTCPPFLAGS) $(HOSTCFLAGS)
LDFLAGS := $(ALLFFLIBS:%=$(LD_PATH)lib%) $(LDFLAGS)
define COMPILE
$(call $(1)DEP,$(1))
$($(1)) $($(1)FLAGS) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $<
endef
COMPILE_C = $(call COMPILE,CC)
COMPILE_CXX = $(call COMPILE,CXX)
COMPILE_S = $(call COMPILE,AS)
%.o: %.c
$(COMPILE_C)
%.o: %.cpp
$(COMPILE_CXX)
%.s: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -S -o $# $<
%.o: %.S
$(COMPILE_S)
%.i: %.c
$(CC) $(CCFLAGS) $(CC_E) $<
%.h.c:
$(Q)echo '#include "$*.h"' >$#
%.ver: %.v
$(Q)sed 's/$$MAJOR/$($(basename $(#F))_VERSION_MAJOR)/' $^ > $#
%.c %.h: TAG = GEN
# Dummy rule to stop make trying to rebuild removed or renamed headers
%.h:
#:
# Disable suffix rules. Most of the builtin rules are suffix rules,
# so this saves some time on slow systems.
.SUFFIXES:
# Do not delete intermediate files from chains of implicit rules
$(OBJS):
endif
include $(SRC_PATH)/arch.mak
OBJS += $(OBJS-yes)
FFLIBS := $(FFLIBS-yes) $(FFLIBS)
TESTPROGS += $(TESTPROGS-yes)
LDLIBS = $(FFLIBS:%=%$(BUILDSUF))
FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(EXTRALIBS)
EXAMPLES := $(EXAMPLES:%=$(SUBDIR)%-example$(EXESUF))
OBJS := $(sort $(OBJS:%=$(SUBDIR)%))
TESTOBJS := $(TESTOBJS:%=$(SUBDIR)%) $(TESTPROGS:%=$(SUBDIR)%-test.o)
TESTPROGS := $(TESTPROGS:%=$(SUBDIR)%-test$(EXESUF))
HOSTOBJS := $(HOSTPROGS:%=$(SUBDIR)%.o)
HOSTPROGS := $(HOSTPROGS:%=$(SUBDIR)%$(HOSTEXESUF))
TOOLS += $(TOOLS-yes)
TOOLOBJS := $(TOOLS:%=tools/%.o)
TOOLS := $(TOOLS:%=tools/%$(EXESUF))
HEADERS += $(HEADERS-yes)
DEP_LIBS := $(foreach NAME,$(FFLIBS),lib$(NAME)/$($(CONFIG_SHARED:yes=S)LIBNAME))
SRC_DIR := $(SRC_PATH)/lib$(NAME)
ALLHEADERS := $(subst $(SRC_DIR)/,$(SUBDIR),$(wildcard $(SRC_DIR)/*.h $(SRC_DIR)/$(ARCH)/*.h))
SKIPHEADERS += $(ARCH_HEADERS:%=$(ARCH)/%) $(SKIPHEADERS-)
SKIPHEADERS := $(SKIPHEADERS:%=$(SUBDIR)%)
HOBJS = $(filter-out $(SKIPHEADERS:.h=.h.o),$(ALLHEADERS:.h=.h.o))
checkheaders: $(HOBJS)
.SECONDARY: $(HOBJS:.o=.c)
alltools: $(TOOLS)
$(HOSTOBJS): %.o: %.c
$(call COMPILE,HOSTCC)
$(HOSTPROGS): %$(HOSTEXESUF): %.o
$(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $< $(HOSTLIBS)
$(OBJS): | $(sort $(dir $(OBJS)))
$(HOBJS): | $(sort $(dir $(HOBJS)))
$(HOSTOBJS): | $(sort $(dir $(HOSTOBJS)))
$(TESTOBJS): | $(sort $(dir $(TESTOBJS)))
$(TOOLOBJS): | tools
OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(TESTOBJS))
CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.ho *.gcno *.gcda
DISTCLEANSUFFIXES = *.pc
LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a
define RULES
clean::
$(RM) $(OBJS) $(OBJS:.o=.d)
$(RM) $(HOSTPROGS)
$(RM) $(TOOLS)
endef
$(eval $(RULES))
-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d))
I experienced that same issue when trying to configure ffmpeg for make.
With the current version of ffmpeg's master branch the issue occurs for common.mak at line 160.
To solve this issue I tried the following steps:
git config core.autocrlf false
delete all *.mak files
git reset --hard
These steps alone did not fully solve my problem. Based on the hints regarding the TAB (\t) characters I changed line 160 from
to
Note the arrow (indicating a TAB) at line 160 between $( and eval $(RULES)).
This TAB solved the problem for me. I had to make this change to a further *.mak file. There was the same error message for another file. By the way, Notepad++ is a great tool to insert a TAB as well as for changing the line endings.
Since ffmpeg takes a while for building I decided to share my solution...
I had this exact same issue - when also checking out FFMPEG on Windows but using git.
After running configure and when trying to run make I got the same line:
common.mak:139: *** missing separator. Stop.
As suggested by #MadScientist - Makefiles are particularly fussy not just about tab (\t) but also the choice of line ending (LF vs. CRLF).
This is down to the GNU make command which has to run them - which seems to only respect LF.
So a *nix version, such as this, will work:
And here is the same file under Windows, which won't work:
(Another giveaway is that it is also bigger with double the bytes at the end of each line!)
Bottom line (so to speak) is that you might have to reformat your files - perhaps by using the dos2unix command.
This would still be the case even if not directly cloning from git - but instead downloading a tar/zip that was itself created from a git clone. The end of lines would be preserved.
Or, if using Git (directly as I was) you have to tell it how to handle the end of line characters. When it checks-out/clones and when it commits.
There is a full description of what this means here: http://adaptivepatchwork.com/2012/03/01/mind-the-end-of-your-line/
And how it can be configured (for the old version of git) via the [core].eol setting.
This is also apparent on Windows, when if you run the installer (e.g. http://git-scm.com/downloads) you get a dialogue such as this:
Selecting the final option to "checkout as-is, commit as-is" fixed it for me. Not perhaps the most principled way, but it forced the LF endings to be preserved.
In makefiles, recipe lines MUST start with a TAB character (TAB must be the first character on the line). You cannot have one or more spaces at the beginning of the line, either with or without a following TAB.
I don't know what you mean by: I tried to removed the tab by single space, \t nothing works; that sentence doesn't make sense to me. Hopefully the above paragraph will help you understand what you need to do.
Be sure you're using a text editor (not a word processor) and that your editor doesn't try to "helpfully" change the formatting in your files.
In general, unless you're more experienced with makefiles I don't recommend using the eval function, which requires a pretty clear understanding of the rules make uses for expanding variables and functions to use correctly. I'm not really sure why you're using eval in the context of the RULES variable, anyway; why not just write the rule directly without eval?
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
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.
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.