Cheatsheet erstellen¶
Überblick¶
GNU Make ist ein Build Automation Tool, das automatisch ausführbare Programme und Bibliotheken aus Quellcode baut, indem Dateien namens Makefiles gelesen werden, die festlegen, wie das Zielprogramm abgeleitet werden soll.
Grundkonzepte¶
Makefile Struktur¶
Target # File to be created or action to be performed Dependency # Files that target depends on Recipe # Commands to create target Rule # Target + dependencies + recipe Variable # Named value that can be reused## Basic Makefile
### Einfaches Beispiel
```makefile
# Simple C program build
program: main.o utils.o
gcc -o program main.o utils.o
main.o: main.c
gcc -c main.c
utils.o: utils.c
gcc -c utils.c
clean:
rm -f *.o program
```_
### Mit Variablen
```makefile
CC = gcc
CFLAGS = -Wall -g
OBJECTS = main.o utils.o
TARGET = program
$(TARGET): $(OBJECTS)
$(CC) -o $(TARGET) $(OBJECTS)
main.o: main.c
$(CC) $(CFLAGS) -c main.c
utils.o: utils.c
$(CC) $(CFLAGS) -c utils.c
clean:
rm -f $(OBJECTS) $(TARGET)
.PHONY: clean
```_
## Variablen
### Variable Definition
```makefile
# Simple assignment
CC = gcc
CFLAGS = -Wall -g
# Recursive assignment (evaluated when used)
SOURCES = $(wildcard *.c)
# Simple assignment (evaluated immediately)
OBJECTS := $(SOURCES:.c=.o)
# Conditional assignment (only if not already defined)
CC ?= gcc
# Append to variable
CFLAGS += -O2
```_
### Einbauvariablen
```makefile
# Automatic variables
$@ # Target name
# Make Cheatsheet
## Overview
GNU Make is a build automation tool that automatically builds executable programs and libraries from source code by reading files called Makefiles which specify how to derive the target program.
## Basic Concepts
### Makefile Structure
```makefile
Ziel: Abhängigkeiten
Befehl
Befehl
Key Terms¶
Ziel # Datei zu erstellen oder Aktion auszuführen
Abhängigkeit # Dateien, die Ziel ist abhängig von
Rezept # Befehle, um Ziel zu erstellen
Regel # Ziel + Abhängigkeiten + Rezept
Variabler # Named-Wert, der wieder verwendet werden kann
Basic Makefile¶
Simple Example¶
# Einfache C-Programm bauen
Programm: main.o utils.o
gcc -o Programm main.o utils. o
Haupt.o: Haupt.c
gcc -c main. c)
utils.o: utils.c
gcc -c utils. c)
sauber:
rm -f *.o Programm
With Variables¶
CC = gcc
CFLAGS = -Wall -g
OBJECTS = main.o utils.o
TARGET = Programm
$(TARGET): $(OBJECTS)
$(CC) -o $(TARGET) $(OBJECTS)
Haupt.o: Haupt.c
$(CC) $(CFLAGS) -c main. c)
utils.o: utils.c
$(CC) $(CFLAGS) -c utils. c)
sauber:
rm -f $(OBJECTS) $(TARGET)
. PHONY: sauber
Variables¶
Variable Definition¶
# Einfache Zuordnung
CC = gcc
CFLAGS = -Wall -g
# Wiederkehrende Zuordnung (bewertet bei Verwendung)
GERICHTE = $(wildcard *.c)
# Einfache Zuordnung (ausgewertet sofort)
OBJECTS:= $(SOURCEN:.c=.o)
# Zustandszuweisung (nur wenn nicht bereits definiert)
CC ?= gcc
# Anpassung an Variable
CFLAGS += -O2
Built-in Variables¶
`< # First dependency $^ # All dependencies $? # Dependencies newer than target $* # Stem of pattern rule match
Example usage¶
%.o: %.c $(CC) $(CFLAGS) -c $< -o $@ ```_
Umweltvariablen¶
```makefile
Use environment variables¶
HOME_DIR = $(HOME) PATH_VAR = $(PATH)
Override environment variables¶
export CC = gcc export CFLAGS = -Wall ```_
Musterregeln¶
Grundmuster¶
```makefile
Pattern rule for C files¶
%.o: %.c $(CC) $(CFLAGS) -c $< -o $@
Pattern rule for C++ files¶
%.o: %.cpp $(CXX) $(CXXFLAGS) -c $< -o $@
Multiple patterns¶
%.o: %.c %.h $(CC) $(CFLAGS) -c $< -o $@ ```_
Erweiterte Muster¶
```makefile
Static pattern rule¶
$(OBJECTS): %.o: %.c $(CC) $(CFLAGS) -c $< -o $@
Pattern with subdirectories¶
build/%.o: src/%.c @mkdir -p build $(CC) $(CFLAGS) -c $< -o $@ ```_
Funktionen¶
String Funktionen¶
```makefile
Substitution¶
SOURCES = main.c utils.c OBJECTS = $(SOURCES:.c=.o)
or¶
OBJECTS = \((patsubst %.c,%.o,\)(SOURCES))
Word functions¶
FIRST_WORD = $(firstword $(SOURCES)) WORD_COUNT = $(words $(SOURCES)) NTH_WORD = \((word 2,\)(SOURCES))
Filter functions¶
C_FILES = \((filter %.c,\)(SOURCES)) NOT_MAIN = \((filter-out main.c,\)(SOURCES)) ```_
Dateifunktionen¶
```makefile
Wildcard¶
SOURCES = $(wildcard src/.c) HEADERS = $(wildcard include/.h)
Directory functions¶
SRC_DIRS = $(dir $(SOURCES)) BASE_NAMES = $(notdir $(SOURCES)) BASENAMES = $(basename $(SOURCES)) SUFFIXES = $(suffix $(SOURCES))
Path manipulation¶
ABS_PATH = $(abspath relative/path) REAL_PATH = $(realpath symlink/path) ```_
Bedingte Funktionen¶
```makefile
If function¶
RESULT = $(if $(DEBUG),debug,release)
Or function¶
COMPILER = $(or $(CC),gcc)
And function¶
VALID = $(and \((CC),\)(SOURCES)) ```_
Bedingte Aussagen¶
ifeq/ifneq¶
```makefile ifeq ($(DEBUG),1) CFLAGS += -g -DDEBUG else CFLAGS += -O2 -DNDEBUG endif
ifneq ($(OS),Windows_NT) CFLAGS += -fPIC endif ```_
ifdef/ifndef¶
```makefile ifdef DEBUG CFLAGS += -g endif
ifndef CC CC = gcc endif ```_
Zustandszuweisung¶
```makefile
Set if not already defined¶
CC ?= gcc
Set based on condition¶
CFLAGS = $(if $(DEBUG),-g -O0,-O2) ```_
Erweiterte Funktionen¶
Dateien einschließen¶
```makefile
Include other makefiles¶
include config.mk include $(wildcard *.d)
Silent include (no error if file doesn't exist)¶
-include optional.mk ```_
Dependance Generation¶
```makefile
Automatic dependency generation¶
DEPDIR := .deps DEPFLAGS = -MT $@ -MMD -MP -MF \((DEPDIR)/\)*.d
%.o: %.c \((DEPDIR)/%.d|\)(DEPDIR) $(CC) $(DEPFLAGS) $(CFLAGS) -c $< -o $@
$(DEPDIR): @mkdir -p $@
DEPFILES := \((SOURCES:%.c=\)(DEPDIR)/%.d) $(DEPFILES):
include $(wildcard $(DEPFILES)) ```_
Nur Voraussetzungen¶
```makefile
Create directory before building objects¶
\((OBJECTS):|\)(OBJDIR)
$(OBJDIR): mkdir -p $(OBJDIR) ```_
Phony Ziele¶
Gemeinsame Phony Ziele¶
```makefile .PHONY: all clean install test help
all: $(TARGET)
clean: rm -f $(OBJECTS) $(TARGET)
install: $(TARGET) cp $(TARGET) /usr/local/bin/
test: \((TARGET) ./\)(TARGET) --test
help: @echo "Available targets:" @echo " all - Build the program" @echo " clean - Remove build files" @echo " install - Install the program" @echo " test - Run tests" ```_
Multi-Target baut¶
Mehrere Programme¶
```makefile PROGRAMS = client server COMMON_OBJS = utils.o network.o
all: $(PROGRAMS)
client: client.o $(COMMON_OBJS) $(CC) -o $@ $^
server: server.o $(COMMON_OBJS) $(CC) -o $@ $^
clean: rm -f *.o $(PROGRAMS)
.PHONY: all clean ```_
Bibliotheksgebäude¶
```makefile LIBNAME = libutils STATIC_LIB = $(LIBNAME).a SHARED_LIB = $(LIBNAME).so LIB_OBJS = utils.o network.o
all: $(STATIC_LIB) $(SHARED_LIB)
$(STATIC_LIB): $(LIB_OBJS) ar rcs $@ $^
$(SHARED_LIB): $(LIB_OBJS) $(CC) -shared -o $@ $^
%.o: %.c $(CC) $(CFLAGS) -fPIC -c $< -o $@ ```_
Verwendung der Befehlszeile¶
Grundlegende Befehle¶
```bash
Build default target¶
make
Build specific target¶
make clean make install
Build with variables¶
make DEBUG=1 make CC=clang
Parallel builds¶
make -j4 make -j$(nproc)
Dry run (show commands without executing)¶
make -n
Silent mode¶
make -s
Keep going on errors¶
make -k ```_
Debugging¶
```bash
Print variables¶
make -p
Debug mode¶
make -d
Print database¶
make --print-data-base
Trace execution¶
make --trace ```_
Komplexe Beispiele¶
C++ Projekt¶
```makefile CXX = g++ CXXFLAGS = -std=c++17 -Wall -Wextra -g LDFLAGS = -lpthread
SRCDIR = src OBJDIR = obj SOURCES = $(wildcard \((SRCDIR)/*.cpp) OBJECTS = \((SOURCES:\)(SRCDIR)/%.cpp=\)(OBJDIR)/%.o) TARGET = myprogram
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJECTS) $(CXX) $(OBJECTS) -o $@ $(LDFLAGS)
$(OBJDIR)/%.o: \((SRCDIR)/%.cpp|\)(OBJDIR) $(CXX) $(CXXFLAGS) -c $< -o $@
$(OBJDIR): mkdir -p $(OBJDIR)
clean: rm -rf $(OBJDIR) $(TARGET)
Dependency generation¶
-include $(OBJECTS:.o=.d)
$(OBJDIR)/%.d: \((SRCDIR)/%.cpp|\)(OBJDIR) $(CXX) -MM -MT $(@:.d=.o) $< >`` $@ ```_
Multidirektorprojekt¶
```makefile
Project structure¶
PROJECT_ROOT = . SRC_DIRS = src src/utils src/network INC_DIRS = include OBJ_DIR = build BIN_DIR = bin
Find all source files¶
SOURCES = \((foreach dir,\)(SRC_DIRS),$(wildcard $(dir)/*.c)) OBJECTS = \((SOURCES:%.c=\)(OBJ_DIR)/%.o) TARGET = $(BIN_DIR)/myapp
Compiler settings¶
CC = gcc CFLAGS = -Wall -g \((addprefix -I,\)(INC_DIRS)) LDFLAGS = -lm
.PHONY: all clean dirs
all: dirs $(TARGET)
dirs: @mkdir -p \((OBJ_DIR) ((BIN_DIR) @mkdir -p \((foreach dir,\)(SRC_DIRS),\)(OBJ_DIR)/\)(dir))
$(TARGET): $(OBJECTS) $(CC) $^ -o $@ $(LDFLAGS)
$(OBJ_DIR)/%.o: %.c $(CC) $(CFLAGS) -c $< -o $@
clean: rm -rf $(OBJ_DIR) $(BIN_DIR) ```_
Best Practices¶
Makefile Organisation¶
```makefile
Variables at the top¶
CC = gcc CFLAGS = -Wall -g TARGET = myprogram
Default target first¶
all: $(TARGET)
Pattern rules¶
%.o: %.c $(CC) $(CFLAGS) -c $< -o $@
Specific rules¶
$(TARGET): $(OBJECTS) $(CC) $^ -o $@
Phony targets at the end¶
.PHONY: all clean install
clean: rm -f *.o $(TARGET) ```_
Fehlerbehebung¶
```makefile
Check for required tools¶
ifeq ($(shell which $(CC)),) $(error Compiler $(CC) not found) endif
Validate variables¶
ifndef SOURCES $(error SOURCES variable is not defined) endif
Conditional compilation¶
ifeq ($(shell pkg-config --exists gtk+-3.0; echo $?),0) CFLAGS += $(shell pkg-config --cflags gtk+-3.0) LDFLAGS += $(shell pkg-config --libs gtk+-3.0) else $(warning GTK+ 3.0 not found, building without GUI) endif ```_
Leistungsspitzen¶
```makefile
Use order-only prerequisites for directories¶
\((OBJECTS):|\)(OBJDIR)
Minimize shell calls¶
SOURCES := $(shell find src -name '*.c')
Use built-in rules when possible¶
Instead of:¶
%.o: %.c¶
$(CC) $(CFLAGS) -c $< -o $@¶
Just use the built-in rule¶
Parallel-safe directory creation¶
$(OBJDIR): @mkdir -p $@ ```_
Integration¶
Mit Versionskontrolle¶
```makefile
Get version from git¶
VERSION = \((shell git describe --tags --always --dirty) CFLAGS += -DVERSION=\"\)(VERSION)\"
Include git info¶
GIT_COMMIT = \((shell git rev-parse HEAD) BUILD_DATE = \((shell date -u +"%Y-%m-%dT%H:%M:%SZ") CFLAGS += -DGIT_COMMIT=\"\)(GIT_COMMIT)\" -DBUILD_DATE=\"\)(BUILD_DATE)\" ```_
Mit Paketmanagern¶
```makefile
pkg-config integration¶
CFLAGS += $(shell pkg-config --cflags libssl) LDFLAGS += $(shell pkg-config --libs libssl)
Check dependencies¶
check-deps: @pkg-config --exists libssl||(echo "libssl not found" && exit 1) ```_
Fehlerbehebung¶
Gemeinsame Themen¶
```bash
Missing separator error¶
Make sure recipes use tabs, not spaces¶
Target not found¶
make: *** No rule to make target 'foo'. Stop.
Check target name and dependencies¶
Circular dependency¶
make: Circular dependency dropped.
Review dependency chain¶
Debug makefile¶
make -p|grep target_name make -d ```_
Debugging Tipps¶
```makefile
Print variable values¶
debug: @echo "CC = $(CC)" @echo "CFLAGS = $(CFLAGS)" @echo "SOURCES = $(SOURCES)" @echo "OBJECTS = $(OBJECTS)"
Check if file exists¶
check-file: @test -f myfile.c && echo "File exists"||echo "File missing" ```_
Ressourcen¶
- Amtshandbuch: [gnu.org/software/make/manual](LINK_4_
- GNU Make: [gnu.org/software/make](LINK_4_
- Tutorial: [makefiletutorial.com](LINK_4_
- **Best Practices*: clarkgrubb.com/makefile-style-guide