Voici un scénario que vous avez surement déjà vécu : vous intervenez sur un nouveau projet et votre premier réflexe est de lire le fichier README pour commencer le développement. Vous commencez à réaliser que ce README n’est plus très à jour et que certaines versions ont changé. Vous avancez à tâtonnement puis abandonnez avant de demander de l’aide à un autre développeur pour finir votre installation.
Il est sûr d’affirmer qu’une mauvaise introduction sur un projet n’a jamais augmenté la motivation d’un développeur. Et pourtant, nous laissons trainer ce genre de choses dans l’espoir qu’un développeur écrive un README à jour jusqu’au prochain changement majeur sur le projet.
Make est un programme que vous avez très certainement déjà manipulé puisqu’il existe depuis 1976 et que son utilisation en est presque obligatoire en C. Son principal cas d’utilisation est l’automatisation de la phase de compilation d’un projet. Il en est devenu un standard dans le monde du développement avec sa simplicité et l’engouement qu’il a reçu.
En effet, pour lancer la compilation de la plupart des projets en C (le noyau Linux par exemple), il nous suffit d’exécuter dans le shell la commande make. La plupart de ces projets sont munis d’un fichier Makefile à la racine.
Si je vous évoque cet outil aujourd’hui, c’est qu’il est utilisable sur tous les systèmes d’exploitation. Il peut automatiser l’installation d’un projet peu importe les technologies utilisées sur celui-ci. En effet, make va utiliser l’interpréteur par défaut du système pour exécuter les commandes décrites dans le Makefile.
Prenons un exemple concret, un projet Java Spring MVC avec un Tomcat conteneurisé avec Docker. On commence par créer un fichier Makefile à la racine du projet pour y inscrire plusieurs règles. Elles sont constituées de la manière suivante :
<nom de la règle>: <listes de prérequis à exécuter avant cette règle>
<commande_1>
<commande_2>
...
# On peut aussi mettre des conditions :
ifneq (...)
...
endif
NB : Documentation complète sur la syntaxe
On crée par conséquent, une première règle qui permettra de vérifier si le développeur possède tous les outils pour compiler/lancer le projet :
JAVA_VERSION = 13
check:
ifneq ($(shell java -version 2>&1 | grep $JAVA_VERSION > /dev/null; printf $$?), 0)
@echo -e "\e[0;31mIncorrect Java version, please use JDK$JAVA_VERSION }.\e[0m"
@exit 1
endif
ifneq ($(shell command -v mvn 2>&1 | grep mvn > /dev/null; printf $$?), 0)
@echo -e "\e[0;31mPlease install Maven.\e[0m"
@exit 1
endif
ifneq ($(shell command -v docker 2>&1 | grep docker > /dev/null; printf $$?), 0)
@echo -e "\e[0;31mPlease install Docker.\e[0m"
@exit 1
endif
NB : Le caractère @ permet de ne pas rendre visible dans la sortie standard l’exécution de la commande.
Une fois la vérification des outils réalisée, on définit l’automatisation de l’installation ainsi que la construction du projet :
# Un exemple d'installation avec un projet Java utilisant une dépendance versionnée.
install: check
docker-compose up -d
mvn install:install-file -DgroupId=com.proxiad -DartifactId=utils -Dversion=1.0.0 -Dpackaging=jar -DgeneratePom=true -Dfile=jars/proxiad-utils.jar
mvn clean package -DskipTests
build: check
docker stop tomcat
mvn clean package
docker start tomcat
docker logs -f --tail 100 tomcat
La règle build
va :
- Exécuter la règle
check
en prérequis - Arrêter Tomcat
- Compiler un nouveau fichier
.war
- Redémarrer un Tomcat en suivant les 100 dernières lignes de logs du conteneur.
À l’aide de la définition de ce prérequis, nous savons que la règle build
ne pourra pas se réaliser tant que notre environnement n’est pas réglé sur les bonnes versions.
Nous ajoutons les deux règles suivantes :
clean
qui supprime les fichiers de construction ainsi que le conteneur.format
lançant le formatage du projet avec spotless :
clean:
docker stop tomcat > /dev/null
docker rm tomcat > /dev/null
git reset --hard && git clean -dffx
format:
@mvn spotless:apply
On obtient donc le fichier Makefile suivant :
JAVA_VERSION=13
all: build
install: check
docker-compose up -d
mvn install:install-file -DgroupId=com.proxiad -DartifactId=utils -Dversion=1.0.0 -Dpackaging=jar -DgeneratePom=true -Dfile=jars/proxiad-utils.jar
mvn clean package -DskipTests
build: check format
docker stop tomcat
mvn clean package
docker start tomcat
docker logs -f --tail 100 tomcat
clean:
docker stop tomcat > /dev/null
docker rm tomcat > /dev/null
git reset --hard && git clean -dffx
format:
@mvn spotless:apply
check:
ifneq ($(shell java -version 2>&1 | grep $JAVA_VERSION > /dev/null; printf $$?), 0)
@echo -e "\e[0;31mIncorrect Java version, please use JDK$JAVA_VERSION }.\e[0m"
@exit 1
endif
ifneq ($(shell command -v mvn 2>&1 | grep mvn > /dev/null; printf $$?), 0)
@echo -e "\e[0;31mPlease install Maven.\e[0m"
@exit 1
endif
ifneq ($(shell command -v docker 2>&1 | grep docker > /dev/null; printf $$?), 0)
@echo -e "\e[0;31mPlease install Docker.\e[0m"
@exit 1
endif
La règle all
est associée à l’exécution de la commande make
sans argument.
Avec de l’imagination, nous pourrions intégrer une règle install-front
et run-front
se chargeant de l’installation ainsi que de la construction d’un front-end dans un sous-dossier ui
:
install-front:
cd ui && npm install
run-front:
cd ui && npm run start
Make est un standard. C’est ce qui en fait sa puissance. Si une personne observe sur un nouveau projet qu’un Makefile a été réalisé, il déterminera qu’il sera à jour et fonctionnel puisque les développeurs précédents l’auront utilisé. Néanmoins, prenez vos précautions lors de vos premières utilisations, cet outil est très capricieux sur la syntaxe.
Pour toutes questions à ce propos, n’hésitez pas à me contacter, ça serait avec plaisir que je pourrais vous aider à mieux maintenir vos projets à l’aide de cet outil !
Arnaud Peralta
Ingénieur d’Etude et Développement
Proxiad Axe Seine