Proses substitusi di GNU Makefiles

11

Pada prompt bash, seseorang dapat mengeksekusi diff menggunakan file pseudo:

diff <(echo test) <(echo test)

Menambahkan ini apa adanya ke dalam Makefile gagal:

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

Kesalahan (petunjuk: / bin / sh menunjuk ke / bin / bash pada sistem ini):

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

Apa maksudnya, dan apakah ada cara untuk tetap membuat dua keluaran tanpa menggunakan file sementara?

Johannes
sumber

Jawaban:

20

/bin/shmungkin ada bashdi sistem Anda, tetapi ketika dipanggil sebagai sh, bashakan berjalan dalam mode POSIX (seolah-olah POSIXLY_CORRECTdidefinisikan, atau dimulai dengan --posix).

Dalam mode ini, proses substitusi tidak ada.

Solusi:

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

Alternatif:

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

Atau cukup definisikan variabel Makefile SHELLsebagai /bin/bash:

SHELL=/bin/bash

Jika Anda ingin mudah dibawa, lanjutkan dengan solusi pertama. Jika Anda baik-baik saja dengan ketergantungan bash, pilih yang kedua. Jika Anda juga tidak perlu peduli dengan makeimplementasi non-GNU , gunakan yang ketiga.


Mengenai pengaturan SHELL: Standar POSIX mengatakan bahwa executable di Makefiles harus dipanggil dengan fungsi system()C library oleh make. Fungsi ini tidak dijamin untuk menggunakan SHELLvariabel lingkungan (pada kenyataannya, hal itu tidak disarankan oleh standar). Standar ini juga mengatakan bahwa pengaturan variabel Makefile SHELLseharusnya tidak mempengaruhi variabel lingkungan SHELL . Namun, dalam sebagian besar implementasi makeyang saya ketahui, variabel Makefile SHELLakan digunakan untuk menjalankan perintah.

Saran dalam Dasar Pemikiran untuk makeutilitas adalah menggunakan bash -c:

Fitur historis MAKESHELL, dan fitur terkait yang disediakan oleh makeimplementasi lain , dihilangkan. Dalam beberapa implementasi itu digunakan untuk membiarkan pengguna menimpa shell untuk digunakan untuk menjalankan makeperintah. Ini membingungkan; untuk portable make, shell harus dipilih oleh makefile writer. Lebih jauh, seorang makefile writer tidak dapat membutuhkan shell pengganti untuk digunakan dan masih mempertimbangkan makefile portable. Meskipun dimungkinkan untuk membakukan suatu mekanisme untuk menentukan shell alternatif, implementasi yang ada tidak menyetujui mekanisme seperti itu, dan makefile penulis sudah dapat meminta shell alternatif dengan menentukan nama shell dalam aturan untuk target; sebagai contoh:

python -c "foo"

Kusalananda
sumber
Apakah ada cara untuk memanggil bashMakefile atau solusi lain untuk masalah diff tanpa menggunakan file sementara?
Johannes
Cukup gunakan dua file sementara, ini kurang lebih apa yang akan dilakukan metode substitusi proses di bawah tenda.
Kusalananda
3
Anda juga dapat mengatur SHELLke /bin/bashdalam Makefile.
Stephen Kitt
1
@Johannes Kusalananda menambahkan info ke jawabannya, yang sangat bagus karena menyajikan sejumlah opsi dan keadaan di mana mereka dapat digunakan. Saya lebih suka Anda menerima jawaban ini ... (Tapi saya menghargai sentimen!)
Stephen Kitt
2
Info yang menggunakan variabel SHELL tidak sesuai POSIX sangat membantu. Mungkin masih lebih baik digunakan bash -c.
Johannes