tutorial make makefile gnu-make

tutorial - makefile linux



Cómo imprimir una variable en makefile (14)

En mi archivo MAKE, tengo una variable ''NDK_PROJECT_PATH'', mi pregunta es ¿cómo puedo imprimirla cuando se compila?

Leí Hacer eco de archivo mostrando la cadena "$ PATH" e intenté:

@echo $(NDK_PROJECT_PATH) @echo $(value NDK_PROJECT_PATH)

Ambos me dan

"build-local.mk:102: *** missing separator. Stop."

¿Alguien sabe por qué no funciona para mí?


@echo $ (NDK_PROJECT_PATH) es la mejor manera de hacerlo. No creo que el error provenga de allí. En general, este error aparece cuando escribiste mal la intención: creo que tienes espacios donde deberías tener una pestaña.


Como ''bobbogo'' en la respuesta anterior señaló y según el manual de GNU Make , puede utilizar información / advertencia / error para mostrar texto.

$(error text…) $(warning text…) $(info text…)

Para imprimir variables,

$(error VAR is $(VAR)) $(warning VAR is $(VAR)) $(info VAR is $(VAR))

cuando usa ''error'', la ejecución de ejecución se detendrá después de mostrar la cadena de error


Ejecutar make -n ; te muestra el valor de la variable ...

Makefile ...

all: @echo $(NDK_PROJECT_PATH)

Mando:

export NDK_PROJECT_PATH=/opt/ndk/project make -n

Salida:

echo /opt/ndk/project


El problema es que echo solo funciona bajo un bloque de ejecución. es decir, cualquier cosa después de "xx:"

Entonces, cualquier cosa que esté por encima del primer bloque de ejecución es solo una inicialización, por lo que no se puede usar ningún comando de ejecución.

Entonces crea un bloque de ejecución


Este makefile generará el mensaje de error ''separador faltante'':

all @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH) done: @echo "All done"

Hay una pestaña antes del @echo "All done" (aunque la regla y la acción done: son en gran medida superfluas), pero no antes de @echo PATH=$(PATH) .

El problema es que la línea que comienza con all debe tener dos puntos : o un igual = para indicar que es una línea objetivo o una línea macro, y no tiene ninguno, por lo que falta el separador.

La acción que hace eco del valor de una variable debe asociarse con un objetivo, posiblemente un dummy o un objetivo PHONEY. Y esa línea objetivo debe tener dos puntos en ella. Si agrega un : después de all en el makefile ejemplo y reemplaza los espacios en blanco iniciales en la siguiente línea por una pestaña, funcionará correctamente.

Probablemente tenga un problema similar cerca de la línea 102 en el makefile original. Si mostró 5 líneas que no están en blanco, sin comentarios antes de las operaciones de eco que están fallando, probablemente sería posible finalizar el diagnóstico. Sin embargo, desde que se formuló la pregunta en mayo de 2013, es poco probable que el makefile esté disponible ahora (agosto de 2014), por lo que esta respuesta no se puede validar formalmente. Solo se puede usar para ilustrar una forma plausible en la que ocurrió el problema.


Esto se puede hacer de una manera genérica y puede ser muy útil al depurar un archivo make complejo. Siguiendo la misma técnica que se describe en otra respuesta , puede insertar lo siguiente en cualquier archivo MAKE:

# if the first command line argument is "print" ifeq ($(firstword $(MAKECMDGOALS)),print) # take the rest of the arguments as variable names VAR_NAMES := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) # turn them into do-nothing targets $(eval $(VAR_NAMES):;@:)) # then print them .PHONY: print print: @$(foreach var,$(VAR_NAMES),/ echo ''$(var) = $($(var))'';) endif

Luego puedes hacer "make print" para volcar el valor de cualquier variable:

$ make print CXXFLAGS CXXFLAGS = -g -Wall


No es necesario modificar el Makefile.

$ cat printvars.mak print-%: @echo ''$*=$($*)'' $ cd /to/Makefile/dir $ make -f ~/printvars.mak -f Makefile print-VARIABLE


Para imprimir el valor de una variable, puede usar:

rule: <tab>@echo $(VAR_NAME)

Cuando la regla se ejecuta, la variable se imprimirá.


Puede imprimir las variables a medida que se lee el archivo MAKE (suponiendo que GNU realice como ha etiquetado esta pregunta adecuadamente) utilizando este método (con una variable llamada "var"):

