Je veux exécuter les commandes suivantes :
./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on
Comment écrire cette chose en tant que boucle dans une Makefile
?
Je veux exécuter les commandes suivantes :
./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on
Comment écrire cette chose en tant que boucle dans une Makefile
?
Ce qui suit le fera si, comme je le suppose par votre utilisation de ./a.out
vous êtes sur une plateforme de type UNIX.
for number in 1 2 3 4 ; do \
./a.out $$number ; \
done
Faites le test comme suit :
target:
for number in 1 2 3 4 ; do \
echo $$number ; \
done
produit :
1
2
3
4
Pour des plages plus importantes, utilisez :
target:
number=1 ; while [[ $$number -le 10 ]] ; do \
echo $$number ; \
((number = number + 1)) ; \
done
Cette sortie va de 1 à 10 inclus, il suffit de changer l'option while
de 10 à 1000 pour une gamme beaucoup plus large comme indiqué dans votre commentaire.
Emboîté Les boucles peuvent être faites ainsi :
target:
num1=1 ; while [[ $$num1 -le 4 ]] ; do \
num2=1 ; while [[ $$num2 -le 3 ]] ; do \
echo $$num1 $$num2 ; \
((num2 = num2 + 1)) ; \
done ; \
((num1 = num1 + 1)) ; \
done
produisant :
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
4 1
4 2
4 3
Une chose est : à quoi sert l'étiquette qwert ? Une autre question concerne les boucles imbriquées. Une erreur de syntaxe apparaît ici for n1 in 0 1 2 ; do \ for n2 in 1 2 3 ; do \ ./a.out $$n1 $$n2 ; \ done done
Qwert est juste un nom de cible qui a peu de chances d'être un vrai fichier. Les règles de Makefile ont besoin d'une cible. Pour ce qui est de l'erreur de syntaxe, il vous manque des éléments - voir la mise à jour.
Cette réponse est à mon avis meilleure, car elle ne nécessite pas l'utilisation d'un shell, c'est un makefile pur (même s'il est spécifique à GNU).
Cette solution permet de masquer le code de sortie de ./a.out 1
. ./a.out 2
sera exécuté quoi qu'il en soit.
LE La principale raison d'utiliser make IMHO est la -j
drapeau. make -j5
lancera 5 commandes shell en même temps. C'est une bonne chose si vous avez 4 processeurs, et un bon test de tout makefile.
En gros, vous voulez faire voir quelque chose comme :
.PHONY: all
all: job1 job2 job3
.PHONY: job1
job1: ; ./a.out 1
.PHONY: job2
job2: ; ./a.out 2
.PHONY: job3
job3: ; ./a.out 3
C'est -j
amical (un bon signe). Pouvez-vous repérer le texte passe-partout ? Nous pourrions écrire :
.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
./a.out $*
pour le même effet (oui, c'est la même chose que la formulation précédente pour ce qui est de l'utilisation de l'option faire mais un peu plus compact).
Un paramétrage supplémentaire permettant de spécifier une limite sur la ligne de commande (aussi fastidieuse que make
ne dispose pas de bonnes macros arithmétiques, je vais donc tricher ici et utiliser $(shell ...)
)
LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "$@ success"
${JOBS}: job%: ; ./a.out $*
Vous l'exécutez avec make -j5 LAST=550
avec LAST
par défaut à 1000.
Y a-t-il une raison particulière à l'utilisation des suffixes .PHONY ? Sont-ils nécessaires pour quelque chose ?
@seb : Sans .PHONY: all
make va chercher un fichier appelé all
. Si un tel fichier existe, make vérifie alors le last-changed-time de ce fichier, et le fichier makefile ne fera presque certainement pas ce que vous vouliez. Le site .PHONY
La déclaration indique que all
est une cible symbolique. Make va donc considérer le all
cible pour être toujours dépassée. Parfait. Voir le manuel.
Je me rends compte que la question date de plusieurs années, mais ce message peut encore être utile à quelqu'un, car il présente une approche différente de celle décrite ci-dessus, qui ne repose ni sur les opérations du shell ni sur la nécessité pour le développeur d'élaborer une chaîne de valeurs numériques codées en dur.
la macro intégrée $(eval ....) est votre amie. Ou du moins, elle peut l'être.
define ITERATE
$(eval ITERATE_COUNT :=)\
$(if $(filter ${1},0),,\
$(call ITERATE_DO,${1},${2})\
)
endef
define ITERATE_DO
$(if $(word ${1}, ${ITERATE_COUNT}),,\
$(eval ITERATE_COUNT+=.)\
$(info ${2} $(words ${ITERATE_COUNT}))\
$(call ITERATE_DO,${1},${2})\
)
endef
default:
$(call ITERATE,5,somecmd)
$(call ITERATE,0,nocmd)
$(info $(call ITERATE,8,someothercmd)
C'est un exemple simpliste. Il ne s'adaptera pas bien aux grandes valeurs - il fonctionne, mais comme la chaîne ITERATE_COUNT augmentera de 2 caractères (espace et point) pour chaque itération, il faudra progressivement plus de temps pour compter les mots à mesure que vous atteindrez les milliers. Tel qu'il est écrit, il ne gère pas les itérations imbriquées (il faudrait une fonction d'itération et un compteur séparés pour le faire). C'est purement gnu make, aucun shell n'est requis (bien que de toute évidence l'OP cherchait à exécuter un programme à chaque fois -- ici, je ne fais qu'afficher un message). Le if dans ITERATE est destiné à attraper la valeur 0, parce que $(word...) se trompera autrement.
Notez que la chaîne croissante servant de compteur est employée parce que le constructeur $(words...) peut fournir un compte arabe, mais que make ne supporte pas autrement les opérations mathématiques (vous ne pouvez pas assigner 1+1 à quelque chose et obtenir 2, à moins que vous n'invoquiez quelque chose du shell pour l'accomplir pour vous, ou que vous utilisiez une opération macro tout aussi alambiquée). Cela fonctionne très bien pour un compteur INCREMENTAL, mais pas si bien pour un compteur DECREMENTAL.
Je ne l'utilise pas moi-même, mais récemment, j'ai eu besoin d'écrire une fonction récursive pour évaluer les dépendances des bibliothèques dans un environnement de compilation multi-binaire et multi-bibliothèque où vous devez savoir s'il faut intégrer d'AUTRES bibliothèques lorsque vous incluez une bibliothèque qui a elle-même d'autres dépendances (dont certaines varient en fonction des paramètres de compilation), et j'utilise une méthode $(eval) et compteur similaire à celle décrite ci-dessus (dans mon cas, le compteur est utilisé pour s'assurer que nous n'entrons pas d'une manière ou d'une autre dans une boucle sans fin, et aussi comme un diagnostic pour signaler combien d'itérations ont été nécessaires).
Autre chose qui n'a pas d'importance, mais qui n'a rien à voir avec la question de l'OP : $(eval...) fournit une méthode pour contourner l'horreur interne de make pour les références circulaires, qui est très bien d'appliquer quand une variable est un type macro (initialisée avec =), par opposition à une affectation immédiate (initialisée avec :=). Il arrive que vous souhaitiez pouvoir utiliser une variable dans sa propre affectation, et $(eval...) vous permettra de le faire. La chose importante à considérer ici est qu'au moment où vous exécutez l'eval, la variable est résolue, et la partie qui est résolue n'est plus traitée comme une macro. Si vous savez ce que vous faites et que vous essayez d'utiliser une variable sur le RHS d'une affectation à elle-même, c'est généralement ce que vous voulez qu'il se passe de toute façon.
SOMESTRING = foo
# will error. Comment out and re-run
SOMESTRING = pre-${SOMESTRING}
# works
$(eval SOMESTRING = pre${SOMESTRING}
default:
@echo ${SOMESTRING}
Bon travail.
Pour une prise en charge multiplateforme, rendez le séparateur de commandes (pour l'exécution de plusieurs commandes sur la même ligne) configurable.
Si vous utilisez MinGW sur une plateforme Windows par exemple, le séparateur de commandes est le suivant &
:
NUMBERS = 1 2 3 4
CMDSEP = &
doit:
$(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))
Ceci exécute les commandes concaténées en une seule ligne :
./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &
Comme mentionné ailleurs, sur une plateforme *nix, utilisez CMDSEP = ;
.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
0 votes
Similaire, mais légèrement plus générique : Commandes bash multilignes dans le makefile