Makefiles are flexible in many ways, it's a small language in itself.
As I said in a post before, I normally write the same
Makefile over and over, even just for compiling a simple project with two or more files. The there proposed
Makefile, however, grew quite big during the writing of the post.
Today I want to present you a variant which is tiny, yet compiles your small to medium projects just fine, while still having dependency tracking and incremental compilation. To do this, I'll make use of some of
makes very convenient implicit rules.
The implicit rules of
make for compiling a C file look like this:
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH) OUTPUT_OPTION = -o $@ %.o: %.c $(COMPILE.c) $(OUTPUT_OPTION) $< %: %.o $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
Making use of these builtin rules, a basic
Makefile can be as simple as:
(make sure the executable target contains at least one object file with the same name, or the executale won't be linked)
CC = gcc SRC = $(wildcard *.c) OBJ = $(SRC:.c=.o) .PHONY: clean foo: foo.o clean: rm -f $(OBJ) foo
While this works, and is a variant of the
Makefile I write for every tiny project, it does not yet track dependencies on headers, or other include files, requiring you to manually clean the project and recompile.
Modern compilers (gcc > 4, clang > 3.0 and ICC > 12.1) support the options
-MP, which will generate dependency files (without using
sed, which was required with
Neither does it respect the environment variable
CC, nor does it generate debuggable executables.
After applying these changes, this is the resulting
CC = gcc DEBUG = -ggdb -O0 -march=native CFLAGS := $(DEBUG) -W -Wall -Wextra -Wpedantic -pedantic -ansi LDLIBS := -lm OUTPUT_OPTION = -MMD -MP -o $@ SRC := $(wildcard *.c) OBJ := $(SRC:.c=.o) DEP := $(SRC:.c=.d) -include $(DEP) .PHONY: clean all: test1 test1: test1.o clean: -rm -f $(OBJ) $(DEP) test1
It now correctly tracks dependencies, respects the
CC environment variable, generates
gdb debugging symbols, and has some default compiler / warning flags.