Zum Inhalt

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: dependencies
    command
    command
```_

### Schlüsselbegriffe

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](https://__LINK_4___
  • GNU Make: [gnu.org/software/make](__LINK_4___
  • Tutorial: [makefiletutorial.com](__LINK_4___
  • *Best Practices: clarkgrubb.com/makefile-style-guide