Quand un programme demande des arguments, la manière simple est d'utiliser Makefile pour compiler les fchiers, puis d'utiliser une deuxième commande afin de lancer le fichier compilé avec les arguments désirés.
Et si cette étape n'était pas nécessaire? En effet Makefile peut tout aussi bien lancer la commande ./Mon_programme
Mais lorsque des arguments entrent en jeu, le nombre de règles peut très rapidement exploser.
Un exemple: trois arguments pour le programme (num_threads, input, output, verbose) et une possibilité d'utiliser time ou valgrind lors de l'exécution de la commande.
En terme de règles, d'une manière naïve, il est possible de créer une règle pour chaque valeur de paramètre.
1-2-4-8-16 threads -> 5 règles.
Deux fichiers input à tester séparément -> 5 * 2 = 10
Mode verbeux optionnel -> 10 * 2 = 20
Exécution simple, avec Time, ou avec Valgrind -> 20 * 3 = 60
60 règles à écrire, et 60 règles à retenir.
Il est possible d'utiliser des variables au sein même des arguments d'une règle Makefile.
Un précédent post indique comment utiliser des règles à l'intérieur du fichier Makefile, je propose d'écrire un post concernant le fait de récupérer les arguments inscrits au terminal lors de l'éxécution de la règle Makefile, et des les inclures à la commande que la règle Makefile exécutera.
De cette sorte, une règle de base seulement existe, et des paramètres viennent rajouter ou modifier des éléments à cette commande.
La commande est donc construite par les arguments passés lors de l'appel de la règle.
Exemple:
RUN_CMD = ./$(TARGET) --dicts $(dicts) --input $(input) --output $(output) --mode $(mode) --threads $(threads)
ifeq ($(extended_verbose),true)
RUN_CMD := $(RUN_CMD) --verbose --extended_verbose
else ifeq ($(verbose),true)
RUN_CMD := $(RUN_CMD) --verbose
endif
ifeq ($(other_algo),true)
RUN_CMD := $(RUN_CMD) --other_algo
endif
execute: all
ifeq ($(prefix),time)
time -f "Compilation time: %e secondes" $(RUN_CMD)
else ifeq ($(prefix),valgrind)
$(VALGRIND) $(RUN_CMD)
else
$(RUN_CMD)
endif
SAMPLE USAGE
make execute prefix=valgrind dicts=dicts input=inputs/input_50l.bin output=build/output mode=detection threads=1 verbose=true
Dans la première ligne, la variable dicts est en fait créé lorsque le terminal appelle la règle avec le parametre dicts=...
Ce post va donc également parler de l'usage de blocks conditionnels dans un Makefile.
J'ai personnellement réduit mon nombre de règles de 60 à 1 dans mon projet grâce à cette méthode.
Quand un programme demande des arguments, la manière simple est d'utiliser Makefile pour compiler les fchiers, puis d'utiliser une deuxième commande afin de lancer le fichier compilé avec les arguments désirés.
Et si cette étape n'était pas nécessaire? En effet Makefile peut tout aussi bien lancer la commande ./Mon_programme
Mais lorsque des arguments entrent en jeu, le nombre de règles peut très rapidement exploser.
Un exemple: trois arguments pour le programme (num_threads, input, output, verbose) et une possibilité d'utiliser time ou valgrind lors de l'exécution de la commande.
En terme de règles, d'une manière naïve, il est possible de créer une règle pour chaque valeur de paramètre.
1-2-4-8-16 threads -> 5 règles.
Deux fichiers input à tester séparément -> 5 * 2 = 10
Mode verbeux optionnel -> 10 * 2 = 20
Exécution simple, avec Time, ou avec Valgrind -> 20 * 3 = 60
60 règles à écrire, et 60 règles à retenir.
Il est possible d'utiliser des variables au sein même des arguments d'une règle Makefile.
Un précédent post indique comment utiliser des règles à l'intérieur du fichier Makefile, je propose d'écrire un post concernant le fait de récupérer les arguments inscrits au terminal lors de l'éxécution de la règle Makefile, et des les inclures à la commande que la règle Makefile exécutera.
De cette sorte, une règle de base seulement existe, et des paramètres viennent rajouter ou modifier des éléments à cette commande.
La commande est donc construite par les arguments passés lors de l'appel de la règle.
Exemple:$(dicts) --input $ (input) --output $(output) --mode $ (mode) --threads $(threads)
RUN_CMD = ./$(TARGET) --dicts
ifeq ($(extended_verbose),true)
RUN_CMD := $(RUN_CMD) --verbose --extended_verbose
else ifeq ($(verbose),true)
RUN_CMD := $(RUN_CMD) --verbose
endif
ifeq ($(other_algo),true)
RUN_CMD := $(RUN_CMD) --other_algo
endif
execute: all
$(VALGRIND) $ (RUN_CMD)
ifeq ($(prefix),time)
time -f "Compilation time: %e secondes" $(RUN_CMD)
else ifeq ($(prefix),valgrind)
else
$(RUN_CMD)
endif
SAMPLE USAGE
make execute prefix=valgrind dicts=dicts input=inputs/input_50l.bin output=build/output mode=detection threads=1 verbose=true
Dans la première ligne, la variable dicts est en fait créé lorsque le terminal appelle la règle avec le parametre dicts=...
Ce post va donc également parler de l'usage de blocks conditionnels dans un Makefile.
J'ai personnellement réduit mon nombre de règles de 60 à 1 dans mon projet grâce à cette méthode.