|
Quick Navigation Bar advanced data structures :: make and makefiles :: debugging techniques [ toc | forums ] |
Note: If the document URL does not begin with http://randu.org/tutorials/c/ then you are viewing a copy. Please direct your browser to the correct location for the most recent version. |
make in the directory, and it would call cc (gcc)
with -o hello option. But this isn't why make is
such a nice tool for program building and management.
target target_name : prerequisites ...
command
...
The target is the parameter you give make. For example make
clean would cause make to carry out the target_name
called clean. If there are any prerequisites
to process, they make will do those before proceeding.
The commands would then be executed under the target.commands
listed must be TABBED over!
edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o insert.o search.o \
files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o insert.o search.o \
files.o utils.o
Now if you change just kbd.c, it will only recompile kbd.c into
it's object file and then relink all of the object files to create
edit. Much easier than recompiling the whole project!
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h
.PHONY: clean
clean :
rm edit $(objects)
So what changed? Now we have a grouping of objects
containing all of our object files so that the edit
target only requires this variable. You may also notice that all
of the .c files are missing from the prerequisite
line. This is because make is deducing that the c source is a required
part of the target and will automatically use the c source file
associated with the object file to compile. What about the
.PHONY target? Let's say you actually have a file
called "clean". If you had just a clean target without the .PHONY,
it would never clean. To avoid this, you can use the .PHONY
target. This isn't used that often because it is rare to have
a file called "clean" in the target directory... but who knows if
you might have one?include
directive.ifdef, ifeq, ifndef, ifneq.$(objects) above.
moo.c
/ \
--- ---
/ \
foo.c bar.c
/ \
------- -------
/ \ / \
baz.c loop.h dood.c shazbot.c
/ \
------- -------
/ \ / \
mop.c <libgen.h> woot.c defs.h
Let's create a more complex, yet easier to maintain Makefile for this
project:
# Source, Executable, Includes, Library Defines
INCL = loop.h defs.h
SRC = moo.c foo.c bar.c baz.c dood.c shazbot.c mop.c woot.c
OBJ = $(SRC:.c=.o)
LIBS = -lgen
EXE = moolicious
# Compiler, Linker Defines
CC = /usr/bin/gcc
CFLAGS = -ansi -pedantic -Wall -O2
LIBPATH = -L.
LDFLAGS = -o $(EXE) $(LIBPATH) $(LIBS)
CFDEBUG = -ansi -pedantic -Wall -g -DDEBUG $(LDFLAGS)
RM = /bin/rm -f
# Compile and Assemble C Source Files into Object Files
%.o: %.c
$(CC) -c $(CFLAGS) $*.c
# Link all Object Files with external Libraries into Binaries
$(EXE): $(OBJ)
$(CC) $(LDFLAGS) $(OBJ)
# Objects depend on these Libraries
$(OBJ): $(INCL)
# Create a gdb/dbx Capable Executable with DEBUG flags turned on
debug:
$(CC) $(CFDEBUG) $(SRC)
# Clean Up Objects, Exectuables, Dumps out of source directory
clean:
$(RM) $(OBJ) $(EXE) core a.out
Now we have a clean and readable Makefile that can
manage the complete source tree. (Remember to use
tabs on the command lines!)
