TL; DR non provare a farlo
$ make run arg
invece crea script:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
e fai questo:
$ ./buildandrunprog.sh arg
risposta alla domanda formulata:
puoi usare una variabile nella ricetta
run: prog
./prog $(var)
quindi passare un'assegnazione variabile come argomento da creare
$ make run var=arg
questo verrà eseguito ./prog arg
.
ma attenzione alle insidie. approfondirò le insidie di questo metodo e altri metodi più in basso.
rispondere all'intenzione assunta alla base della domanda:
il presupposto: si desidera eseguire prog
alcuni argomenti ma farlo ricostruire prima di eseguirlo, se necessario.
la risposta: crea uno script che ricostruisce se necessario, quindi esegue prog con args
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
questo script rende l'intenzione molto chiara. usa make per fare ciò per cui è buono: costruire. utilizza uno script di shell per fare ciò per cui è buono: elaborazione batch.
in più puoi fare tutto ciò di cui potresti aver bisogno con la piena flessibilità ed espressività di uno script shell senza tutti gli avvertimenti di un makefile.
anche la sintassi di chiamata ora è praticamente identica:
$ ./buildandrunprog.sh foo "bar baz"
confrontare con:
$ ./prog foo "bar baz"
in contrasto con
$ make run var="foo bar\ baz"
sfondo:
make non è progettato per passare argomenti a una destinazione. tutti gli argomenti sulla riga di comando vengono interpretati come obiettivo (noto anche come obiettivo), come opzione o come assegnazione variabile.
quindi se esegui questo:
$ make run foo --wat var=arg
make interpreterà run
e foo
come obiettivi (target) da aggiornare in base alle loro ricette. --wat
come opzione per make. e var=arg
come assegnazione variabile.
per maggiori dettagli consultare: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals
per la terminologia consultare: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction
sul metodo di assegnazione variabile e perché sconsiglio
$ make run var=arg
e la variabile nella ricetta
run: prog
./prog $(var)
questo è il modo più "corretto" e diretto per passare argomenti a una ricetta. ma sebbene possa essere utilizzato per eseguire un programma con argomenti, non è certamente progettato per essere utilizzato in questo modo. vedi https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
secondo me questo ha un grosso svantaggio: quello che vuoi fare è correre prog
con l'argomento arg
. ma invece di scrivere:
$ ./prog arg
stai scrivendo:
$ make run var=arg
questo diventa ancora più imbarazzante quando si tenta di passare più argomenti o argomenti contenenti spazi:
$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz
confrontare con:
$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz
per la cronaca questo è come prog
appare il mio :
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
nota inoltre che non dovresti inserire le $(var)
virgolette nel makefile:
run: prog
./prog "$(var)"
perché allora prog
otterrà sempre solo un argomento:
$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz
tutto questo è il motivo per cui mi raccomando contro questo percorso.
per completezza ecco alcuni altri metodi per "passare argomenti per far funzionare".
metodo 1:
run: prog
./prog $(filter-out $@, $(MAKECMDGOALS))
%:
@true
spiegazione super breve: filtra l'obiettivo corrente dall'elenco degli obiettivi. create catch all target ( %
) che non fa nulla per ignorare silenziosamente gli altri obiettivi.
metodo 2:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
spiegazione super breve: se l'obiettivo è run
quindi rimuovere il primo obiettivo e creare non fare nulla obiettivi per gli obiettivi rimanenti utilizzando eval
.
entrambi ti permetteranno di scrivere qualcosa del genere
$ make run arg1 arg2
per una spiegazione più approfondita, studia il manuale di make: https://www.gnu.org/software/make/manual/html_node/index.html
problemi del metodo 1:
gli argomenti che iniziano con un trattino saranno interpretati da make e non passati come obiettivo.
$ make run --foo --bar
soluzione
$ make run -- --foo --bar
gli argomenti con un segno di uguale saranno interpretati da make e non passati
$ make run foo=bar
nessuna soluzione alternativa
gli argomenti con spazi sono imbarazzanti
$ make run foo "bar\ baz"
nessuna soluzione alternativa
se un argomento risulta essere run
(uguale al target) verrà rimosso anche
$ make run foo bar run
verrà eseguito ./prog foo bar
invece di./prog foo bar run
soluzione alternativa possibile con il metodo 2
se un argomento è un obiettivo legittimo verrà eseguito anche.
$ make run foo bar clean
verrà eseguito ./prog foo bar clean
ma anche la ricetta per il target clean
(supponendo che esista).
soluzione alternativa possibile con il metodo 2
quando si digita male un bersaglio legittimo, questo verrà silenziosamente ignorato a causa della cattura del bersaglio.
$ make celan
ignorerà in silenzio celan
.
soluzione è rendere tutto dettagliato. quindi vedi cosa succede. ma questo crea molto rumore per l'output legittimo.
problemi del metodo 2:
se un argomento ha lo stesso nome di una destinazione esistente, make stamperà un avviso che viene sovrascritto.
nessuna soluzione alternativa che conosco
gli argomenti con un segno uguale saranno comunque interpretati da make e non passati
nessuna soluzione alternativa
gli argomenti con spazi sono ancora imbarazzanti
nessuna soluzione alternativa
gli argomenti con interruzioni di spazio nel eval
tentativo di creare non fanno nulla.
soluzione alternativa: creare la cattura globale di tutto il target senza fare nulla come sopra. con il problema di cui sopra che ignorerà di nuovo silenziosamente obiettivi legittimi errati.
utilizza eval
per modificare il makefile in fase di esecuzione. quanto peggio si può andare in termini di leggibilità e debugabilità e il Principio del minimo stupore .
soluzione alternativa: non farlo !! 1 invece scrivi uno script di shell che esegue make e quindi viene eseguito prog
.
ho testato solo usando gnu make. altre marche possono avere comportamenti diversi.
TL; DR non provare a farlo
$ make run arg
invece crea script:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
e fai questo:
$ ./buildandrunprog.sh arg