Proceso de sustitución en GNU Makefiles

11

En un indicador de bash, uno puede ejecutar diff usando pseudo archivos:

diff <(echo test) <(echo test)

Agregar esto como está en un Makefile falla:

all:
        diff <(echo test) <(echo test)

El error (sugerencia: / bin / sh apunta a / bin / bash en este sistema):

/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `diff <(echo test) <(echo test)'

¿Qué significa, y hay alguna manera de diferenciar dos salidas sin usar archivos temporales?

Johannes
fuente

Respuestas:

20

/bin/shpuede estar bashen su sistema, pero cuando se invoca como sh, bashse ejecutará en modo POSIX (como si POSIXLY_CORRECTestuviera definido o se inició con --posix).

En este modo, las sustituciones de proceso no existen.

Soluciones:

all:
    command1 >file1
    command2 >file2
    diff file1 file2
    rm -f file1 file2

Alternativa:

all:
    bash -c "diff <(command1) <(command2)"

O simplemente defina la variable Makefile SHELLcomo /bin/bash:

SHELL=/bin/bash

Si desea portabilidad, elija la primera solución. Si está de acuerdo con una dependencia bash, elija el segundo. Si además no necesita preocuparse por makeimplementaciones que no sean GNU , use la tercera.


Respecto a la configuración SHELL: el estándar POSIX dice que los ejecutables en Makefiles deben ser invocados con la system()función de biblioteca C por make. No se garantiza que esta función use la SHELLvariable de entorno (de hecho, el estándar desaconseja hacerlo). El estándar también llega a cierto punto para decir que establecer la variable Makefile SHELLno debería afectar la variable de entorno SHELL . makeSin embargo, en la mayoría de las implementaciones que conozco, la variable Makefile SHELLse usará para ejecutar los comandos.

La sugerencia en la justificación de la makeutilidad es utilizar bash -c:

Se omitió la MAKESHELLcaracterística histórica y las características relacionadas proporcionadas por otras makeimplementaciones. En algunas implementaciones se usa para permitir que un usuario anule el shell que se usará para ejecutar makecomandos. Esto fue confuso; para un portátil make, el escritor de archivos MAKE debe elegir el shell. Además, un escritor de archivos MAKE no puede requerir que se use un shell alternativo y aún así considera que el archivo MAKE es portátil. Si bien sería posible estandarizar un mecanismo para especificar un shell alternativo, las implementaciones existentes no están de acuerdo con dicho mecanismo, y los escritores de archivos MAKE ya pueden invocar un shell alternativo especificando el nombre del shell en la regla para un objetivo; por ejemplo:

python -c "foo"

Kusalananda
fuente
¿Hay alguna manera de invocar bashen el Makefile o cualquier otra solución al problema de diff sin usar archivos temporales?
Johannes
Solo use dos archivos temporales, esto es más o menos lo que el método de sustitución del proceso haría de todos modos.
Kusalananda
3
También podría establecer SHELLque /bin/bashen el Makefile.
Stephen Kitt
1
@Johannes Kusalananda's agregó la información a su respuesta, lo cual es genial ya que presenta una serie de opciones y las circunstancias en las que se pueden usar. Prefiero que aceptes esta respuesta ... (¡Pero aprecio el sentimiento!)
Stephen Kitt
2
La información de que el uso de la variable SHELL no cumple con POSIX fue muy útil. Quizás aún sea mejor usarlo bash -c.
Johannes