makefile - phony - Pasando argumentos para "hacer correr"
makefile windows (11)
Yo uso Makefiles.
Tengo un objetivo llamado run
que ejecuta el objetivo de compilación. Simplificado, se parece a lo siguiente:
prog: ....
...
run: prog
./prog
Siéntate de nuevo. Sé que esto es ingenioso, pero no hay necesidad de una ovación de pie.
Ahora, mi pregunta es: ¿hay alguna forma de pasar argumentos? Así que eso
make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat
¡Gracias!
Aquí está mi ejemplo. Tenga en cuenta que estoy escribiendo bajo Windows 7, usando mingw32-make.exe que viene con Dev-Cpp. (Tengo c: / Windows / System32 / make.bat, por lo que el comando todavía se llama "make".)
$(make run) args to my command
Uso para la limpieza regular:
.PHONY: run
run:
prog $(arg1)
Uso para limpiar y crear una copia de seguridad en mydir /:
clean:
$(RM) $(OBJ) $(BIN)
@echo off
if "${backup}" NEQ "" ( mkdir ${backup} 2> nul && copy * ${backup} )
Aquí hay otra solución que podría ayudar con algunos de estos casos de uso:
test-%:
$(PYTHON) run-tests.py $@
En otras palabras, elija un prefijo ( test-
en este caso), y luego pase el nombre del objetivo directamente al programa / corredor. Supongo que esto es más útil si hay algún script de corredor involucrado que pueda desenvolver el nombre del objetivo en algo útil para el programa subyacente.
Esta pregunta tiene casi tres años, pero de todos modos ...
Si estás usando GNU make, esto es fácil de hacer. El único problema es que make
interpretará los argumentos no opcionales en la línea de comandos como objetivos. La solución es convertirlos en objetivos de no hacer nada, para que make
no se queje:
# 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)
Ejecutando esto da:
$ make run foo bar baz
prog foo bar baz
No conozco una forma de hacer exactamente lo que quiere, pero una solución puede ser:
run: ./prog
./prog ${ARGS}
Entonces:
make ARGS="asdf" run
No estoy muy orgulloso de esto, pero no quería pasar las variables de entorno, así que invertí la forma de ejecutar un comando enlatado:
$ ./buildandrunprog.sh arg
esto imprimirá el comando que desea ejecutar, así que simplemente evalúelo en una subshell:
second_argument := $(word 2, $(MAKECMDGOALS) )
No. Mirando la sintaxis de la página de manual de GNU make
make [-f makefile] [opciones] ... [objetivos] ...
puede especificar múltiples objetivos, por lo tanto, ''no'' (al menos no de la manera exacta que especificó).
Puede extraer explícitamente cada n-ésimo argumento en la línea de comando. Para hacer esto, puede usar la variable MAKECMDGOALS, que contiene la lista de argumentos de la línea de comandos dada a ''make'', que interpreta como una lista de objetivos. Si desea extraer el n-ésimo argumento, puede usar esa variable combinada con la función "palabra", por ejemplo, si desea el segundo argumento, puede almacenarlo en una variable de la siguiente manera:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
Puede pasar la variable al Makefile como a continuación:
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
Alternativamente use la solución provista por Beta :
run:
@echo ./prog $(filter-out $@,$(MAKECMDGOALS))
%:
@:
%:
- regla que coincide con cualquier nombre de tarea;@:
- receta vacía = no hacer nada
Uso:
$ make run the dog kicked the cat
./prog the dog kicked the cat
TL; DR no intente hacer esto
$ make run arg
en su lugar crea guión:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
y haz esto:
$ ./buildandrunprog.sh arg
Responde a la pregunta planteada:
Puedes usar una variable en la receta.
run: prog
./prog $(var)
luego pasa una asignación de variable como un argumento para hacer
$ make run var=arg
esto ejecutará ./prog arg
.
Pero ten cuidado con las trampas. Explicaré los inconvenientes de este método y otros métodos más abajo.
Responda a la intención asumida detrás de la pregunta:
El supuesto: desea ejecutar prog
con algunos argumentos, pero reconstruirlo antes de ejecutar si es necesario.
La respuesta: crear un script que reconstruya si es necesario y luego ejecute prog con args
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
Este guión deja muy clara la intención. Utiliza make para hacer lo que es bueno para: construir. utiliza un script de shell para hacer lo que es bueno para: procesamiento por lotes.
También la sintaxis de llamada es ahora prácticamente idéntica:
$ ./buildandrunprog.sh arg
comparar con:
$ make run foo bar --wat var=arg
además, puede hacer lo que necesite con la total flexibilidad y expresividad de un script de shell sin todas las advertencias de un makefile.
fondo:
make no está diseñado para ejecutar un objetivo y pasar argumentos a ese objetivo. todos los argumentos en la línea de comando se interpretan como un objetivo (también conocido como objetivo), como una opción o como una asignación de variable.
así que si ejecuta esto:
$ make run var=arg
make interpretará run
, foo
y bar
como objetivos (objetivos) para actualizar de acuerdo con sus recetas. --wat
como una opción para hacer. y var=arg
como una asignación de variable.
Para obtener más detalles, consulte: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals
para la terminología vea: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction
sobre el método de asignación de variables y por qué lo recomiendo
run: prog
./prog $(var)
y la variable en la receta
$ ./prog arg
Esta es la forma más "correcta" y directa de pasar argumentos a una receta. pero si bien puede usarse para ejecutar un programa con argumentos, ciertamente no está diseñado para usarse de esa manera. vea https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
en mi opinión, esto tiene una gran desventaja: lo que quiere hacer es ejecutar prog
con argumento arg
. pero en lugar de escribir:
$ make run var=arg
estas escribiendo:
$ make run var="foo bar/ baz"
./prog foo bar/ baz
argcount: 2
arg: foo
arg: bar baz
esto se vuelve aún más incómodo al intentar pasar múltiples argumentos o argumentos que contienen espacios:
$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz
comparar con:
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
para el registro esto es lo que parece mi prog
:
run: prog
./prog "$(var)"
tenga en cuenta que cuando coloca $(var)
entre comillas en el archivo make:
$ make run var="foo bar/ baz"
./prog "foo bar/ baz"
argcount: 1
arg: foo bar/ baz
entonces prog
siempre obtendrá solo un argumento:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
Todo esto es por lo que recomiendo contra esta ruta.
Para completar, aquí hay algunos otros métodos para "pasar argumentos para ejecutar".
Método 1:
$ ./buildandrunprog.sh foo "bar baz"
Explicación muy breve: filtre el objetivo actual de la lista de objetivos. crea catch all target ( %
) que no hace nada para ignorar silenciosamente los otros objetivos.
método 2:
$ ./prog foo "bar baz"
súper breve explicación: si se run
el objetivo, elimine el primer objetivo y cree objetivos de no hacer nada para los objetivos restantes utilizando eval
.
Para una explicación más detallada, estudie el manual de make: https://www.gnu.org/software/make/manual/html_node/index.html
Problemas del método 1:
Los argumentos que comienzan con un guión se interpretarán por make y no se pasarán como un objetivo.
run: prog ./prog $(filter-out $@, $(MAKECMDGOALS)) %: @true
solución
ifeq (run, $(firstword $(MAKECMDGOALS))) runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS)) $(eval $(runargs):;@true) endif run: ./prog $(runargs)
si un argumento se
run
(igual al objetivo) también se eliminará$ make run --foo --bar
ejecutará
./prog foo bar
lugar de./prog foo bar run
solución posible con el método 2
Si un argumento es un objetivo legítimo, también se ejecutará.
$ make run -- --foo --bar
ejecutará
./prog foo bar clean
pero también la receta para el objetivo declean
(suponiendo que exista).solución posible con el método 2
Es incómodo pasar argumentos con espacios
$ make run foo bar run
sin solución
cuando se equivoca al escribir un objetivo legítimo, se ignorará silenciosamente debido a la captura de todos los objetivos.
$ make run foo bar clean
simplemente ignorará silenciosamente
celan
.La solución es hacer todo detallado. para que veas lo que pasa pero eso crea mucho ruido para la salida legítima.
Problemas del método 2:
Si un argumento tiene el mismo nombre que un destino existente, make imprimirá una advertencia de que se está sobrescribiendo.
ninguna solución que yo sepa
pasar argumentos con el espacio sigue siendo incómodo.
sin solución
Los argumentos con espacios se
eval
tratando de crear objetivos de nada.solución alternativa: cree la captura global de todos los destinos sin hacer nada como se indicó anteriormente. con el problema anterior, nuevamente ignorará silenciosamente objetivos legítimos mal escritos.
utiliza
eval
para modificar el makefile en tiempo de ejecución. cuánto peor puede ir en términos de legibilidad y depuración y el Principio de menos asombro .solución: ¡no haga esto! 1 en lugar de eso, escriba un script de shell que ejecute make y luego ejecute
prog
.
Sólo he probado utilizando gnu make. Otras marcas pueden tener un comportamiento diferente.
TL; DR no intente hacer esto
$ make run foo "bar/ baz"
en su lugar crea guión:
$ make celan
y haz esto:
$ make run arg
anon , run: ./prog
parece un poco extraño, ya que la parte derecha debe ser un objetivo, así que run: prog
ve mejor.
Yo sugeriría simplemente:
run:
@echo command-you-want
Y me gustaría agregar, que los argumentos pueden ser pasados:
- como argumento:
make arg1="asdf" run
- o definirse como entorno:
arg1="asdf" make run