Ce qui suit le fera si, comme je suppose par votre utilisation de ./a.out, vous êtes sur une plate-forme de type UNIX.
for number in 1 2 3 4 ; do \
./a.out $$number ; \
done
Testez comme suit:
target:
for number in 1 2 3 4 ; do \
echo $$number ; \
done
produit:
1
2
3
4
Pour des gammes plus importantes, utilisez:
target:
number=1 ; while [[ $$number -le 10 ]] ; do \
echo $$number ; \
((number = number + 1)) ; \
done
Cela produit 1 à 10 inclus, changez simplement la whilecondition de terminaison de 10 à 1000 pour une plage beaucoup plus grande comme indiqué dans votre commentaire.
qwert est juste un nom cible qui n'est probablement pas un vrai fichier. Les règles Makefile ont besoin d'un objectif. Quant à l'erreur de syntaxe, il vous manque des trucs - voir mise à jour.
paxdiablo
2
Puisque vous supposez que son shell reconnaît ((...)), pourquoi ne pas utiliser le plus simple pour ((i = 0; i <WHATEVER; ++ i)); faire ...; terminé ?
Idelic
1
Notez que la seqcommande qui génère une séquence de nombres existe sur la plupart (tous?) Des systèmes Unix, vous pouvez donc écrire for number in ``seq 1 1000``; do echo $$number; done(Mettez un seul backtick de chaque côté de la commande seq, pas deux, je ne sais pas comment formater cela correctement en utilisant la syntaxe de stackoverflow)
Suzanne Dupéron
3
Merci, il me manquait le double $$ pour référencer la variable de boucle for.
Leif Gruenwoldt du
1
@ Jonz: le caractère de continuation de ligne est dû au fait que makechaque ligne est normalement traitée comme une chose à exécuter dans un sous-shell séparé . Sans suite, il essaierait d'exécuter un sous-shell avec juste (par exemple) for number in 1 2 3 4 ; do, sans le reste de la boucle. Avec lui, il devient effectivement une seule ligne du formulaire while something ; do something ; done, qui est une déclaration complète. La $$question est répondue ici: stackoverflow.com/questions/26564825/… , avec le code apparemment extrait de cette même réponse :-)
Cette réponse est meilleure à mon humble avis, car elle ne nécessite aucun shell, c'est un makefile pur (même s'il est spécifique à GNU).
Jocelyn delalande
7
le point-virgule est crucial sinon seule la première itération s'exécutera
Jeremy Leipzig
7
Cette solution masque le code de sortie de ./a.out 1. ./a.out 2sera exécuté malgré tout.
bobbogo
1
@Alexander: pourriez-vous préciser à quelle limitation vous faites référence?
Idelic
1
@Idelic, oui. Pour le makefile et le shellscript suivants, le shellscript fonctionne (passe l'argument à ls), tandis que le Makefile donne une erreur: make: execvp: / bin / sh: Liste d'arguments trop longue Makefile: ix.io/d5L Shellscript: ix.io / d5M Il s'agit d'un problème dans la fonction foreach que j'ai rencontré au travail, lorsqu'une liste inhabituellement longue de noms de fichiers (avec de longs chemins également) a été transmise à une commande. Nous avons dû trouver une solution de contournement.
Alexander
107
LA principale raison d'utiliser make IMHO est le -jdrapeau. make -j5exécutera 5 commandes shell à la fois. C'est bien si vous avez 4 processeurs, et un bon test de n'importe quel makefile.
Fondamentalement, vous voulez faire voir quelque chose comme:
pour le même effet (oui, c'est la même que la formulation précédente en ce qui concerne make , juste un peu plus compact).
Un peu de paramétrage pour que vous puissiez spécifier une limite sur la ligne de commande (fastidieux car maken'a pas de bonnes macros arithmétiques, donc je vais 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 exécutez cela avec make -j5 LAST=550, avec une valeur par LASTdéfaut de 1000.
C'est certainement la meilleure réponse, pour la raison que Bobbogo a mentionnée ( -j ).
dbn
Une raison particulière pour laquelle il utilise les suffixes .PHONY? Sont-ils nécessaires pour quelque chose?
Seb
6
@seb: Sans .PHONY: all, make recherchera un fichier appelé all. Si un tel fichier existe, make vérifie ensuite l'heure de la dernière modification de ce fichier, et le makefile ne fera certainement pas ce que vous vouliez. La .PHONYdéclaration indique à make que allc'est une cible symbolique. Make considérera donc leall cible est toujours dépassée. Parfait. Voir le manuel.
@JoeS gnu.org/software/make/manual/make.html#Static-Pattern (je pense que vous vouliez dire à quoi sert le 2e * deux-points * ). Ne les confondez pas avec les règles de modèle non agréables (à mon humble avis) . Règles de modèle statiques sont vraiment utiles à chaque fois que la liste des cibles peut être compensée par l' une des marque « s motifs Noddy (même pour les dépendances). Ici, j'en utilise un juste pour la commodité que tout ce qui correspond %à la règle est disponible comme $*dans la recette.
bobbogo
22
Je me rends compte que la question est vieille de plusieurs années, mais ce message peut toujours être utile à quelqu'un car il démontre une approche qui diffère de ce qui précède, et ne dépend ni des opérations du shell ni de la nécessité pour le développeur de supprimer un code dur codé chaîne de valeurs numériques.
la macro intégrée $ (eval ....) est votre amie. Ou peut être au moins.
C'est un exemple simpliste. Il ne s'agrandira pas assez pour les grandes valeurs - cela fonctionne, mais comme la chaîne ITERATE_COUNT augmentera de 2 caractères (espace et point) pour chaque itération, à mesure que vous montez par milliers, il faut progressivement plus de temps pour compter les mots. Comme écrit, il ne gère pas l'itération imbriquée (vous auriez besoin d'une fonction d'itération et d'un compteur séparés pour le faire). Ceci est purement gnu make, aucune exigence de shell (bien que évidemment l'OP cherchait à exécuter un programme à chaque fois - ici, j'affiche simplement un message). Le if dans ITERATE est destiné à attraper la valeur 0, car $ (mot ...) se trompera autrement.
Notez que la chaîne croissante pour servir de compteur est utilisée parce que le $ (mots ...) intégré peut fournir un compte arabe, mais cette marque ne prend pas en charge les opérations mathématiques (vous ne pouvez pas affecter 1 + 1 à quelque chose et obtenir 2, sauf si vous invoquez quelque chose à partir du shell pour l'accomplir pour vous, ou si vous utilisez une opération de macro tout aussi compliquée). Cela fonctionne très bien pour un compteur INCRÉMENTAL, mais pas aussi bien pour un compteur DÉCRÉMENTAL.
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 à travers un environnement de construction multi-binaire et multi-bibliothèque où vous devez savoir pour apporter D'AUTRES bibliothèques lorsque vous incluez une bibliothèque qui lui-même a d'autres dépendances (dont certaines varient en fonction des paramètres de construction), et j'utilise une méthode $ (eval) et counter similaire à la précédente (dans mon cas, le compteur est utilisé pour nous assurer que nous n'entrons pas dans une infinité boucle, et aussi comme diagnostic pour signaler combien d'itération était nécessaire).
Quelque chose d'autre ne vaut rien, bien que non significatif pour l'OP Q: $ (eval ...) fournit une méthode pour contourner l'horreur interne de make aux références circulaires, ce qui est tout à fait correct à appliquer lorsqu'une variable est un type macro (initialisé avec =), par rapport à une affectation immédiate (initialisée avec: =). Il y a des moments où vous voulez 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 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 de toute façon.
SOMESTRING = foo
# will error. Comment out and re-run
SOMESTRING = pre-${SOMESTRING}
# works
$(eval SOMESTRING = pre${SOMESTRING}
default:
@echo ${SOMESTRING}
Je suis coincé à une étape lors de l'écriture d'un Makefile. J'ai le code suivant: set_var: @ NUM = 0; tandis que [[$$ NUM <1]]; do \ echo "je suis ici"; \ echo $$ NUM vidage $$ {NUM} .txt; \ var = "SSA_CORE $$ {NUM} _MAINEXEC"; \ echo $$ var; \ var1 = eval echo \$${$(var)}; \ echo $$ var1; \ ((NUM = NUM + 1)); \ done all: set_var ici SSA_CORE0_MAINEXEC est une variable d'environnement qui est déjà définie. Je souhaite donc que cette valeur soit évaluée ou imprimée à l'aide de la variable var1. Je l'ai essayé comme indiqué ci-dessus mais ne fonctionne pas. pLease aide.
XYZ_Linux
2
C'est en effet une solution de contournement facile, mais cela vous empêche d'utiliser la belle option "make -j 4" pour que les processus s'exécutent en parallèle.
TabeaKischka
1
@TabeaKischka: en effet. Ce n'était pas la méthode " recommandée ", mais cela signifie davantage si l'on a besoin de certaines fonctionnalités qui ne sont pas proposées par un Makefile, alors on peut recourir à une implémentation dans bashet donc utiliser les fonctionnalités. La boucle est l'une des caractéristiques pour lesquelles cela peut être démontré.
Bien que la boîte à outils de la table GNUmake ait une vraie whileboucle (quoi que cela signifie dans la programmation GNUmake avec ses deux ou trois phases d'exécution), si la chose dont vous avez besoin est une liste itérative, il existe une solution simple avec interval. Pour le plaisir, nous convertissons également les nombres en hexadécimal:
include gmtt/gmtt.mk
# generate a list of 20 numbers, starting at 3 with an increment of 5
NUMBER_LIST := $(call interval,3,20,5)
# convert the numbers in hexadecimal (0x0 as first operand forces arithmetic result to hex) and strip '0x'
NUMBER_LIST_IN_HEX := $(foreach n,$(NUMBER_LIST),$(call lstrip,$(call add,0x0,$(n)),0x))
# finally create the filenames with a simple patsubst
FILE_LIST := $(patsubst %,./a%.out,$(NUMBER_LIST_IN_HEX))
$(info $(FILE_LIST))
#I have a bunch of files that follow the naming convention
#soxfile1 soxfile1.o soxfile1.sh soxfile1.ini soxfile1.txt soxfile1.err
#soxfile2 soxfile2.o soxfile2.sh soxfile2.ini soxfile2.txt soxfile2.err
#sox... .... ..... .... .... ....
#in the makefile, only select the soxfile1.. soxfile2... to install dir
#My GNU makefile solution follows:
tgt=/usr/local/bin/ #need to use sudo
tgt2=/backup/myapplication/ #regular backup
install:
for var in $$(ls -f sox* | grep -v '\.' ) ; \
do \
sudo cp -f $$var ${TGT} ; \
cp -f $$var ${TGT2} ; \
done
#The ls command selects all the soxfile* including the *.something
#The grep command rejects names with a dot in it, leaving
#My desired executable files in a list.
Réponses:
Ce qui suit le fera si, comme je suppose par votre utilisation de
./a.out
, vous êtes sur une plate-forme de type UNIX.Testez comme suit:
produit:
Pour des gammes plus importantes, utilisez:
Cela produit 1 à 10 inclus, changez simplement la
while
condition de terminaison de 10 à 1000 pour une plage beaucoup plus grande comme indiqué dans votre commentaire.Les boucles imbriquées peuvent se faire ainsi:
produisant:
la source
seq
commande qui génère une séquence de nombres existe sur la plupart (tous?) Des systèmes Unix, vous pouvez donc écrirefor number in ``seq 1 1000``; do echo $$number; done
(Mettez un seul backtick de chaque côté de la commande seq, pas deux, je ne sais pas comment formater cela correctement en utilisant la syntaxe de stackoverflow)make
chaque ligne est normalement traitée comme une chose à exécuter dans un sous-shell séparé . Sans suite, il essaierait d'exécuter un sous-shell avec juste (par exemple)for number in 1 2 3 4 ; do
, sans le reste de la boucle. Avec lui, il devient effectivement une seule ligne du formulairewhile something ; do something ; done
, qui est une déclaration complète. La$$
question est répondue ici: stackoverflow.com/questions/26564825/… , avec le code apparemment extrait de cette même réponse :-)Si vous utilisez GNU make, vous pouvez essayer
qui va générer et exécuter
la source
./a.out 1
../a.out 2
sera exécuté malgré tout.LA principale raison d'utiliser make IMHO est le
-j
drapeau.make -j5
exécutera 5 commandes shell à la fois. C'est bien si vous avez 4 processeurs, et un bon test de n'importe quel makefile.Fondamentalement, vous voulez faire voir quelque chose comme:
C'est
-j
sympa (bon signe). Pouvez-vous repérer la plaque de chaudière? On pourrait écrire:pour le même effet (oui, c'est la même que la formulation précédente en ce qui concerne make , juste un peu plus compact).
Un peu de paramétrage pour que vous puissiez spécifier une limite sur la ligne de commande (fastidieux car
make
n'a pas de bonnes macros arithmétiques, donc je vais tricher ici et utiliser$(shell ...)
)Vous exécutez cela avec
make -j5 LAST=550
, avec une valeur parLAST
défaut de 1000.la source
.PHONY: all
, make recherchera un fichier appeléall
. Si un tel fichier existe, make vérifie ensuite l'heure de la dernière modification de ce fichier, et le makefile ne fera certainement pas ce que vous vouliez. La.PHONY
déclaration indique à make queall
c'est une cible symbolique. Make considérera donc leall
cible est toujours dépassée. Parfait. Voir le manuel.%
à la règle est disponible comme$*
dans la recette.Je me rends compte que la question est vieille de plusieurs années, mais ce message peut toujours être utile à quelqu'un car il démontre une approche qui diffère de ce qui précède, et ne dépend ni des opérations du shell ni de la nécessité pour le développeur de supprimer un code dur codé chaîne de valeurs numériques.
la macro intégrée $ (eval ....) est votre amie. Ou peut être au moins.
C'est un exemple simpliste. Il ne s'agrandira pas assez pour les grandes valeurs - cela fonctionne, mais comme la chaîne ITERATE_COUNT augmentera de 2 caractères (espace et point) pour chaque itération, à mesure que vous montez par milliers, il faut progressivement plus de temps pour compter les mots. Comme écrit, il ne gère pas l'itération imbriquée (vous auriez besoin d'une fonction d'itération et d'un compteur séparés pour le faire). Ceci est purement gnu make, aucune exigence de shell (bien que évidemment l'OP cherchait à exécuter un programme à chaque fois - ici, j'affiche simplement un message). Le if dans ITERATE est destiné à attraper la valeur 0, car $ (mot ...) se trompera autrement.
Notez que la chaîne croissante pour servir de compteur est utilisée parce que le $ (mots ...) intégré peut fournir un compte arabe, mais cette marque ne prend pas en charge les opérations mathématiques (vous ne pouvez pas affecter 1 + 1 à quelque chose et obtenir 2, sauf si vous invoquez quelque chose à partir du shell pour l'accomplir pour vous, ou si vous utilisez une opération de macro tout aussi compliquée). Cela fonctionne très bien pour un compteur INCRÉMENTAL, mais pas aussi bien pour un compteur DÉCRÉMENTAL.
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 à travers un environnement de construction multi-binaire et multi-bibliothèque où vous devez savoir pour apporter D'AUTRES bibliothèques lorsque vous incluez une bibliothèque qui lui-même a d'autres dépendances (dont certaines varient en fonction des paramètres de construction), et j'utilise une méthode $ (eval) et counter similaire à la précédente (dans mon cas, le compteur est utilisé pour nous assurer que nous n'entrons pas dans une infinité boucle, et aussi comme diagnostic pour signaler combien d'itération était nécessaire).
Quelque chose d'autre ne vaut rien, bien que non significatif pour l'OP Q: $ (eval ...) fournit une méthode pour contourner l'horreur interne de make aux références circulaires, ce qui est tout à fait correct à appliquer lorsqu'une variable est un type macro (initialisé avec =), par rapport à une affectation immédiate (initialisée avec: =). Il y a des moments où vous voulez 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 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 de toute façon.
Make'ing heureux.
la source
Pour la prise en charge multiplateforme, rendez le séparateur de commandes (pour exécuter plusieurs commandes sur la même ligne) configurable.
Si vous utilisez MinGW sur une plateforme Windows par exemple, le séparateur de commandes est
&
:Cela exécute les commandes concaténées sur une seule ligne:
Comme mentionné ailleurs, sur une plate-forme * nix, utilisez
CMDSEP = ;
.la source
Ce n'est pas vraiment une pure réponse à la question, mais une façon intelligente de contourner ces problèmes:
au lieu d'écrire un fichier complexe, déléguez simplement le contrôle par exemple à un script bash comme: makefile
et script.sh ressemble à:
la source
eval echo \$${$(var)}
; \ echo $$ var1; \ ((NUM = NUM + 1)); \ done all: set_var ici SSA_CORE0_MAINEXEC est une variable d'environnement qui est déjà définie. Je souhaite donc que cette valeur soit évaluée ou imprimée à l'aide de la variable var1. Je l'ai essayé comme indiqué ci-dessus mais ne fonctionne pas. pLease aide.bash
et donc utiliser les fonctionnalités. La boucle est l'une des caractéristiques pour lesquelles cela peut être démontré.Vous pouvez peut-être utiliser:
la source
Vous pouvez utiliser
set -e
comme préfixe pour la boucle for. Exemple:make
quittera immédiatement avec un code de sortie<> 0
.la source
Bien que la boîte à outils de la table GNUmake ait une vraie
while
boucle (quoi que cela signifie dans la programmation GNUmake avec ses deux ou trois phases d'exécution), si la chose dont vous avez besoin est une liste itérative, il existe une solution simple avecinterval
. Pour le plaisir, nous convertissons également les nombres en hexadécimal:Production:
la source
Une solution macro simple, indépendante du shell / de la plateforme, est ...
la source
la source