Last active
January 23, 2023 12:02
-
-
Save maelvls/dd321db21fb33ed7b57a to your computer and use it in GitHub Desktop.
Exemple de Makefile où j'ai noté tout ce que j'avais appris sur Makefile/make
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# ANCIEN MAKEFILE Inutile maintenant ; on utilisera ./configure; make | |
# | |
# makefile | |
# Mael Valais, 2014-04-07 15:23 | |
# | |
# Makefile permettant la compilation du projet climso-auto | |
# NOTE: les # */ sont là à cause de Xcode | |
# | |
# A faire : | |
# - comprendre VPATH (les espaces ? pas d'espaces?) (OK) | |
# - essayer de comprendre les .d et -MF (PRESQUE OK) | |
# - comprendre ce qu'est un CFLAGS, CXXFLAGS (OK -> -g) | |
# | |
# Déroulement d'une compilation : | |
# - pré-compilation puis compilation en .o grâce à CC (-I pour les includes) | |
# - linkage des .o grâce à LD (-L pour les répertoires des librairies, -l pour les archives .a) | |
# -lm cherche donc libm.a ou libm.dylib | |
# -L/usr/local/lib permet à LD de trouver des trucs qui ne sont pas dans le PATH_LIB_JECONNAISPAS | |
# par défaut | |
# Il faut tester si BINDIR et OBJDIR existent | |
# Si pas en std=c99, alors on ne peut pas déclarer une variable dans un for(int...) | |
# NOTES GÉNÉRALES SUR LE MAKEFILE ET MAKE | |
# Sur ça : | |
# all: | |
# cd dir | |
# pwd | |
# `pwd` retournera exactement la même chose qu'avant le `cd dir`, pour la bonne raison | |
# que `make` utilise, pour chaque nouvelle ligne, un nouveau "sous-shell". | |
# `.PHONY all`: il s'agit de s'assurer que le target "all" ne soit pas cherché comme | |
# étant un fichier, car "all" n'est qu'un target artificiel, une sorte d'alias | |
# ATTENTION: l'assignation des variables CFLAGS, CXXFLAGS, CC, CXX & cie doit se faire | |
# sans écraser celles qui ont (peut-être) été données par l'utilisateur en faisant par exemple : | |
# make CPPFLAGS=-I. CXXFLAGS=-g LDFLAGS=-L. CXX=gcc-5 | |
# Pour faire cela, il y a plusieurs types d'assignations : | |
# CPPFLAGS = value -> remplace variable existante; la valeur est "expanded" à l'appel | |
# CPPFLAGS := value -> remplace variable existante; la valeur est "expanded" à la déclaration | |
# CPPFLAGS := value -> | |
# CPPFLAGS += value -> ajoute à la suite du CPPFLAGS existant | |
# CPPFLAGS ?= value -> n'assigne QUE si CPPFLAGS n'était pas déjà assignée | |
# NOTE: Je parle de "expension" ou de variables "expended" pour parler du moment où elles sont | |
# remplacées par leurs valeurs réelles. | |
# Variables shell locales dans une commande dans un makefile: | |
# Les variables $var sont d'abord évaluées par `make`. Donc si j'écris une target avec une commande | |
# shell qui contient une variable locale, elle sera remplacée par make avant que le shell ne puisse | |
# l'évaluer. Il faut 'échapper' les variables avec deux dollars: $$var | |
# Exemple: | |
# src/version.ml: | |
# @V=`git describe --tags`; echo $$V | |
# | |
# Variables diverses | |
# | |
# Dossier des Sources (.c, .cpp,.h) | |
SRCDIR=Sources | |
# Dossier des librairies (.c, .cpp, .h) | |
SRCLIBDIR=Libraries | |
FILTER=main camera_sbig_lib | |
# Dossier des objets .o | |
OBJDIR=Builds | |
# Dossier des exécutables .out | |
BINDIR=. | |
# Nom de l'exécutable en sortie | |
BIN=a.out | |
# Librairies EXTERNES (exple -L/usr/local/lib) utilisées par le linker | |
# Par défaut, c'est dans LD_LIBRARY_PATH (mais pas sur MacOSX je crois) | |
EXTERN_INCLUDES= -I/usr/local/include | |
EXTERN_LIBS_DIR= -L/usr/local/lib | |
EXTERN_LIBS=-lm -ltiff | |
# | |
# Les variables des règles implicites et explicites | |
# | |
# Utiliser les préprocesseurs/compilateur/linker indépendament: | |
# - `gcc -E` permet de lancer le préprocesseur seulement | |
# - `gcc -c` permet de lancer préproc+parser+type check | |
# +generation/optimisation code => fichier assembleur "objet" .o | |
# | |
# Variable de préproceseur | |
CPPFLAGS= # Exemple: -DDEBUG=1, -I/usr/local/include | |
# Variables de compilation (.c, .cpp) | |
CFLAGS= # Les .c (avec gcc) Exemple: -g, -O3 | |
CXXFLAGS= # Les .cpp Exemple: -g, -O0 | |
CPATH=/usr/local/include/:/usr/include/ # Équivalent PATH pour chemins vers headers/includes | |
# NOTE: C_INCLUDE_PATH, CPLUS_INCLUDE_PATH | |
# sont équivalents mais spécifiques pour | |
# chaque langage | |
# Variables de choix du compilateur | |
CC=clang # Compilateur .c | |
CXX=clang++ # Compilateur .cpp | |
# Variable de linkage (ld/llvm) | |
LDFLAGS=$(EXTERN_LIBS) # Exemple: -liconv, -lm, -L/usr/local/lib | |
LD_LIBRARY_PATH=/usr/local/lib/:/usr/lib/ # Équivalent PATH pour chemins vers librairies | |
RM=rm -rf $(OBJDIR)/*.o $(BINDIR)/$(BIN) # */ | |
# EXPLICATION : | |
# CC et CFLAGS sont des variables qui conditionnent les règles implicites ; | |
# Par exemple, si une dépendance foo.o ne trouve aucune règle exlicite | |
# "foo.o: foo.c", alors make fait appel à la règle implicite | |
# foo.o: foo.c | |
# $(CC) -c (la compilation) | |
# | |
# Définition des différents main.c liés à chaque règle (arduino, all...) | |
# NOTE: "all", "arduino"... ont besoin d'un main.c | |
# | |
MAIN_TEST_ALL=main_global.c | |
MAIN_TEST_ARDUINO=main_arduino.c | |
MAIN_TEST_CAMERA=main_camera.c | |
MAIN_TEST_POSITION=main_position.c | |
# | |
# Fonctions | |
# | |
# Supprimer les blancs | |
# $(call nospaces,a b c d ) donne abcd | |
space:=$(subst , ,) | |
nospaces=$(subst $(space),,$(1)) | |
# NOTE : Wildcard permet de "développer" le contenu avec * par exemple (comme en shell) | |
# Wildcard récursif. Appel : $(call rwildcard, , *.c) pour le rep. courant | |
rwildcard=$(foreach d,$(wildcard $(1)*),$(call rwildcard,$d/,$(2)) $(filter $(subst *,%,$(2)),$d)) | |
# Supprime tous les termes de CHAINE contenant TERME quelque part | |
# $(call filter_out_multiple,TERME,CHAINE) | |
recursive_rep=$(sort $(dir $(call rwildcard,$(1),*))) | |
filter_out = $(foreach v,$(2),$(if $(findstring $(1),$(v)),,$(v))) | |
# Supprime tous les termes de CHAINE où existent le TERME1 ou TERME2... | |
# $(call filter_out_multiple,TERME1 TERME2 (...),CHAINE) | |
filter_out_multiple = $(foreach v,$(2), $(if $(call nospaces,$(foreach p,$(1),$(if $(findstring $(p),$(v)),n,))),,$(v))) | |
# | |
# Préparation du VPATH qui permettra à make de chercher les sources aux bons endroits | |
# lors de la phase de build | |
# | |
SRCLIBDIR := $(call recursive_rep,$(SRCLIBDIR)) | |
SRCDIR := $(call recursive_rep,$(SRCDIR)) | |
VPATH := $(SRCDIR) $(SRCLIBDIR) # */ # Où trouver les SOURCES (libs, .c...) | |
# | |
# Construction de la liste des objets à build des les sources | |
# | |
LIST_OBJ := $(subst .c,.o,$(call rwildcard,$(SRCDIR),*.c)) | |
LIST_OBJ += $(subst .cpp,.o,$(call rwildcard,$(SRCDIR),*.cpp)) | |
LIST_OBJ := $(call filter_out_multiple,$(FILTER),$(LIST_OBJ)) # On filtre (main.c..) | |
LIST_OBJ := $(addprefix $(OBJDIR)/,$(notdir $(LIST_OBJ))) # On enlève les repertoires | |
# | |
# Construction de la liste des objets à build des les librairies | |
# | |
LIST_OBJ_LIB := $(subst .c,.o,$(call rwildcard,$(SRCLIBDIR),*.c)) | |
LIST_OBJ_LIB += $(subst .cpp,.o,$(call rwildcard,$(SRCLIBDIR),*.cpp)) | |
LIST_OBJ_LIB := $(call filter_out_multiple,$(FILTER),$(LIST_OBJ_LIB)) # On filtre (main.c..) | |
LIST_OBJ_LIB := $(addprefix $(OBJDIR)/,$(notdir $(LIST_OBJ_LIB))) # On enlève les repertoires | |
# | |
# Construction des includes (les headers) | |
# | |
#USER_INCLUDES := $(SRCDIR) $(SRCLIBDIR) | |
#USER_INCLUDES := $(addprefix -I,$(USER_INCLUDES)) | |
USER_INCLUDES := $(addprefix -I,$(sort $(dir $(call rwildcard, ,*.h)))) | |
# | |
# Build (sources, librairies) | |
# | |
$(OBJDIR)/%.o: %.c $(OBJDIR) | |
$(CC) $(USER_INCLUDES) $(EXTERN_INCLUDES) $(CPPFLAGS) $(CFLAGS) -o $@ -c $< | |
$(OBJDIR)/%.o: %.cpp $(OBJDIR) | |
$(CXX) $(USER_INCLUDES) $(EXTERN_INCLUDES) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $< | |
arduino: $(OBJDIR)/$(MAIN_TEST_ARDUINO:.c=.o) $(addprefix $(OBJDIR),cmd_arduino.o) | |
$(CXX) $(EXTERN_LIBS_DIR) $(LDFLAGS) $^ -o $(BINDIR)/$(BIN) | |
camera: $(OBJDIR)/$(MAIN_TEST_CAMERA:.c=.o) $(LIST_OBJ) $(LIST_OBJ_LIB) | |
$(CXX) $(EXTERN_LIBS_DIR) $(LDFLAGS) $^ -o $(BINDIR)/$(BIN) | |
position: $(OBJDIR)/$(MAIN_TEST_POSITION:.c=.o) $(LIST_OBJ) $(LIST_OBJ_LIB) | |
$(CXX) $(EXTERN_LIBS_DIR) $(LDFLAGS) $^ -o $(BINDIR)/$(BIN) | |
all: $(OBJDIR)/$(MAIN_TEST_ALL:.c=.o) $(LIST_OBJ) $(LIST_OBJ_LIB) $(BINDIR) | |
$(CXX) $(EXTERN_LIBS_DIR) $(LDFLAGS) $^ -o $(BINDIR)/$(BIN) | |
clean: | |
$(RM) | |
$(BINDIR): | |
$(OBJDIR): | |
@echo "--------- Creation du dossier $@ ---------" | |
@mkdir $@ | |
essai: | |
@echo "---------------ESSAI----------------" | |
@echo "Liste des objets : $(LIST_OBJ)" | |
@echo "Liste des objets librairie : $(LIST_OBJ_LIB)" | |
@echo "USER_INCLUDES : $(USER_INCLUDES)" | |
@echo "EXTERN_INCLUDES : $(EXTERN_INCLUDES)" | |
@echo "EXTERN_LIBS_DIR : $(EXTERN_LIBS_DIR)" | |
@echo "EXTERN_LIBS : $(EXTERN_LIBS)" | |
@echo "SRCLIBDIR récursif : $(SRCLIBDIR)" | |
# On peut utiliser VPATH pour indiquer les chemins des dépendances : | |
# VPATH=$(SRCDIR):$(LIBDIR)... | |
# Ou utiliser vpath | |
# ATTENTION : apparement MAKE fait un cc -c -o cmd_arduino.o Sources/cmd_arduino.c | |
# tout seul de son côté à cause du VPATH ? | |
# Les fichiers de dépendance .d (cc -E appelle le pré-processeur) | |
# $(CC) -E -MM $^ -MF leFichierDesDependances.d | |
# Exemple d'appel : | |
# foo.o: foo.c | |
# cc -E -MM $^ -MF leFichierDesDependances.d ($^ == foo.c) | |
# donnera dans leFichierDesDependances.d : | |
# foo.o: foo.c foo.h bar.c bar.h | |
# | |
### Memo des variables automatiques ### | |
# $@ Le nom de la cible | |
# $< Le nom de la première dépendance | |
# $^ La liste des dépendances | |
# $? La liste des dépendances plus récentes que la cible | |
# $* Le nom du fichier sans suffixe | |
### Memo de la suite d'utilitaires liés à gcc (binutils) | |
# ld Pour linker | |
# ar Pour ouvrir les archives des .so | |
# nm Pour lister les symboles d'un .o ou dyll | |
### Prépend des commandes, par exemple `@echo`: | |
# @ suppresses the normal 'echo' of the command that is executed. | |
# - means ignore the exit status of the command that is executed (normally, a non-zero exit status would stop that part of the build). | |
# + means 'execute this command under make -n' (when commands are not normally executed). | |
# | |
# vim:ft=make | |
# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Pour lancer une commande shell :