Passare argomenti a "make run"


Risposte:


264

Non conosco un modo per fare esattamente quello che vuoi, ma una soluzione alternativa potrebbe essere:

run: ./prog
    ./prog $(ARGS)

Poi:

make ARGS="asdf" run
# or
make run ARGS="asdf"

27
@Rob: $ () è più portatile, funziona in Nmake oltre che make.
John Knoeller,

7
@Rob: Nmake non ha mai supportato $ {} per l'espansione macro e sembra essere una forma arcaica ora in fase di creazione. $ () è raccomandato da tutti i tutorial online che ho visto. $ () è anche più coerente con altri strumenti come bash.
John Knoeller,

10
Forse è arcaico. Ho sempre usato $ {}, ma il manuale di GNU Make afferma "Per sostituire il valore di una variabile, scrivi un segno di dollaro seguito dal nome della variabile tra parentesi o parentesi graffe: $(foo)' or $ {foo} 'è un riferimento valido a la variabile "pippo". " e procede a fornire esempi in cui viene utilizzato solo $ (). Ah bene.
Jakob Borg,

7
applausi John e la calma, sono tornato indietro e ho visto che il suggerimento proveniva dalla mia copia del libro OReilly della prima edizione "Managing Projects with Make". L'autore afferma la regola sulla sostituzione dell'archivio usando () e le macro in grado di fare entrambe le cose, ma suggerisce di usare {} per distinguere. Ma .... La nuova edizione ora è stata ribattezzata "Gestione dei progetti con GNU Make" e utilizza () dappertutto. Vai a capire .... Immagino che dovrò modernizzare! (-: Sono ancora sorpreso dal fatto che MS NMake abbia barfatto a {}, comunque.
Rob Wells,

1
@xealits Certo che c'è - c'è un esempio alla domanda qui
helvete

198

Questa domanda ha quasi tre anni, ma comunque ...

Se stai usando GNU make, questo è facile da fare. L'unico problema è che makeinterpreteranno gli argomenti non di opzione nella riga di comando come target. La soluzione è di trasformarli in obiettivi "non fare nulla", quindi makenon lamentarti:

# If the first argument is "run"...
ifeq (run,$(firstword $(MAKECMDGOALS)))
  # use the rest as arguments for "run"
  RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
  # ...and turn them into do-nothing targets
  $(eval $(RUN_ARGS):;@:)
endif

prog: # ...
    # ...

.PHONY: run
run : prog
    @echo prog $(RUN_ARGS)

In esecuzione questo dà:

$ make run foo bar baz
prog foo bar baz

2
Questo è fantastico, tranne che non sembra funzionare per argomenti che iniziano con un trattino:prog foo bar --baz
ingydotnet,

22
Esso funziona in questo caso, ma si deve dire makenon interpretare --bazcome opzione riga di comando: make -- prog foo bar --baz. Il --significato "tutto ciò che segue è un argomento, non un'opzione".
Idelic

Come definirei un valore predefinito per l' RUN_ARGSutilizzo di questo?
Bouke,

Magari aggiungi un elseramo al ifeqe imposta RUN_ARGSlì?
Idelico

1
Buon punto azzurrato! Ma esiste una soluzione per questo: sostituire la linea "eval" con $(eval $(RUN_ARGS):dummy;@:), senza definire un bersaglio fittizio.
Lucas Cimon,

52

per standard make puoi passare argomenti definendo macro come questa

make run arg1=asdf

quindi usali in questo modo

run: ./prog $(arg1)
   etc

Riferimenti per rendere Microsoft NMake


34

Puoi passare la variabile al Makefile come di seguito:

run:
    @echo ./prog $$FOO

Uso:

$ make run FOO="the dog kicked the cat"
./prog the dog kicked the cat

o:

$ FOO="the dog kicked the cat" make run
./prog the dog kicked the cat

In alternativa, utilizzare la soluzione fornita da Beta :

run:
    @echo ./prog $(filter-out $@,$(MAKECMDGOALS))
%:
    @:

%:- regola che corrisponde a qualsiasi nome di attività; @:- ricetta vuota = non fare nulla

Uso:

$ make run the dog kicked the cat
./prog the dog kicked the cat

23

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 progalcuni 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à rune foocome obiettivi (target) da aggiornare in base alle loro ricette. --watcome opzione per make. e var=argcome 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 progcon 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 progappare 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 progotterrà 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 è runquindi 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 barinvece 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 cleanma 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 evaltentativo 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 evalper 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

12

Ecco un'altra soluzione che potrebbe aiutare con alcuni di questi casi d'uso:

test-%:
    $(PYTHON) run-tests.py $@

In altre parole, selezionare un prefisso ( test-in questo caso), quindi passare il nome di destinazione direttamente al programma / corridore. Immagino che ciò sia utile soprattutto se è coinvolto qualche script di runner che può scartare il nome di destinazione in qualcosa di utile per il programma sottostante.


2
Puoi anche usare $*per passare solo la parte del bersaglio che corrisponde al %.
Malvineous,

9

No. Guardando la sintassi dalla pagina man di GNU make

make [-f makefile] [opzioni] ... [target] ...

puoi specificare più target, quindi 'no' (almeno no nel modo esatto specificato).


4

È possibile estrarre esplicitamente ogni n-esimo argomento nella riga di comando. Per fare ciò, è possibile utilizzare la variabile MAKECMDGOALS, contiene l'elenco degli argomenti della riga di comando forniti da 'make', che interpreta come un elenco di destinazioni. Se si desidera estrarre l'argomento n-esimo, è possibile utilizzare quella variabile combinata con la funzione "parola", ad esempio, se si desidera il secondo argomento, è possibile memorizzarlo in una variabile come segue:

second_argument := $(word 2, $(MAKECMDGOALS) )

Questo esegue anche il comando make per quell'argomento. make: *** No rule to make target 'arg'. Stop.
ThomasReggi,

2

anon , run: ./progsembra un po 'strano, poiché la parte giusta dovrebbe essere un bersaglio, quindirun: prog sembra migliore.

Suggerirei semplicemente:

.PHONY: run

run:
        prog $(arg1)

e vorrei aggiungere che gli argomenti possono essere passati:

  1. come argomento: make arg1="asdf" run
  2. o essere definito come ambiente: arg1="asdf" make run

2

Ecco il mio esempio Si noti che sto scrivendo in Windows 7, utilizzando mingw32-make.exe fornito con Dev-Cpp. (Ho c: \ Windows \ System32 \ make.bat, quindi il comando è ancora chiamato "make".)

clean:
    $(RM) $(OBJ) $(BIN) 
    @echo off
    if "${backup}" NEQ "" ( mkdir ${backup} 2> nul && copy * ${backup} )

Utilizzo per la pulizia regolare:

make clean

Utilizzo per la pulizia e la creazione di un backup in mydir /:

make clean backup=mydir

2

Non troppo orgoglioso di questo, ma non volevo passare le variabili d'ambiente, quindi ho invertito il modo di eseguire un comando fisso:

run:
    @echo command-you-want

questo stamperà il comando che si desidera eseguire, quindi è sufficiente valutarlo in una subshell:

$(make run) args to my command

4
guardando indietro a questa risposta due anni dopo: perché mai ero così testardo da non voler usare le variabili d'ambiente e perché pensavo che integrare la generazione di un altro comando fosse migliore?
Conrad.Dean,

0

Ho trovato un modo per ottenere gli argomenti con un segno di uguale (=)! La risposta è soprattutto un'aggiunta alla risposta di @lesmana (in quanto è la più completa e spiegata qui), ma sarebbe troppo grande per scriverla come commento. Ancora una volta, ripeto il suo messaggio: TL; DR non provare a farlo!

Avevo bisogno di un modo per trattare il mio argomento --xyz-enabled=false(dato che il default è vero), che ormai sappiamo tutti che questo non è un obiettivo di make e quindi non fa parte $(MAKECMDGOALS).

Osservando tutte le variabili di make, facendo eco, $(.VARIABLES)ho ottenuto questi output interessanti:

[...] -*-command-variables-*- --xyz-enabled [...]

Questo ci consente di andare in due modi: o iniziare tutto con una --(se questo si applica al tuo caso), oppure esaminare la GNU per rendere specifica (probabilmente non destinata a noi usare) una variabile -*-command-variables-*-. ** Vedi piè di pagina per ulteriori opzioni ** Nel mio caso questa variabile conteneva:

--xyz-enabled=false

Con questa variabile possiamo combinarla con la soluzione già esistente con $(MAKECMDGOALS)e quindi definendo:

# the other technique to invalidate other targets is still required, see linked post
run:
    @echo ./prog $(-*-command-variables-*-) $(filter-out $@,$(MAKECMDGOALS))`

e usandolo con (mescolando esplicitamente l'ordine degli argomenti):

make run -- config --xyz-enabled=false over=9000 --foo=bar show  isit=alwaysreversed? --help

tornato:

./prog isit=alwaysreversed? --foo=bar over=9000 --xyz-enabled=false config show --help

Come puoi vedere, perdiamo l'ordine totale degli arg. La parte con i termini "assegnazione" sembra essere stata invertita, l'ordine dei parametri "destinazione" viene mantenuto. Ho messo il "compito" -args all'inizio, speriamo che al tuo programma non importi dove si colloca l'argomento.


Aggiornamento: seguenti rendono anche le variabili promettenti:

MAKEFLAGS =  -- isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false
MAKEOVERRIDES = isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false

-2

Un altro trucco che uso è la -nbandiera, che dice makedi fare una corsa a secco. Per esempio,

$ make install -n 
# Outputs the string: helm install stable/airflow --name airflow -f values.yaml
$ eval $(make install -n) --dry-run --debug
# Runs: helm install stable/airflow --name airflow -f values.yaml --dry-run --debug
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.