run phony makefile

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 de clean (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


para hacer estándar puedes pasar argumentos definiendo macros como esta

make run arg1=asdf

entonces úsalos así

run: ./prog $(arg1) etc

Referencias para make NMake de Microsoft NMake


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:

  1. como argumento: make arg1="asdf" run
  2. o definirse como entorno: arg1="asdf" make run