Prozessersetzung in GNU-Makefiles

11

An einer Bash-Eingabeaufforderung kann diff mithilfe von Pseudodateien ausgeführt werden:

diff <(echo test) <(echo test)

Das Hinzufügen wie es ist zu einem Makefile schlägt fehl:

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

Der Fehler (Hinweis: / bin / sh zeigt auf / bin / bash auf diesem System):

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

Was bedeutet das und gibt es eine Möglichkeit, zwei Ausgaben ohne Verwendung temporärer Dateien zu unterscheiden?

Johannes
quelle

Antworten:

20

/bin/shkann bashauf Ihrem System, aber wenn sie als aufgerufen sh, bashwird in POSIX - Modus ausgeführt werden (als ob POSIXLY_CORRECTdefiniert wurde, oder es wurde begonnen mit --posix).

In diesem Modus sind keine Prozessersetzungen vorhanden.

Lösungen:

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

Alternative:

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

Oder definieren Sie einfach den Makefile - Variable SHELLwie /bin/bash:

SHELL=/bin/bash

Wenn Sie Portabilität wünschen, wählen Sie die erste Lösung. Wenn Sie mit einer Abhängigkeit von basheinverstanden sind, wählen Sie die zweite aus. Wenn Sie sich zusätzlich nicht um Nicht-GNU- makeImplementierungen kümmern müssen , verwenden Sie die dritte.


In Bezug auf die Einstellung SHELL: Der POSIX-Standard besagt, dass ausführbare Dateien in Makefiles mit der system()C-Bibliotheksfunktion von aufgerufen werden sollten make. Es wird nicht garantiert, dass diese Funktion die SHELLUmgebungsvariable verwendet (dies wird vom Standard sogar nicht empfohlen). Der Standard geht auch auf eine gewisse Länge ein, um zu sagen, dass das Festlegen der Makefile-Variablen SHELLkeine Auswirkungen auf die Umgebungsvariable haben sollte SHELL . In den meisten makemir bekannten Implementierungen wird jedoch die Makefile-Variable SHELLverwendet, um die Befehle auszuführen.

Der Vorschlag in der Begründung für das makeDienstprogramm lautet bash -c:

Das historische MAKESHELLMerkmal und verwandte Merkmale, die von anderen makeImplementierungen bereitgestellt wurden , wurden weggelassen. In einigen Implementierungen wird es verwendet, damit ein Benutzer die Shell überschreibt, die zum Ausführen von makeBefehlen verwendet werden soll. Das war verwirrend; Für ein tragbares makeGerät sollte die Shell vom Makefile-Writer ausgewählt werden. Ferner kann ein Makefile-Writer nicht die Verwendung einer alternativen Shell erfordern und das Makefile dennoch als portabel betrachten. Während es möglich wäre, einen Mechanismus zum Angeben einer alternativen Shell zu standardisieren, stimmen vorhandene Implementierungen einem solchen Mechanismus nicht zu, und Makefile-Writer können bereits eine alternative Shell aufrufen, indem sie den Shell-Namen in der Regel für ein Ziel angeben. zum Beispiel:

python -c "foo"

Kusalananda
quelle
Gibt es eine Möglichkeit, bashdas Makefile oder eine andere Lösung für das Diff-Problem aufzurufen, ohne temporäre Dateien zu verwenden?
Johannes
Verwenden Sie einfach zwei temporäre Dateien. Dies ist mehr oder weniger das, was die Prozessersetzungsmethode ohnehin unter der Haube tun würde.
Kusalananda
3
Sie können auch festlegen , SHELLum /bin/bashin der Datei Makefile.
Stephen Kitt
1
@Johannes Kusalananda hat die Informationen zu seiner Antwort hinzugefügt, was großartig ist, da es eine Reihe von Optionen und die Umstände bietet, unter denen sie verwendet werden können. Ich möchte lieber, dass Sie diese Antwort akzeptieren ... (Aber ich schätze das Gefühl!)
Stephen Kitt
2
Die Information, dass die Verwendung der SHELL-Variablen nicht POSIX-konform ist, war sehr hilfreich. Vielleicht ist es noch besser zu benutzen bash -c.
Johannes