Substitution de processus dans les Makefiles GNU

11

Sur une invite bash, on peut exécuter diff en utilisant des pseudo-fichiers:

diff <(echo test) <(echo test)

L'ajout tel quel dans un Makefile échoue:

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

L'erreur (indice: / bin / sh pointe vers / bin / bash sur ce système):

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

Qu'est-ce que cela signifie et existe-t-il un moyen de toujours différencier deux sorties sans utiliser de fichiers temporaires?

Johannes
la source

Réponses:

20

/bin/shpeut être bashsur votre système, mais lorsqu'il est appelé as sh, bashil s'exécutera en mode POSIX (comme s'il POSIXLY_CORRECTétait défini ou démarré avec --posix).

Dans ce mode, les substitutions de processus n'existent pas.

Solutions:

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

Alternative:

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

Ou définissez simplement la variable Makefile SHELLcomme /bin/bash:

SHELL=/bin/bash

Si vous voulez la portabilité, optez pour la première solution. Si vous êtes d'accord avec une dépendance sur bash, choisissez la seconde. Si vous n'avez pas non plus besoin de vous soucier des makeimplémentations non GNU , utilisez la troisième.


Concernant le réglage SHELL: La norme POSIX dit que les exécutables dans Makefiles doivent être appelés avec la system()fonction de bibliothèque C par make. Cette fonction n'est pas garantie d'utiliser la SHELLvariable d'environnement (en fait, cela est déconseillé par la norme). La norme va également jusqu'à dire que la définition de la variable Makefile ne SHELLdevrait pas affecter la variable d'environnement SHELL . Dans la plupart des implémentations de ce makeque je connais, cependant, la variable Makefile SHELLsera utilisée pour exécuter les commandes.

La suggestion dans la justification de l' makeutilitaire est d'utiliser bash -c:

La MAKESHELLfonctionnalité historique et les fonctionnalités associées fournies par d'autres makeimplémentations ont été omises. Dans certaines implémentations, il est utilisé pour permettre à un utilisateur de remplacer le shell à utiliser pour exécuter des makecommandes. C'était déroutant; pour un portable make, le shell doit être choisi par l'auteur du makefile. De plus, un écrivain de makefile ne peut pas exiger qu'un autre shell soit utilisé et considère toujours le makefile portable. Bien qu'il soit possible de normaliser un mécanisme pour spécifier un autre shell, les implémentations existantes ne conviennent pas d'un tel mécanisme, et les rédacteurs de makefile peuvent déjà invoquer un autre shell en spécifiant le nom du shell dans la règle pour une cible; par exemple:

python -c "foo"

Kusalananda
la source
Existe-t-il un moyen d'invoquer bashdans le Makefile ou toute autre solution au problème de diff sans utiliser de fichiers temporaires?
Johannes
Il suffit d'utiliser deux fichiers temporaires, c'est plus ou moins ce que la méthode de substitution de processus ferait de toute façon.
Kusalananda
3
Vous pouvez également mettre SHELLà /bin/bashla Makefile.
Stephen Kitt
1
@Johannes Kusalananda's a ajouté l'info à sa réponse, ce qui est génial car elle présente un certain nombre d'options et les circonstances dans lesquelles elles peuvent être utilisées. Je préfère que vous acceptiez cette réponse ... (Mais j'apprécie le sentiment!)
Stephen Kitt
2
Les informations selon lesquelles l'utilisation de la variable SHELL n'est pas conforme à POSIX ont été très utiles. Peut-être vaut-il encore mieux l'utiliser bash -c.
Johannes