TL; DR versuchen Sie nicht, dies zu tun
$ make run arg
Erstellen Sie stattdessen ein Skript:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
und mach das:
$ ./buildandrunprog.sh arg
Antwort auf die gestellte Frage:
Sie können eine Variable im Rezept verwenden
run: prog
./prog $(var)
Übergeben Sie dann eine Variablenzuweisung als Argument
$ make run var=arg
Dies wird ausgeführt ./prog arg
.
aber hüte dich vor Fallstricken. Ich werde auf die Fallstricke dieser Methode und anderer Methoden weiter unten eingehen.
Antwort auf die vermutete Absicht hinter der Frage:
Die Annahme: Sie möchten prog
mit einigen Argumenten ausgeführt werden, müssen diese jedoch vor der Ausführung neu erstellen, falls erforderlich.
Die Antwort: Erstellen Sie ein Skript, das bei Bedarf neu erstellt wird, und führen Sie dann prog mit args aus
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
Dieses Skript macht die Absicht sehr klar. Es verwendet make, um das zu tun, wofür es gut ist: Bauen. Es verwendet ein Shell-Skript, um das zu tun, wofür es gut ist: Stapelverarbeitung.
Außerdem können Sie mit der vollen Flexibilität und Ausdruckskraft eines Shell-Skripts alles tun, was Sie sonst noch benötigen, ohne die Einschränkungen eines Makefiles.
auch die aufrufende Syntax ist jetzt praktisch identisch:
$ ./buildandrunprog.sh foo "bar baz"
vergleichen mit:
$ ./prog foo "bar baz"
im Gegensatz zu
$ make run var="foo bar\ baz"
Hintergrund:
make ist nicht dafür ausgelegt, Argumente an ein Ziel zu übergeben. Alle Argumente in der Befehlszeile werden entweder als Ziel (auch als Ziel bezeichnet), als Option oder als Variablenzuweisung interpretiert.
Also, wenn Sie dies ausführen:
$ make run foo --wat var=arg
make wird interpretiert run
und foo
als Ziele (Targets) nach ihren Rezepten aktualisiert. --wat
als Option für machen. und var=arg
als variable Zuordnung.
Weitere Informationen finden Sie unter: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals
Die Terminologie finden Sie unter: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction
über die variable Zuweisungsmethode und warum ich dagegen empfehle
$ make run var=arg
und die Variable im Rezept
run: prog
./prog $(var)
Dies ist die "korrekteste" und einfachste Möglichkeit, Argumente an ein Rezept zu übergeben. Obwohl es verwendet werden kann, um ein Programm mit Argumenten auszuführen, ist es sicherlich nicht dafür ausgelegt, auf diese Weise verwendet zu werden. Siehe https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
Meiner Meinung nach hat dies einen großen Nachteil: Was Sie tun möchten, ist prog
mit Argumenten zu laufen arg
. aber anstatt zu schreiben:
$ ./prog arg
du schreibst:
$ make run var=arg
Dies wird noch umständlicher, wenn Sie versuchen, mehrere Argumente oder Argumente mit Leerzeichen zu übergeben:
$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz
vergleichen mit:
$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz
Für die Aufzeichnung prog
sieht es so aus:
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
Beachten Sie auch, dass Sie $(var)
im Makefile keine Anführungszeichen setzen sollten :
run: prog
./prog "$(var)"
denn dann prog
bekommt man immer nur ein argument:
$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz
All dies ist, warum ich gegen diese Route empfehle.
Der Vollständigkeit halber sind hier einige andere Methoden aufgeführt, um "Argumente zu übergeben, um sie auszuführen".
Methode 1:
run: prog
./prog $(filter-out $@, $(MAKECMDGOALS))
%:
@true
super kurze Erklärung: aktuelles Ziel aus der Liste der Ziele herausfiltern. Erstelle catch all target ( %
), was nichts dazu beiträgt, die anderen Ziele stillschweigend zu ignorieren.
Methode 2:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
super kurze Erklärung: Wenn das Ziel ist, run
entfernen Sie das erste Ziel und erstellen Sie keine Ziele für die verbleibenden Ziele mit eval
.
Mit beiden können Sie so etwas schreiben
$ make run arg1 arg2
Weitere Informationen finden Sie im Handbuch von make: https://www.gnu.org/software/make/manual/html_node/index.html
Probleme der Methode 1:
Argumente, die mit einem Bindestrich beginnen, werden von make interpretiert und nicht als Ziel übergeben.
$ make run --foo --bar
Problemumgehung
$ make run -- --foo --bar
Argumente mit Gleichheitszeichen werden von make interpretiert und nicht übergeben
$ make run foo=bar
Keine Problemumgehung
Argumente mit Leerzeichen sind umständlich
$ make run foo "bar\ baz"
Keine Problemumgehung
Wenn ein Argument zufällig run
(gleich dem Ziel) ist, wird es ebenfalls entfernt
$ make run foo bar run
läuft ./prog foo bar
statt./prog foo bar run
Problemumgehung mit Methode 2 möglich
Wenn ein Argument ein legitimes Ziel ist, wird es ebenfalls ausgeführt.
$ make run foo bar clean
läuft ./prog foo bar clean
aber auch das Rezept für das Ziel clean
(vorausgesetzt es existiert).
Problemumgehung mit Methode 2 möglich
Wenn Sie ein legitimes Ziel falsch eingeben, wird es aufgrund des Ziels "Alle fangen" stillschweigend ignoriert.
$ make celan
wird einfach still ignorieren celan
.
Problemumgehung ist, alles wortreich zu machen. Sie sehen also, was passiert. aber das erzeugt viel Rauschen für die legitime Ausgabe.
Probleme der Methode 2:
Wenn ein Argument denselben Namen wie ein vorhandenes Ziel hat, gibt make eine Warnung aus, dass es überschrieben wird.
Keine Problemumgehung, die ich kenne
Argumente mit einem Gleichheitszeichen werden weiterhin von make interpretiert und nicht übergeben
Keine Problemumgehung
Argumente mit Leerzeichen sind immer noch umständlich
Keine Problemumgehung
Argumente mit Leerzeichen, die eval
versuchen zu erstellen, bewirken nichts.
Problemumgehung: Erstellen Sie das globale Ziel "catch all", ohne die oben genannten Schritte auszuführen. mit dem Problem wie oben, dass es wieder stillschweigend falsch eingegebene legitime Ziele ignoriert.
Es wird verwendet eval
, um das Makefile zur Laufzeit zu ändern. Wie viel schlimmer können Sie in Bezug auf Lesbarkeit und Debugbarkeit und das Prinzip des geringsten Erstaunens gehen .
Problemumgehung: Tun Sie dies nicht !! 1 Schreiben Sie stattdessen ein Shell-Skript, das make ausführt und dann ausgeführt wird prog
.
Ich habe nur mit Gnu Make getestet. andere Marken haben möglicherweise ein anderes Verhalten.
TL; DR versuchen Sie nicht, dies zu tun
$ make run arg
Erstellen Sie stattdessen ein Skript:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
und mach das:
$ ./buildandrunprog.sh arg