Pasar argumentos para "hacer ejecutar"
Yo uso archivos Make.
Tengo un objetivo llamado run
que ejecuta el objetivo de compilación. Simplificado, se parece a lo siguiente:
prog: ....
...
run: prog
./prog
¿Hay alguna forma de pasar argumentos? De modo que
make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat
No conozco una manera de hacer exactamente lo que quieres, pero una solución alternativa podría ser:
run: ./prog
./prog $(ARGS)
Entonces:
make ARGS="asdf" run
# or
make run ARGS="asdf"
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 que no sean opciones en la línea de comando como objetivos. La solución es convertirlos en objetivos que no hacen nada, así que make
no te quejes:
# 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)
Ejecutar esto da:
$ make run foo bar baz
prog foo bar baz
TL;DR no intentes hacer esto
$ make run arg
en su lugar cree un script build_and_run_prog.sh
:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
y haz esto:
$ ./build_and_run_prog.sh arg
Siga leyendo para obtener una explicación de por qué esta es la opción más razonable y por qué es mejor evitar las otras alternativas.
Respuesta a la pregunta formulada : cómo pasar argumentos a un objetivo de creación
puedes usar una variable en la receta
run: prog
./prog $(var)
luego pase una asignación de variable como argumento para hacer
$ make run var=arg
esto se ejecutará ./prog arg
.
esta es la forma más correcta y sencilla de "pasar argumentos a una receta". consulte el manual de gnu make sobre variables anuladas
pero si bien puede usarse para ejecutar un programa con argumentos, ciertamente no está diseñado para usarse de esa manera.
Permítanme explicar algunos problemas.
lo que quieres hacer es ejecutar prog
con argumento arg
. pero en lugar de escribir:
$ ./prog arg
necesitas escribir:
$ make run var=arg
Esto se vuelve aún más incómodo cuando se intenta pasar múltiples argumentos o argumentos que contienen espacios.
en lugar de escribir
$ ./prog foo "bar baz"
necesitas escribir
$ make run var="foo bar\ baz"
o
$ make run var="foo \"bar baz\""
Espero que veas cómo esto se volverá bastante incómodo para cualquier cosa que no sean los argumentos más simples.
También tenga en cuenta que no debe poner $(var)
comillas en el archivo MAKE:
run: prog
./prog "$(var)"
porque entonces prog
siempre obtendrá un solo argumento.
Responda a la supuesta intención detrás de su pregunta : desea ejecutar prog
con algunos argumentos pero reconstruirlo antes de ejecutarlo si es necesario.
Cree un script que se reconstruya si es necesario y luego ejecute prog con args
build_and_run_prog.sh
:
#! /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 aquello para lo que sirve: construir/compilar. Utiliza un script de shell para hacer aquello para lo que sirve: procesamiento por lotes.
Además, puede hacer cualquier otra cosa que necesite con la total flexibilidad y expresividad de un script de shell sin todas las advertencias de un archivo MAKE.
Además, la sintaxis de llamada ahora es prácticamente idéntica:
$ ./build_and_run_prog.sh foo "bar baz"
en comparación con:
$ ./prog foo "bar baz"
contraste con
$ make run var="foo bar\ baz"
Explicación básica de cómo make maneja los argumentos :
Make no está diseñado para pasar argumentos a un 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.
entonces si ejecutas esto:
$ make run foo --wat var=arg
make interpretará run
y foo
como objetivos (objetivos) actualizará según sus recetas. --wat
como opción para hacer. Y var=arg
como asignación variable para make.
Espero que puedas ver que el único método que tienes para pasar información desde la línea de comando para usarla dentro de una receta (sin hacks) es mediante la asignación de variables.
para más detalles consulte el manual de gnu sobre cómo ejecutar make
Para completar, estos son algunos de los trucos para "pasar argumentos para ejecutar".
Método 1 :
run: prog
./prog $(filter-out $@, $(MAKECMDGOALS))
%:
@true
Explicación súper breve: filtre el objetivo actual de la lista de objetivos. luego pase la lista de objetivos como argumentos a prog
. También cree un objetivo general ( %
) que no haga nada para ignorar silenciosamente todos los demás "objetivos".
esto te permitirá escribir algo como esto
$ make run arg1 arg2
problemas del método 1 :
Los argumentos que comienzan con un guión se interpretarán como marca y no como objetivo.
$ make run --foo --bar
solución alterna
$ make run -- --foo --bar
Los argumentos con signo igual serán interpretados como make y no aprobados.
$ make run foo=bar
no hay solución
Las discusiones con espacios son incómodas.
$ make run foo "bar\ baz"
no hay solución
Si un argumento resulta ser
run
(igual al objetivo), también se eliminará.$ make run foo bar run
se ejecutará
./prog foo bar
en lugar de./prog foo bar run
solución alternativa posible con el método 2
Si un argumento es un objetivo legítimo, también se ejecutará.
$ make run foo bar clean
se ejecutará
./prog foo bar clean
, sino también la receta para el objetivoclean
(suponiendo que exista).solución alternativa posible con el método 2
Cuando escribe mal un objetivo legítimo, se ignorará silenciosamente debido al objetivo de captura total.
$ make celan
simplemente lo ignorará en silencio
celan
.La solución alternativa es hacer que todo sea detallado. pues ya ves lo que pasa. pero eso crea mucho ruido para la producción legítima.
Método 2 :
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
Explicación súper breve: si el objetivo es run
, procese la lista de objetivos y guárdela en la variable. También cree objetivos de no hacer nada para los "objetivos" restantes usando eval
. más tarde, cuando se ejecute, prog
pase la variable preparada como argumentos.
problemas del método 2 :
Si un argumento tiene el mismo nombre que un objetivo existente, make imprimirá una advertencia de que se está sobrescribiendo.
no hay solución que yo sepa
Los argumentos con un signo igual seguirán siendo interpretados por make y no aprobados.
no hay solución
Las discusiones con espacios siguen siendo incómodas
no hay solución
Argumentos con pausas espaciales
eval
que intentan crear objetivos de no hacer nada.Solución alternativa: cree el objetivo global de captura total sin hacer nada como se indicó anteriormente. con el problema anterior de que nuevamente ignorará silenciosamente los objetivos legítimos mal escritos.
se utiliza
eval
para modificar el archivo MAKE en tiempo de ejecución. ¿Cuánto peor se puede llegar en términos de legibilidad y depuración y el Principio de mínimo asombro ?solución alternativa: ¡no lo hagas!
Solo he probado usando gnu make. otras marcas pueden tener un comportamiento diferente.
ñu hacer manual
https://www.gnu.org/software/make/manual/html_node/index.html
para la marca estándar, puede pasar argumentos definiendo macros como esta
make run arg1=asdf
entonces úsalos así
run: ./prog $(arg1)
etc
Referencias para hacer NMake de Microsoft