GNU Makefile 中的進程替換

GNU Makefile 中的進程替換

在 bash 提示字元下,可以使用偽檔案執行 diff:

diff <(echo test) <(echo test)

將其按原樣新增至 Makefile 中失敗:

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

錯誤(提示:/bin/sh 指向該系統上的/bin/bash):

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

這是什麼意思?

答案1

/bin/sh可能bash在您的系統上,但當作為 呼叫時shbash將以 POSIX 模式運行(就好像POSIXLY_CORRECT已定義,或以 啟動--posix)。

在此模式下,不存在進程替換。

解決方案:

  1. 使用明確臨時檔案:

    all:
        command1 >tmpfile
        command2 | diff tmpfile -
        rm -f tmpfile
    
  2. 使用bash -c內嵌腳本:

    all:
        bash -c 'diff <(command1) <(command2)'
    
  3. 將 Makefile 變數定義SHELL為(或系統上的/bin/bash任何路徑):bash

    SHELL=/bin/bash
    

如果您想要可移植性,請選擇第一個解決方案。如果您同意依賴bash,請選擇第二個。如果您另外不需要關心非 GNUmake實現,請使用第三種。


關於設定SHELL: POSIX 標準規定 Makefile 中的可執行檔應該system()由 C 函式庫函數呼叫make。該函數不保證使用SHELL環境變數(事實上,標準不鼓勵這樣做)。該標準還詳細說明設定 Makefile 變數SHELL不應影響環境變數 SHELL。然而,在我所知道的大多數實作中make,Makefile 變數SHELL將用於執行命令。

中的建議make該實用程式的基本原理是使用bash -c

歷史MAKESHELL特徵以及其他make實作提供的相關特徵被省略。在某些實作中,它用於讓使用者覆蓋用於運行make命令的 shell。這很令人困惑;對於便攜式make,shell 應由 makefile 編寫者選擇。此外,makefile 編寫者不能要求使用備用 shell 並仍然認為 makefile 是可移植的。雖然可以標準化指定備用 shell 的機制,但現有的實作並不同意這種機制,而且 makefile 編寫者已經可以透過在目標規則中指定 shell 名稱來呼叫備用 shell;例如:

python -c "foo"

相關內容