Makefile學習記錄(一)

在項目開放中使用makefile編譯項目,在學習使用過程中出現了一些問題,這裏做一些記錄備份,已提供後面回顧


1makefile的函數理解

函數定義方法

define func_name

some_operation

endef

 

實際上makefile本質上是一種多行變量:

如:

define func_name

var := $1

endef

 

value :=$(call func_name,param1,……)

 

value的最後結果是

value = var:=param1

 

爲了驗證一下,編寫簡單的makefile測試一下:

然後make一下,結果如下:


可以看出value的值實際上就是test的展開式,那麼我們在test函數中添加多行操作看看會有什麼變化,修改後如下:


添加var1 = 123,然後執行make,會有報錯:

這是爲什麼呢,其實只要將test展開就知道了:

value = var := 123

     var1:= 123

 

target執行時就是這樣的:

target:

         echo var:=123

   var1:= 123

 

因爲在var1之前有tab空格所以var1被當做了make的指令執行,單實際上make沒有這個執行,所以報錯爲var1 命令沒有找到,由此可以看出定義函數是這一點要尤爲重視,否者函數的引用很容易出現問題。

 

 

2. eval函數的理解

make GNU對該函數做了細緻的描述:

簡單翻譯一下:

函數「eval」是一個比較特殊的函數。使用它可以在Makefile中構造一個可變的規則結構關係(依賴關係鏈),其中可以使用其它變量和函數。函數「eval」對它的參數進行展開,展開的結果作爲Makefile的一部分,make可以對展開內容進行語法解析。展開的結果可以包含一個新變量、目標、隱含規則或者是明確規則等。也就是說此函數的功能主要是:根據其參數的關係、結構,對它們進行替換展開。

函數「eval」的返回值時空

尤爲重要的是 eval」函數執行時會對它的參數進行兩次展開。:「eval」函數執行時會對它的參數進行兩次展開。第一次展開過程發是由函數本身完成的,第二次是函數展開後的結果被作爲Makefile內容時由make解析時展開的。明確這一過程對於使用「eval」函數非常重要。理解了函數「eval」二次展開的過程後。實際使用時,如果在函數的展開結果中存在引用(格式爲:$(x)),那麼在函數的參數中應該使用「$$」來代替「$」。因爲這一點,所以通常它的參數中會使用函數「value」來取一個變量的文本值

簡單點來說就是$(eval  text)會將text展開當做makefile的一部分,被make執行,所以text會被展開二次,第一次是eval展開,第二次則是作爲被make執行進行的展開。還有一點需要特別注意eval的返回值是空,所以不能出現諸如:value := $(eval text)這類使用,value只能爲空

 

說了這麼多還是用實例測試一下:

定義一個函數,目的是獲取本地目錄,如上,執行make

可以看出value的值,但是$(local_dir)這個變量的值時空,爲什麼會這樣,實際上我們將函數展開就理解了:

value := local_dir := /home/jimmy/workspace/my_study/test

target:

         @echolocal_dir:

看出來沒有,makefile中沒有定義local_dir這個變量。但是這個和eval有什麼關係,不要緊我們來修改一下:


 

然後make一下:


可以看出value的值時空,因爲eval的返回值是空,而local_dir這個變量這時候被定義了,而且還被賦值了。到這讀者是否看出來了eval的作用。

         實際上就是eval展開了eval_test這個函數,並將其作爲makefile的一部分送給make執行了一下,這樣local_dir就被定義了;這個和call函數有明顯的區別,call僅僅是將函數按照多行變量展開了,並不會送給make去執行;

 

猜測:

不過在上述例子中有個奇怪的點就是$(shell pwd)按照手冊需要添加$$但是沒有添加其結果好像也沒有影響,那麼修改一下如何:


再次make


 

還是沒有影響,這是爲什麼,我猜猜是和$(shell pwd)的展開時間有關,在$(call eval_test)時就已經執行,這時候函數展開爲local_dir := $/home/jimmy/workspace/mystudy/test,然後evallocal_dir :=$/home/jimmy/workspace/mystudy/test送給make作爲makefie一部分執行。那爲什麼在輸出是$這個符號不見了,測試一下。


執行make


可以看出Value2的輸出爲空,那麼是否單個$會被忽略呢?

 

那麼我們再添加一個試試呢:


輸出錯誤:


這個真是很奇怪原因是什麼呢!我們可以來展開一下。

第一次是call函數展開:

local_dir := $$$/home/jimmy/workspace/mystudy/test

然後eval展開:

local_dir :=$$ /home/jimmy/workspace/mystudy/test

 

然後執行

local_dir :=$$/home/jimmy/WorkSpace/my_study/test

echo時:把$$/home/jimmy/WorkSpace/my_study/test作爲一個shell變量,然後會發現shell中不存在該變量,然後報錯??

以上還有很多疑問,後續學習補充

 

 

3makefile的一些注意點

Makefile中所有以$打頭的單詞都會被解釋成Makefile中的變量。如果你需要調用shell中的變量(或者正則表達式中錨定句位$),都需要加兩個$符號($$)。實例如下:

PATH="/home/jimmy"

all:

   echo ${PATH}

   echo $$PATH

例子中的第一個${PATH}引用的是Makefile中的變量,而不是shell中的PATH環境變量,後者引用的事Shell中的PATH環境變量。

 

在目標文件冒號後在起一行,並且有tab空格則作爲shell執行

target:

         value= $(value2)   shell執行

 

targetvalue = $(value2)   作爲makefile 的代碼

 

target

value = $(value2)   作爲makefile 的代碼

 

Makefile中的shell,每一行是一個進程,不同行之間變量值不能傳遞。所以,Makefile中的shell不管多長也要寫在一行。