程式扎記: [GNU Make] 函式 : 使用者自訂函式

標籤

2015年11月24日 星期二

[GNU Make] 函式 : 使用者自訂函式

前言 : 
GNU make 支援內建函式以及使用者自訂函式. 函式調用 (function invocation) 看起來非常像變數參照 (variable), 不過前者包含了一個或多個被逗號隔開的參數. 大部分內建函式展開後多半會被賦值給一個變數或是傳遞給一個 subshell. 使用者自訂函式則儲存在變數或巨集中, 而且會接收呼叫者 (caller) 所傳來之一或多個參數. 

使用者自訂函式 : 
能夠將命令列儲存在變數裡, 讓我們得以在 makefile 中使用各種應用程式. 請參考下面例子 : 
  1. AWK := gawk  
  2. KILL := kill  
  3. kill_test:  
  4.     @$(call kill-acroread,root)  
  5.   
  6. #$(kill-acroread)  
  7. # filter out "username pid"  
  8. define kill-acroread  
  9.     ps aux | \  
  10.     $(AWK) -F" " '{print $$1,$$2}' | \  
  11.     grep $1  
  12. endef  
執行命令如下 : 
linux-tl0r:~/GnuMake/Ch04 # make kill_test
john 4584

在這個例子, 當使用者使用工作目標 kill_test, 則巨集 kill-acroread 則會被呼叫, 並傳入一個參數 "john". 而這個巨集的作用即是利用 ps 命令取出所有Process 訊息並透過 pipe 導給命令 gawk. 最後依據傳入參數來 grep 這些 Process. 這裡要特別提出來的是我們在 awk 命令稿中欄位參照會被依序寫成 $1$2 等等. 如果我們沒有為 awk 加上引號, 這些東西將被視為 make 變數. 我們可以透過以 "額外之錢號 '$' 規避 $n中的錢號 (也就是 $$n)", 然後將之縮減成一個錢號, 並將之傳給 subshell. 

你可以傳遞引數給變數與巨集, 這樣展開的結果就可以客製化, 巨集的參數在巨集的定義的主體可依序以 $1$2 等進行參照. 因此在這裡我們使用了一個參數參照 $1 來取代 grep 搜尋樣式. 最後請注意巨集參數 $1 與命令 gawk 欄位參數 $$1 之間的些微差異. 記住 "哪個程式是變數參照的接受者" 是一件重要的事. 

呼叫巨集 call : 
call 是一個內建於 make 的函式, call 會展開它的第一個引數, 以及把其餘引數依序置換到 $1$2.. 的地方. 而其語法如下定義 : 
$(call macro-name[, param1 ...])

macro-name 可以是任何巨集或是變數的名稱. 巨集或變數的值甚至不必包含任何的 $n 參照, 如果是這樣使用 call 幾乎就沒什麼意義. macro-name 之後是巨集的引數, 並以逗號為分隔符. 請注意 call 的第一個引數是一個非展開式的變數名稱, 但如果你為 call 的第一個引數加上一個錢號以及小括號, 該引數就會像變數一樣被展開, 而它的值會被傳遞給 call

call 的引數檢查機制非常簡單, 你可以為 call 指定任何數目的引數. 如果一個巨集參照了一個參數 $n, 但是調用它的 call 實例並未指定相應的引數, 那麼該變數就會變成空值. 如果 call實例所指定的引數比巨集的 $n 參照還多, 在巨集中並不會展開額外的引數. 如果你是從一個巨集來調用另一個巨集, 最好能夠知道 make 3.80 的一個奇怪特性. call 函式所定義的引數, 在展開動作期間, 會被視為一般的 make 變數. 如果一個巨集調用了另一個巨集, 被調用者(此為child)將可以在它的巨集展開期間看到調用者(此為 parent)的引數

請參考下面範例 : 
  1. define parent  
  2.         echo "parent has two parameters: $1 $2"  
  3.         $(call child,$1)  
  4. endef  
  5.   
  6. define child  
  7.         echo "child has one parameter: $1"  
  8.         echo "but child can also see parent's second parameter: $2"  
  9. endef  
  10.   
  11. scoping_issue:  
  12.         @$(call parent,one,two)  
執行結果如下 : 
linux-tl0r:~/GnuMake/Ch04 # make scoping_issue
parent has two parameters: one two
child has one parameter: one
but child can also see parent's second parameter:
 <如果在 make 3.80 則會出現 two>
這個問題已經在 make 3.81 版解決, 所以 $2 會被展開成空白值. 

補充說明 : 
GNU Make Doc 
[GNU Make] 變數與巨集 : 巨集 
[Linux命令] awk : 文字資料的進階處理

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!