makefile必知必會(II)

makefile必知必會(II)


定義變量

makefile的變量定義有三種方式

1.        立即賦值 a:=b

2.        延遲賦值 a=b

3.        條件賦值 a?=b

4.        附加賦值 a+=b

它們之間的區別是,

第一種方式,會立即計算b的值,並賦值給a;

第二種方式,相當於C++和java的引用。如果後面b的值改變了,那麼a的值也會改變;

第三種方式,如果a沒有定義,則相當於a=b ,否則不執行任何操作;

第四種方式,將b的值添加到a原有的值後面,再賦值給a。

 

獲取變量值

$(var) //表示取變量var的值,記得當變量名多於一個字符時,使用”()”.

 

定義宏

define function

xxx // 具體的內容

endef

需要指出的是,雖然形式上類似函數,但是實際內容只是字符串替換,這與C中的宏函數是一樣的。

 

什麼時候計算變量

makefile的解析分爲兩個階段,第一階段生成規則和依賴關係,第二階段執行規則;

只有立即展開的變量會在第一階段計算,而延後展開的變量會在第二階段計算。

立即與延後展開的規則

表達式

何時擴展a

何時擴展b

a=b

立即

延後

a?=b

立即

延後

a:=b

立即

立即

a+=b

立即

取決於之間a的定義方式
如果是a:=,在立即
否則延後

define a
b …
endef

立即

延後

a : b
    c …

立即

立即
(命令中的變量,即變量c是延後展開)

 

 

eval

有兩個特點

1. 做兩次變量展開;以$(eval var),首先會對var做一次變量展開,然後對展開後的結果,再執行一次變量展開。詳細的描述請各位參考鏈接

2. $(eval var)返回爲空。這個特性被大量使用於宏定義define中。

  看下面這個例子:

define import_target

  include $(1)

  _PREFIXID := $(if$2, $2, TARGET)

  $(_ PREFIXID)

endef

按上面定義的宏,當去計算a:=$(call  import_target)時,幾乎總是會報錯。

原因是宏定義只是簡單的做字符串替換,一經替換後,原來看起來是一行語句,一下子就變成多行,從而導致makefile解析錯誤。

  於是只能使用“\”將各個語句連接爲一行。

define import_target

  include $(1) \

   _PREFIXID := $(if $2, $2,TARGET) \

  $(_ PREFIXID)

endef

  這樣做相當於

         include $(1) _PREFIXID := $(if $2, $2, TARGET)  $(_ PREFIXID)

  顯然,肯定還是報解析錯誤。

 最終解決方案,將各個子語句使用$(eval )包裹,

 define import_target

$(eval include $(1)) \

$(eval _PREFIXID := $(if $2,$2, TARGET)) \

$(_ PREFIXID)

endef 

解析時,makefile先對$(1)做展開,假設結果爲xxx,這是第一次;然後執行include xxx,這是第二次展開。執行完後,整個$(eval include $(1))表達式返回值爲空。這樣解析錯誤解決了,而且 import_target的返回結果又正好是_ PREFIXID的值。

 

call

格式:$(call func,param1, param2,..)

實現自定義函數調用。func使用define定義。 call會自動將param1的值賦值給func中的$1變量,將param2賦值給$2變量,依次類推。

小心空格

變量賦值a:=   b, 不會將b前面的空格賦值給a

大部分函數調用,特別是$(call func, param) 如果參數前面有空格,則會將空格連同參數一起傳入。因此要特別小心。

使用$(strip var)是個好習慣,可以避免不小心引入前置或者後置的空格導致的問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章