Cómo imprimir una variable en un archivo MAKE


246

En mi archivo MAKE, tengo una variable 'NDK_PROJECT_PATH', mi pregunta es ¿cómo puedo imprimirlo 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 da

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

¿Alguien sabe por qué no me funciona?

Respuestas:


222

Puede imprimir variables a medida que se lee el archivo MAKE (suponiendo que GNU crea como ha etiquetado esta pregunta apropiadamente) 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 la receta completa ( $(info $$var is [${var}])echo Hello world) como una sola variable expandida recursivamente. Cuando make decide ejecutar la receta (por ejemplo, cuando le dice que cree all), expande la variable y luego pasa cada línea resultante por separado al shell.

Entonces, en doloroso detalle:

  • Se expande $(info $$var is [${var}])echo Hello world
  • Para hacer esto primero se expande $(info $$var is [${var}])
    • $$ se convierte en literal $
    • ${var}se convierte :-)(decir)
    • El efecto secundario es que $var is [:-)]aparece en la salida estándar
    • La expansión del $(info...)aunque está vacía
  • Make se queda con echo Hello world
    • echo Hello worldPrimero haga impresiones en stdout para hacerle saber lo que le pedirá al shell que haga
  • El caparazón se imprime Hello worlden stdout.

2
debería ser (punto) .PHONY en lugar de PHONY?
hammadian

172

Según el manual de GNU Make y también señalado por 'bobbogo' en la respuesta a continuación, puede usar información / advertencia / error para mostrar el texto.

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

Para imprimir variables,

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

'error' pararía el maquillaje ejecución, después de mostrar la cadena de error


Wow, no sabía esto. Mucho mejor que el eco, que duplica el comando en los registros.
deepelement


44

Si simplemente quiere algo de salida, desea usarlo $(info)solo. Puede hacerlo en cualquier lugar de un Makefile, y se mostrará cuando se evalúe esa línea:

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

Saldrá VAR="<value of VAR>"cada vez que realice procesos de esa línea. Este comportamiento depende mucho de la posición, por lo que debe asegurarse de que la $(info)expansión ocurra 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 $(flavor)función le dirá qué tipo de variable es algo. Entonces en esta regla:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
  • $*se expande hasta el tallo que el % patrón coincide con la regla.
  • $($*)se expande al valor de la variable cuyo nombre está dado por $*.
  • El [y ]delinean claramente la expansión variable. También puede usar "y / "o similar.
  • $(flavor $*)te 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 Realice impresiones texten su stdout como efecto secundario de la expansión. La expansión de $(info)aunque está vacía. Puede pensarlo así @echo, pero lo más importante es que no usa el shell, por lo que no tiene que preocuparse por las reglas de cotización del shell.
  • @trueestá ahí solo para proporcionar un comando para la regla. Sin eso, make también saldrá print-blah is up to date. Creo que @truedeja más claro que está destinado a ser un no-op.

Al ejecutarlo, obtienes

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

Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar una aclaración de un autor, deje un comentario debajo de su publicación; siempre puede comentar sus propias publicaciones y, una vez que tenga la reputación suficiente , podrá comentar cualquier publicación . - De la opinión
Dragon Energy

Gracias por el comentario Entiendo que puedo comentar una vez que tengo suficiente reputación, pero ¿qué debo hacer mientras tanto? Creo que mi respuesta proporciona un valor adicional, ¿no debería agregarla?
Jim Nasby el

1
Sugeriría reescribir esto para que sea una respuesta independiente que compita con la que está comentando, en lugar de redactarla como un comentario fuera de lugar para esa respuesta.
Charles Duffy el

@ JimNasby Sí, lo que sugirió Charles. En realidad, podría ayudar como un comienzo simplemente eliminar esa parte de "perdón, no suficiente representante para comentar", ya que es una especie de bandera roja. Si lo convierte en una respuesta completa (puede editarlo todo lo que quiera), debería funcionar bastante bien. Salud.
Dragon Energy

Excelente: esta es una respuesta mucho mejor ahora. :)
Charles Duffy el

6

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


2
Intenté '@echo $ (NDK_PROJECT_PATH)', sigo recibiendo un error "build-local.mk:102: *** falta separador. Detener". Solo tengo 1 espacio después de 'echo', no hay espacio ni pestaña antes de '@echo'.
Michael

¿Estás seguro de que el error proviene de esta línea? ¿Es esta línea una regla? Probablemente debe estar sangrada ...

6

Todas las versiones de makerequieren que las líneas de comando estén sangradas con una TAB (no espacio) como primer carácter de la línea. Si nos mostró 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 como:

myTarget: myDependencies
        @echo hi

donde el primer carácter en la segunda línea debe ser TAB.


4

Correr 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

Sin embargo, esto es bastante útil y lo uso --just-printen lugar de ejecución
Fredrick Gauss el

3

Esto makefilegenerará 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 done:regla y la acción son en gran medida superfluas), pero no antes del @echo PATH=$(PATH).

El problema es que el inicio de línea alldebe tener dos puntos :o un igual =para indicar que es una línea objetivo o una línea macro, y no tiene ninguna, por lo que falta el separador.

La acción que hace eco del valor de una variable debe estar asociada con un objetivo, posiblemente un objetivo ficticio o PHONEY. Y esa línea objetivo debe tener dos puntos. Si agrega un :after allen el ejemplo makefiley reemplaza los espacios en blanco en la siguiente línea por una pestaña, funcionará de manera sensata.

Probablemente tenga un problema análogo cerca de la línea 102 en el original makefile. Si mostraste 5 líneas en blanco y sin comentarios antes de las operaciones de eco que están fallando, probablemente sería posible finalizar el diagnóstico. Sin embargo, dado que la pregunta se hizo en mayo de 2013, es poco probable que la división makefileaún 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 de cómo ocurrió el problema.


3

No es necesario modificar el Makefile.

$ cat printvars.mak
print-%:
        @echo '$*=$($*)'

$ cd /to/Makefile/dir
$ make -f ~/printvars.mak -f Makefile print-VARIABLE

2

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

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

Así que crea un bloc de ejecución


1

Esto se puede hacer de forma 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 puede simplemente "hacer imprimir" para volcar el valor de cualquier variable:

$ make print CXXFLAGS
CXXFLAGS = -g -Wall


0

Si no desea modificar el Makefile en sí, puede usarlo --evalpara agregar un nuevo objetivo y luego ejecutar el nuevo objetivo, p. Ej.

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

Estoy tratando de ejecutar su script pero recibo un errormake: *** missing separator. Stop.
Rinaldi Segecin

Ah, perdón, arreglado. Faltan dos puntos al final del objetivo "pruebas de impresión".
Wade

En realidad no necesita líneas nuevas y pestañas, un punto y coma será suficiente:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
bobbogo

0

si usa android make (mka) @echo $(NDK_PROJECT_PATH)no funcionará y le da un error, *** missing separator. Stop." use esta respuesta si está tratando de imprimir variables en android make

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

eso funcionó para mí


0

Por lo general, hago eco de un error si quería ver el valor de la variable (solo si desea ver el valor. Se detendrá la ejecución).

@echo $ (error NDK_PROJECT_PATH = $ (NDK_PROJECT_PATH))

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.