Make examples
Step-ByStep C makefile
The following examples all make reference to a sourcetree that looks like the following.
src/ libhello.h libhello.c main.c # includes libhello.hEach example below is a little cleaner than the last, but a little more abstract.
ex 1: compile everything, every time
Makefile
This will get the job done, but will recompile every file every time. Not very efficient.# ============= # configuration # ============= # compiler CC = gcc # compiler DEBUG = -g # compiler's debug flag (so can use gdb) STD = c99 # the C-standard to compile with CFLAGS = -Wall $(DEBUG) # compile-executable flags LFLAGS = -Wall -c $(DEBUG) # compile-object (.o) flags # ============= # build targets # ============= # default/implied 'make' argument # # target: depends1 depends2 ... bin/main: test -d bin || mkdir bin $(CC) -std=$(STD) $(CFLAGS) build/main.c build/libhello.c -o bin/main clean: test -d bin && rm -rf bin
ex 2: Compile .o for each file, then combine
This is much more efficent. Every file gets compiled to .o (only as-needed), then those .o files are built into your final executable.
My chief complaint here is that this makefile is going to require an exceptional amount of maintenance, defining every single .o file.
Makefile
# ============= # configuration # ============= # compiler CC = gcc # compiler DEBUG = -g # compiler's debug flag (so can use gdb) STD = c99 # the C-standard to compile with CFLAGS = -Wall $(DEBUG) # compile-executable flags LFLAGS = -Wall -c $(DEBUG) # compile-object (.o) flags # ============= # build targets # ============= # default/implied 'make' argument # # target: depends1 depends2 ... bin/main: build/main.o build/libhello.o test -d bin || mkdir bin $(CC) -std=$(STD) $(CFLAGS) build/main.o build/libhello.o -o bin/main # other possible 'make' arguments # ex: make clean # ex: make build/main.o build/main.o: test -d build || mkdir build $(CC) -std=$(STD) $(LFLAGS) src/main.c -o $@ build/libhello.o: test -d build || mkdir build $(CC) -std=$(STD) $(LFLAGS) src/libhello.c -o $@ clean: test -d build && rm -rf build test -d bin && rm -rf bin
ex 3: low-maintenance makefile
This produces exactly the same result as the 2nd-example, but it performs additional automation within the makefile.
- sourcfiles are found automatically
- .o file definitions and dependencies are produced automatically
Makefile
# ============= # configuration # ============= # compiler CC = gcc # compiler DEBUG = -g # compiler's debug flag (so can use gdb) STD = c99 # the C-standard to compile with CFLAGS = -Wall $(DEBUG) # compile-executable flags LFLAGS = -Wall -c $(DEBUG) # compile-object (.o) flags # targets SRCS = $(shell find src/ -type f -name '*.c') OBJS = $(patsubst src/%,build/%,$(SRCS:.c=.o)) # ============= # build targets # ============= # default/implied 'make' argument # # target: depends1 depends2 ... bin/main: $(OBJS) test -d bin || mkdir bin @echo $(OBJS) $(CC) -std=$(STD) $(CFLAGS) $(OBJS) -o bin/main ## IMPORTANT: if this is cpp, before $(OBJS) you must include the target's .cpp file # .o-target for each .c-file build/%.o: src/%.c test -d build || mkdir build $(CC) -std=$(STD) $(LFLAGS) -o $@ $< # other 'make' arguments clean: test -d build && rm -rf build test -d bin && rm -rf bin
$@
is the file being generated$<
name of first prerequisiteSee https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables