Substituição de processo nos Makefiles GNU

11

Em um prompt do bash, é possível executar diff usando pseudo arquivos:

diff <(echo test) <(echo test)

Adicionar isso como está em um Makefile falha:

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

O erro (dica: / bin / sh aponta para / bin / bash neste sistema):

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

O que significa e ainda existe uma maneira de diferenciar duas saídas sem usar arquivos temporários?

Johannes
fonte

Respostas:

20

/bin/shpode estar bashem seu sistema, mas, quando chamado como sh, bashestará em execução no modo POSIX (como se tivesse POSIXLY_CORRECTsido definido ou iniciado --posix).

Nesse modo, as substituições de processo não existem.

Soluções:

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

Alternativa:

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

Ou apenas defina a variável Makefile SHELLcomo /bin/bash:

SHELL=/bin/bash

Se você deseja portabilidade, escolha a primeira solução. Se você estiver bem com uma dependência bash, escolha a segunda. Se você não precisar se preocupar com makeimplementações que não sejam GNU , use a terceira.


Em relação à configuração SHELL: O padrão POSIX diz que os executáveis ​​em Makefiles devem ser chamados com a system()função de biblioteca C por make. Não é garantido que esta função use a SHELLvariável de ambiente (de fato, isso é desencorajado pelo padrão). O padrão também é extensivo ao dizer que a configuração da variável Makefile SHELLnão deve afetar a variável de ambiente SHELL . Entretanto, na maioria das implementações makeque eu conheço, a variável Makefile SHELLserá usada para executar os comandos.

A sugestão na justificativa para a makeutilidade é usar bash -c:

O MAKESHELLrecurso histórico e os recursos relacionados fornecidos por outras makeimplementações foram omitidos. Em algumas implementações, é usado para permitir que um usuário substitua o shell a ser usado para executar makecomandos. Isso foi confuso; para um portátil make, o shell deve ser escolhido pelo escritor do makefile. Além disso, um gravador de makefile não pode exigir que um shell alternativo seja usado e ainda considera o makefile portátil. Embora seja possível padronizar um mecanismo para especificar um shell alternativo, as implementações existentes não concordam com esse mecanismo, e os gravadores de makefile já podem chamar um shell alternativo especificando o nome do shell na regra de um destino; por exemplo:

python -c "foo"

Kusalananda
fonte
Existe uma maneira de chamar bashno Makefile ou qualquer outra solução para o problema diff sem usar arquivos temporários?
7777 Johannes
Basta usar dois arquivos temporários, isto é mais ou menos o que o método de substituição de processo faria sob o capô de qualquer maneira.
Kusalananda
3
Você também pode definir SHELLa /bin/bashno Makefile.
Stephen Kitt
1
@Johannes Kusalananda adicionou a informação à sua resposta, o que é ótimo, pois apresenta várias opções e as circunstâncias em que elas podem ser usadas. Eu prefiro que você aceitar essa resposta ... (Mas eu aprecio o sentimento!)
Stephen Kitt
2
A informação de que o uso da variável SHELL não é compatível com POSIX foi muito útil. Talvez ainda seja melhor usar bash -c.
Johannes