$(info $$var is [${var}])

Puede agregar esta construcción a cualquier receta para ver qué marca pasará al shell:

PHONY: all all: ; $(info $$var is [${var}])echo Hello world

Ahora, lo que sucede aquí es que make almacena toda la receta ( $(info $$var is [${var}])echo Hello world ) como una única variable expandida recursivamente. Cuando make decide ejecutar la receta (por ejemplo, cuando le dice que construya all ), expande la variable y luego pasa cada línea resultante por separado al shell.

Entonces, con doloroso detalle:

  • Se expande $(info $$var is [${var}])echo Hello world
  • Para hacer esto, primero se expande $(info $$var is [${var}])
    • $$ convierte en $ literal
    • ${var} convierte en :-) (decir)
    • El efecto secundario es que $var is [:-)] aparece en la salida estándar
    • La expansión de $(info...) está vacía
  • Make se queda con echo Hello world
    • Imprima echo Hello world en stdout primero para que sepas qué le va a pedir al shell que haga
  • El shell imprime Hello world en stdout.

Si no desea modificar el Makefile en sí mismo, puede usar --eval para agregar un nuevo objetivo, y luego ejecutar el nuevo objetivo, por ejemplo

make --eval=''print-tests: @echo TESTS $(TESTS) '' print-tests

Puede insertar el carácter TAB requerido en la línea de comando usando CTRL-V, TAB

ejemplo Makefile desde arriba:

all: do-something TESTS= TESTS+=''a'' TESTS+=''b'' TESTS+=''c'' do-something: @echo "doing something" @echo "running tests $(TESTS)" @exit 1


Si simplemente quiere un resultado, quiere usar $(info) por sí mismo. Puedes hacer eso en cualquier parte de un Makefile, y se mostrará cuando se evalúe esa línea:

$(info VAR="$(VAR)")

La salida VAR="<value of VAR>" siempre que los procesos se alineen. Este comportamiento depende mucho de la posición, por lo que debe asegurarse de que la expansión de $(info) suceda DESPUÉS de que todo lo que podría modificar $(VAR) ya haya sucedido.

Una opción más genérica es crear una regla especial para imprimir el valor de una variable. En términos generales, las reglas se ejecutan después de que se asignan las variables, por lo que esto le mostrará el valor que realmente se está utilizando. (Sin embargo, es posible que una regla cambie una variable .) Un buen formato ayudará a aclarar en qué se establece una variable, y la función $(flavor) le dirá qué tipo de variable es algo. Entonces en esta regla:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true

  • $* expande hasta la raíz de que el patrón % coincide con la regla.
  • $($*) expande al valor de la variable cuyo nombre viene dado por $* .
  • El [ y ] delinean claramente la expansión variable. También puede usar " y " o similar.
  • $(flavor $*) le dice qué tipo de variable es. NOTA: $(flavor) toma un nombre de variable, y no su expansión. Entonces, si dices make print-LDFLAGS , obtienes $(flavor LDFLAGS) , que es lo que quieres.
  • $(info text) proporciona salida. Imprima text en su stdout como efecto secundario de la expansión. La expansión de $(info) sin embargo, está vacía. Puedes pensar que es como @echo , pero lo más importante es que no usa el shell, por lo que no tienes que preocuparte por las reglas de cotización del intérprete de comandos.
  • @true está allí solo para proporcionar un comando para la regla. Sin eso, make también generará print-blah is up to date . Siento que @true deja más claro que está destinado a ser un no-operativo.

Al ejecutarlo, obtienes

$ make print-LDFLAGS LDFLAGS is a recursive variable set to [-L/Users/...]


Todas las versiones de make requieren que las líneas de comando tengan sangría con una TAB (no espacio) como el primer carácter en la línea. Si nos mostrara la regla completa en lugar de solo las dos líneas en cuestión, podríamos dar una respuesta más clara, pero debería ser algo así como:

myTarget: myDependencies @echo hi

donde el primer caracter en la segunda línea debe ser TAB.



si usa android make (mka) @echo @echo $(NDK_PROJECT_PATH) no funcionará y le dará el error *** missing separator. Stop." *** missing separator. Stop." Use esta respuesta si está tratando de imprimir variables en Android.

NDK_PROJECT_PATH := some_value $(warning $(NDK_PROJECT_PATH))

eso funcionó para mí