Podstawianie procesów w plikach GNU Makefiles


11

W wierszu poleceń bash można uruchomić diff przy użyciu pseudoplików:

diff <(echo test) <(echo test)

Dodanie tego, co jest w pliku Makefile, kończy się niepowodzeniem:

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

Błąd (wskazówka: / bin / sh wskazuje na / bin / bash w tym systemie):

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

Co to znaczy i czy istnieje sposób, aby nadal różnicować dwa wyjścia bez używania plików tymczasowych?

Odpowiedzi:


20

/bin/shmoże być bashw twoim systemie, ale gdy zostanie wywołany jako sh, bashbędzie działał w trybie POSIX (tak jakby POSIXLY_CORRECTzostał zdefiniowany lub został uruchomiony przy pomocy --posix).

W tym trybie podstawienia procesów nie istnieją.

Rozwiązania:

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

Alternatywny:

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

Lub po prostu zdefiniuj zmienną Makefile SHELLjako /bin/bash:

SHELL=/bin/bash

Jeśli chcesz mieć przenośność, skorzystaj z pierwszego rozwiązania. Jeśli wszystko jest w porządku z zależnością bash, wybierz drugą. Jeśli dodatkowo nie musisz przejmować się makeimplementacjami innymi niż GNU , użyj trzeciego.


Jeśli chodzi o ustawienia SHELL: Standard POSIX mówi, że pliki wykonywalne w Makefile powinien być wywołany z system()funkcją C bibliotekę make. Nie można zagwarantować, że funkcja ta będzie używać SHELLzmiennej środowiskowej (w rzeczywistości standard tego odradza). Norma również do pewnego stopnia mówi, że ustawienie zmiennej Makefile SHELLnie powinno wpływać na zmienną środowiskową SHELL . Jednak w większości znanych mi implementacji makezmienna Makefile SHELLbędzie używana do wykonywania poleceń.

Sugestia w Uzasadnieniem dla makenarzędzia ma zastosowania bash -c:

Funkcja historyczna MAKESHELLi funkcje powiązane z innymi makeimplementacjami zostały pominięte. W niektórych implementacjach umożliwia użytkownikowi przesłonięcie powłoki używanej do uruchamiania makepoleceń. To było mylące; w przypadku urządzenia przenośnego makepowłoka powinna zostać wybrana przez pisarza makefile. Ponadto program piszący makefile nie może wymagać użycia alternatywnej powłoki i nadal uważa, że ​​plik makefile jest przenośny. Chociaż możliwe byłoby ujednolicenie mechanizmu określania alternatywnej powłoki, istniejące implementacje nie zgadzają się na taki mechanizm, a twórcy plików makefile mogą już wywoływać alternatywną powłokę, podając nazwę powłoki w regule dla celu; na przykład:

python -c "foo"


Czy istnieje sposób na wywołanie bashw Makefile lub inne rozwiązanie problemu z różnicą bez użycia plików tymczasowych?
Johannes,

Wystarczy użyć dwóch plików tymczasowych, mniej więcej tak by to robiła metoda podstawiania procesów.
Kusalananda

3
Można również ustawić SHELL, aby /bin/bashw pliku Makefile.
Stephen Kitt,

1
@Johannes Kusalananda dodał informacje do swojej odpowiedzi, co jest świetne, ponieważ zawiera wiele opcji i okoliczności, w których można je wykorzystać. Wolałbym, żebyś zaakceptował tę odpowiedź ... (Ale doceniam sentyment!)
Stephen Kitt

2
Informacja, że ​​użycie zmiennej SHELL nie jest zgodne z POSIX, było bardzo pomocne. Może jeszcze lepiej jest użyć bash -c.
Johannes,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.