程式扎記: [GNU Make] 命令 : 空命令 & 命令環境

標籤

2015年12月27日 星期日

[GNU Make] 命令 : 空命令 & 命令環境

空命令 
空命令 (empty command) 就是一個什麼事都不做的命令. 例如: 
先前有提到工作目標的必要條件可以跟著一個分號和命令. 此處分號之後空無一物, 這表示命令不存在. 當然你也可以在工作目標後指定只包含一個 Tab 的空白列, 不過這樣做不利於閱讀與維護. 空命令最常用來避免一個樣式規則來比對特定工作目標, 進而執行你不想要的命令. 請注意的是, 在 make 其它的版本中, 空工作目標 (empty target) 有時候會被當作假工作目標 (phony target) 來用. 在 GNU make 中, 你可以使用 .PHONY 這個特殊工作目標: 
A phony target is one that is not really the name of a file; rather it is just a name for a recipe to be executed when you make an explicit request. There are two reasons to use a phony target: to avoid a conflict with a file of the same name, and to improve performance.

來避免將工作目標視為檔案, 而造成不預期的執行結果. 

命令環境 
make 執行命令時會從 make 本身繼承其處理環境. 此環境包括當前的工作目標, 檔案描述符以及傳遞自 make 的環境變數. 當一個 subshell 被建立時, make 會將若干變數加入環境: 
* MAKEFLAGS
* MFLAGS
* MAKELEVEL

MAKEFLAGS 變數包含了你傳遞給 make 的命令列選項; MFLAGS 變數的內容是 MAKEFLAGS 的鏡射版本, 存在的理由是為了舊版的相容性; MAKELEVEL 變數的內容代表 make 巢狀調用的次數. 也就是說當 make 遞迴調用 make 時, MAKELEVEL 變數的值就會加一. 對 make 而言, 具單一父程式的子程式將會具有一個同一值的 MAKELEVEL 變數. 這些變數通常會被用來管理遞迴建造 (recursive make). 

當然使用者可以透過 export 指令 將任何變數加入子城市的環境之中. 

make 用來執行命令的當前工作目錄就是上層 make 的工作目錄. 這個目錄通常就是你用來執行 make 程式的目錄, 不過你可以透過 --directory ( -C) 參數加以變更: 
  1. -C DIRECTORY, --directory=DIRECTORY  
  2.                             Change to DIRECTORY before doing anything.  
請注意! 僅使用 --file 來指定不同的 makefile 並無法變更當前目錄, 這只會影響所讀取的 makefile: 
  1. -f FILE, --file=FILE, --makefile=FILE  
  2.                             Read FILE as a makefile.  
make 所衍生 (spawn) 的每個子行程都會繼成三個標準的擋案描述符: stdin, stdout 和 stderr. 這並沒有任何值得特別注意的地方, 除了命令稿可以讀取它的 stdin 這件事. 這是合理且可行的. 一旦命令稿完成它的剖析動作後, 接下來命令便會如剖析結果被執行. 不過使用者一般不會透過這種互動方式來執行 makefile. 使用者通常會希望這麼做: 
- 啟動 make
- "走完" 每個步驟
- 傳回稍後要檢查的結果.

當然能夠讀取 stdin 將有助於與 "cron 為基礎的自動建奏程序" 的互動. 而 makefile 中常見的一個錯誤就是意外的讀取了 stdin: 
  1. $(DATA_FILE): $(RAW_DATA)  
  2.     grep pattern $(RAW_DATA_FILES) > $@  
此處當我們以變數來作為 grep 命令 指定輸入檔的時候, 如果誤用了變數名稱導致展開來後空無一物, grep 命令 將會讀取自 stdin! 但這不會顯示提式符或指示為何 make "掛掉了". 這個問題的一個簡單解決方案就是總在命令列上使用 /dev/null 以作為額外的 "檔案": 
  1. $(DATA_FILE): $(RAW_DATA)  
  2.     grep pattern $(RAW_DATA_FILES) /dev/null > $@  
現在這個 grep 命令 一定不會去讀取 stdin!

沒有留言:

張貼留言

網誌存檔