To use it, just set the list of variables to print on the command line, and include the debug target: $ make V="USERNAME SHELL" debug makefile:2: USERNAME = Owner makefile:2: SHELL = /bin/sh.exe make: debug is up to date. Now you can print variables by simply listing them on the command line.
Unfortunately, there is no such thing as a makefile debugger to examine how a particular rule is being evaluated or a variable expanded. Instead, most debugging is performed with simple print state- ments and by inspection of the makefile.
The Debug configuration of your program is compiled with full symbolic debug information which help the debugger figure out where it is in the source code. Is Release mode is faster than Debug mode ? The Release mode enables optimizations and generates without any debug data, so it is fully optimized. .
You can use Target-specific Variable Values. Example:
CXXFLAGS = -g3 -gdwarf2
CCFLAGS = -g3 -gdwarf2
all: executable
debug: CXXFLAGS += -DDEBUG -g
debug: CCFLAGS += -DDEBUG -g
debug: executable
executable: CommandParser.tab.o CommandParser.yy.o Command.o
$(CXX) -o output CommandParser.yy.o CommandParser.tab.o Command.o -lfl
CommandParser.yy.o: CommandParser.l
flex -o CommandParser.yy.c CommandParser.l
$(CC) -c CommandParser.yy.c
Remember to use $(CXX) or $(CC) in all your compile commands.
Then, 'make debug' will have extra flags like -DDEBUG and -g where as 'make' will not.
On a side note, you can make your Makefile a lot more concise like other posts had suggested.
This question has appeared often when searching for a similar problem, so I feel a fully implemented solution is warranted. Especially since I (and I would assume others) have struggled piecing all the various answers together.
Below is a sample Makefile which supports multiple build types in separate directories. The example illustrated shows debug and release builds.
Supports ...
#
# Compiler flags
#
CC = gcc
CFLAGS = -Wall -Werror -Wextra
#
# Project files
#
SRCS = file1.c file2.c file3.c file4.c
OBJS = $(SRCS:.c=.o)
EXE = exefile
#
# Debug build settings
#
DBGDIR = debug
DBGEXE = $(DBGDIR)/$(EXE)
DBGOBJS = $(addprefix $(DBGDIR)/, $(OBJS))
DBGCFLAGS = -g -O0 -DDEBUG
#
# Release build settings
#
RELDIR = release
RELEXE = $(RELDIR)/$(EXE)
RELOBJS = $(addprefix $(RELDIR)/, $(OBJS))
RELCFLAGS = -O3 -DNDEBUG
.PHONY: all clean debug prep release remake
# Default build
all: prep release
#
# Debug rules
#
debug: $(DBGEXE)
$(DBGEXE): $(DBGOBJS)
$(CC) $(CFLAGS) $(DBGCFLAGS) -o $(DBGEXE) $^
$(DBGDIR)/%.o: %.c
$(CC) -c $(CFLAGS) $(DBGCFLAGS) -o $@ $<
#
# Release rules
#
release: $(RELEXE)
$(RELEXE): $(RELOBJS)
$(CC) $(CFLAGS) $(RELCFLAGS) -o $(RELEXE) $^
$(RELDIR)/%.o: %.c
$(CC) -c $(CFLAGS) $(RELCFLAGS) -o $@ $<
#
# Other rules
#
prep:
@mkdir -p $(DBGDIR) $(RELDIR)
remake: clean all
clean:
rm -f $(RELEXE) $(RELOBJS) $(DBGEXE) $(DBGOBJS)
If by configure release/build, you mean you only need one config per makefile, then it is simply a matter and decoupling CC and CFLAGS:
CFLAGS=-DDEBUG
#CFLAGS=-O2 -DNDEBUG
CC=g++ -g3 -gdwarf2 $(CFLAGS)
Depending on whether you can use gnu makefile, you can use conditional to make this a bit fancier, and control it from the command line:
DEBUG ?= 1
ifeq ($(DEBUG), 1)
CFLAGS =-DDEBUG
else
CFLAGS=-DNDEBUG
endif
.o: .c
$(CC) -c $< -o $@ $(CFLAGS)
and then use:
make DEBUG=0
make DEBUG=1
If you need to control both configurations at the same time, I think it is better to have build directories, and one build directory / config.
Note that you can also make your Makefile simpler, at the same time:
DEBUG ?= 1
ifeq (DEBUG, 1)
CFLAGS =-g3 -gdwarf2 -DDEBUG
else
CFLAGS=-DNDEBUG
endif
CXX = g++ $(CFLAGS)
CC = gcc $(CFLAGS)
EXECUTABLE = output
OBJECTS = CommandParser.tab.o CommandParser.yy.o Command.o
LIBRARIES = -lfl
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CXX) -o $@ $^ $(LIBRARIES)
%.yy.o: %.l
flex -o $*.yy.c $<
$(CC) -c $*.yy.c
%.tab.o: %.y
bison -d $<
$(CXX) -c $*.tab.c
%.o: %.cpp
$(CXX) -c $<
clean:
rm -f $(EXECUTABLE) $(OBJECTS) *.yy.c *.tab.c
Now you don't have to repeat filenames all over the place. Any .l files will get passed through flex and gcc, any .y files will get passed through bison and g++, and any .cpp files through just g++.
Just list the .o files you expect to end up with, and Make will do the work of figuring out which rules can satisfy the needs...
for the record:
$@
The name of the target file (the one before the colon)
$<
The name of the first (or only) prerequisite file (the first one after the colon)
$^
The names of all the prerequisite files (space separated)
$*
The stem (the bit which matches the %
wildcard in the rule definition.
you can have a variable
DEBUG = 0
then you can use a conditional statement
ifeq ($(DEBUG),1)
else
endif
Completing the answers from earlier... You need to reference the variables you define info in your commands...
DEBUG ?= 1
ifeq (DEBUG, 1)
CFLAGS =-g3 -gdwarf2 -DDEBUG
else
CFLAGS=-DNDEBUG
endif
CXX = g++ $(CFLAGS)
CC = gcc $(CFLAGS)
all: executable
executable: CommandParser.tab.o CommandParser.yy.o Command.o
$(CXX) -o output CommandParser.yy.o CommandParser.tab.o Command.o -lfl
CommandParser.yy.o: CommandParser.l
flex -o CommandParser.yy.c CommandParser.l
$(CC) -c CommandParser.yy.c
CommandParser.tab.o: CommandParser.y
bison -d CommandParser.y
$(CXX) -c CommandParser.tab.c
Command.o: Command.cpp
$(CXX) -c Command.cpp
clean:
rm -f CommandParser.tab.* CommandParser.yy.* output *.o
You could also add something simple to your Makefile such as
ifeq ($(DEBUG),1)
OPTS = -g
endif
Then compile it for debugging
make DEBUG=1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With