Aller au contenu

Faire une feuille de chaleur

Aperçu général

GNU Make est un outil d'automatisation de construction qui construit automatiquement des programmes exécutables et des bibliothèques à partir du code source en lisant des fichiers appelés Makefiles qui précisent comment dériver le programme cible.

Concepts de base

Structure du fichier de marque

target: dependencies
    command
    command

Termes clés

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
```_

## Fichier Make de base

### Exemple simple
```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
```_

### Avec variables
```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

Variables

Définition variable

# 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

Variables intégrées

# 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
```_fichier de make
cible: dépendances
commande
commande

Key Terms

Cible # Fichier à créer ou action à exécuter
Dépendance # Fichiers dont la cible dépend
Recette # Commandes pour créer une cible
Règle # Cible + dépendances + recette
Variable # Valeur nommée pouvant être réutilisée

Basic Makefile

Simple Example

# Construction de programme C simple
programme: main.o utils.o
gcc -o programme main.o utils. o

main.o: main.c
Gcc -c principal. c

utils.o: utils.c
- C'est des articles. c

nettoyer:
rm -f *.o programme

With Variables

```fichier de make CC = gcc CFLAGS = -Taille -g OBJECTIFS = main.o utils.o TARGET = programme

$(TARGET): $(OBJECTIFS) $(CC) -o $(TARGET) $(OBJETS)

main.o: main.c $(CC) $(CFLAGS) -c principal. c

utils.o: utils.c $(CC) $(CFLAGS) -c utils. c

nettoyer: rm -f $(OBJECTS) $(TARGET)

. PHYSIQUE: propre


## Variables

### Variable Definition
```fichier de make
# Attribution simple
CC = gcc
CFLAGS = -Taille -g

# Affectation récursive (évaluée en cas d'utilisation)
SOURCES = $(carte blanche *.c)

# Affectation simple (évaluée immédiatement)
OBJECTIFS := $(SOURCES:.c=.o)

# Affectation conditionnelle (seulement si elle n'est pas déjà définie)
CC ?= gcc

# Ajouter à la variable
CLAGS += -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 $@


### Variables d'environnement
```makefile
# Use environment variables
HOME_DIR = $(HOME)
PATH_VAR = $(PATH)

# Override environment variables
export CC = gcc
export CFLAGS = -Wall

Règles de configuration

Modèles de base

# 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 $@

Modèles avancés

# Static pattern rule
$(OBJECTS): %.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

# Pattern with subdirectories
build/%.o: src/%.c
    @mkdir -p build
    $(CC) $(CFLAGS) -c $< -o $@

Fonctions

Fonctions de chaîne

# 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))

Fonctions de fichiers

# 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)

Fonctions conditionnelles

# If function
RESULT = $(if $(DEBUG),debug,release)

# Or function
COMPILER = $(or $(CC),gcc)

# And function
VALID = $(and $(CC),$(SOURCES))

Déclarations conditionnelles

ideq/ifneq

ifeq ($(DEBUG),1)
    CFLAGS += -g -DDEBUG
else
    CFLAGS += -O2 -DNDEBUG
endif

ifneq ($(OS),Windows_NT)
    CFLAGS += -fPIC
endif

ifdef/ifndef

ifdef DEBUG
    CFLAGS += -g
endif

ifndef CC
    CC = gcc
endif

Affectation conditionnelle

# Set if not already defined
CC ?= gcc

# Set based on condition
CFLAGS = $(if $(DEBUG),-g -O0,-O2)

Caractéristiques avancées

Inclure les fichiers

# Include other makefiles
include config.mk
include $(wildcard *.d)

# Silent include (no error if file doesn't exist)
-include optional.mk

Génération de dépendance

# 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))

Commande seulement les conditions préalables

# Create directory before building objects
$(OBJECTS):|$(OBJDIR)

$(OBJDIR):
    mkdir -p $(OBJDIR)

Objectifs fictifs

Cibles de contrefaçon communes

.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"

Constructions multi-cibles

Programmes multiples

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

Bâtiment de la bibliothèque

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 $@

Utilisation de la ligne de commande

Commandes de base

# 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

Déboguement

# Print variables
make -p

# Debug mode
make -d

# Print database
make --print-data-base

# Trace execution
make --trace

Exemples complexes

C++ Projet

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) $< >`` $@

Projet pluridirectionnel

# 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)

Meilleures pratiques

Organisation de 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)

Gestion des erreurs

# 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

Conseils de performance

# 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 $@

Intégration

Avec contrôle de version

# 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)\"

Avec les gestionnaires de paquets

# 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)

Dépannage

Questions communes

# 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

Conseils de débogage

# 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"

Ressources

  • Manuel officiel : [gnu.org/software/make/manual] (LINK_4)
  • GNU Make: [gnu.org/software/make] (LINK_4)
  • Tutorial: makefiletutorial.com
  • Meilleures pratiques: [clarkgrubb.com/makefile-style-guide] (LINK_4)