TL; DR n'essayez pas de faire cela
$ make run arg
créez plutôt un script:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
et faites ceci:
$ ./buildandrunprog.sh arg
réponse à la question posée:
vous pouvez utiliser une variable dans la recette
run: prog
./prog $(var)
puis passez une affectation de variable comme argument pour faire
$ make run var=arg
cela s'exécutera ./prog arg
.
mais méfiez-vous des pièges. je développerai les pièges de cette méthode et d'autres méthodes plus bas.
réponse à l'intention supposée derrière la question:
l'hypothèse: vous voulez exécuter prog
avec quelques arguments mais le faire reconstruire avant de l'exécuter si nécessaire.
la réponse: créer un script qui reconstruit si nécessaire puis exécute prog avec args
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
ce script rend l'intention très claire. il utilise make pour faire ce pour quoi il est bon: construire. il utilise un script shell pour faire ce qu'il est bon: le traitement par lots.
De plus, vous pouvez faire tout ce dont vous pourriez avoir besoin avec toute la flexibilité et l'expressivité d'un script shell sans toutes les mises en garde d'un makefile.
la syntaxe d'appel est désormais pratiquement identique:
$ ./buildandrunprog.sh foo "bar baz"
comparer aux:
$ ./prog foo "bar baz"
contrairement à
$ make run var="foo bar\ baz"
Contexte:
make n'est pas conçu pour transmettre des arguments à une cible. tous les arguments de la ligne de commande sont interprétés soit comme un objectif (alias cible), comme une option, soit comme une affectation de variable.
donc si vous lancez ceci:
$ make run foo --wat var=arg
make interprétera run
et foo
comme objectifs (cibles) à mettre à jour en fonction de leurs recettes. --wat
en option pour faire. et var=arg
comme une affectation variable.
pour plus de détails, voir: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals
pour la terminologie, voir: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction
sur la méthode d'affectation des variables et pourquoi je la déconseille
$ make run var=arg
et la variable dans la recette
run: prog
./prog $(var)
c'est le moyen le plus "correct" et le plus simple de passer des arguments à une recette. mais bien qu'il puisse être utilisé pour exécuter un programme avec des arguments, il n'est certainement pas conçu pour être utilisé de cette façon. voir https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
à mon avis, cela a un gros inconvénient: ce que vous voulez faire, c'est exécuter prog
avec argument arg
. mais au lieu d'écrire:
$ ./prog arg
tu écris:
$ make run var=arg
cela devient encore plus gênant lorsque vous essayez de passer plusieurs arguments ou des arguments contenant des espaces:
$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz
comparer aux:
$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz
pour mémoire, voici à quoi je prog
ressemble:
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
notez également que vous ne devez pas mettre $(var)
de guillemets dans le makefile:
run: prog
./prog "$(var)"
car alors, prog
il n'y aura toujours qu'un seul argument:
$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz
c'est pourquoi je déconseille cette route.
pour être complet, voici quelques autres méthodes pour "passer des arguments pour exécuter".
méthode 1:
run: prog
./prog $(filter-out $@, $(MAKECMDGOALS))
%:
@true
super courte explication: filtrer l'objectif actuel de la liste des objectifs. create catch all target ( %
) qui ne fait rien pour ignorer silencieusement les autres objectifs.
méthode 2:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
super courte explication: si la cible est run
alors supprimez le premier objectif et créez des cibles de ne rien faire pour les objectifs restants en utilisant eval
.
les deux vous permettront d'écrire quelque chose comme ça
$ make run arg1 arg2
pour une explication plus approfondie, étudiez le manuel de make: https://www.gnu.org/software/make/manual/html_node/index.html
problèmes de méthode 1:
les arguments qui commencent par un tiret seront interprétés par make et ne seront pas transmis comme objectif.
$ make run --foo --bar
solution de contournement
$ make run -- --foo --bar
les arguments avec un signe égal seront interprétés par make et ne seront pas passés
$ make run foo=bar
pas de solution
les arguments avec des espaces sont maladroits
$ make run foo "bar\ baz"
pas de solution
si un argument se trouve être run
(égal à la cible), il sera également supprimé
$ make run foo bar run
fonctionnera ./prog foo bar
au lieu de./prog foo bar run
solution possible avec la méthode 2
si un argument est une cible légitime, il sera également exécuté.
$ make run foo bar clean
s'exécutera ./prog foo bar clean
mais aussi la recette de la cible clean
(en supposant qu'elle existe).
solution possible avec la méthode 2
lorsque vous saisissez mal une cible légitime, elle est ignorée en silence à cause de la capture de toutes les cibles.
$ make celan
va simplement ignorer silencieusement celan
.
solution de contournement consiste à tout rendre verbeux. vous voyez donc ce qui se passe. mais cela crée beaucoup de bruit pour la sortie légitime.
problèmes de méthode 2:
si un argument a le même nom qu'une cible existante, make affichera un avertissement indiquant qu'il est écrasé.
aucune solution de contournement que je connaisse
les arguments avec un signe égal seront toujours interprétés par make et ne seront pas passés
pas de solution
les arguments avec des espaces sont toujours maladroits
pas de solution
des arguments avec des sauts d'espace eval
essayant de créer des cibles de ne rien faire.
solution: créez la cible globale catch all sans rien faire comme ci-dessus. avec le problème ci-dessus, il ignorera à nouveau silencieusement les cibles légitimes mal tapées.
il utilise eval
pour modifier le makefile lors de l'exécution. combien pire pouvez-vous aller en termes de lisibilité et de débogage et le principe du moindre étonnement .
solution de contournement: ne faites pas ça !! 1 au lieu d'écrire un script shell qui exécute make puis s'exécute prog
.
j'ai seulement testé en utilisant gnu make. d'autres marques peuvent avoir un comportement différent.
TL; DR n'essayez pas de faire cela
$ make run arg
créez plutôt un script:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
et faites ceci:
$ ./buildandrunprog.sh arg