介紹 Makefile 兩個基本功能:
  1. 建置規則 : 該目標要如何完成?
  2. 檔案相依性 : 如果 xxx 更新的話, 代表我要跟著更新(或著是重新編譯)
在這邊我們想要透過 Makefile 來建置程式
那要怎樣才能把剛才所作的事換成用 Makefile ?
就開始一步一步分析並從頭開始寫, 我們的目標是要建置 prog 這隻程式
打開一個 Makefile 並且打入
 
prog:

接著打入 make 他會跟你抱怨, 不知道怎麼建立 prog
 
make: Nothing to be done for `prog'.


所以這邊要開始進入 Makefile 第一個重要的功能了, 如何加入建置規則?
方式是在該目標下一行先敲一下 tab 然後開始寫指令
要注意, 一定要是 tab 而不能是空白

 
prog:
    gcc a.o b.o c.o -o prog


在這邊為了簡化還是先退回只有三個檔案
然後按下 make

gcc a.o b.o c.o -o prog

現在只打 4 個字就取代 23 個字了!
但目前其他三的檔案還是沒有建立規則, 大致受上一樣畫葫蘆
 

prog:
    gcc a.o b.o c.o -o prog

a.o:
    gcc a.c -o a.o -c

b.o:
    gcc b.c -o b.o -c

c.o:
    gcc c.c -o c.o -c


在按下 make 後你可能會發現, 他跟你說 prog 已經是最新版了

 
make: `prog' is up to date.


現在就來修改 a.c 檔案的內容後重新按 make

 
...
 
你會發現
 

他還是跟你說 prog 已經是最新版了

 
make: `prog' is up to date.
 

主要原因是我們沒有告訴 make 檔案相依性

他不知道什麼時候該重新建置目標

要加入檔案相依性只要在目標後面加入所相依的檔案名稱即可
 

prog: a.o b.o c.o 
    gcc a.o b.o c.o -o prog

a.o: a.c 
    gcc a.c -o a.o -c

b.o: b.c 
    gcc b.c -o b.o -c

c.o: c.c 
    gcc c.c -o c.o -c



加入完相依性後再按 make 他就會重新編譯 a.o 跟 prog 了!


gcc a.c -o a.o -c
gcc a.o b.o c.o -o prog

 
所以用 Makefile 有啥好處 ?

從上面的例子可以看出使用 Makefile 來建置程式的好處 :
  1. 節省打編譯指令的時間
  2. 建立相依性後, 可自動偵測是否需重建
其實在現代的多核心機器下還可以利用 Makefile 的內建功能來達到平行建置
只要你在建置時在 make 後面加入 -jn 其中 n 帶入數字,

例如
make -j4

代表一次平行執行四個任務, 也就是最多同時會編譯四個檔案!
這個功能則是一般手動編譯較難以達成的, 並且可以非常有效的節省編譯時間

 
Makefile 常見錯誤訊息

一般而言寫 Makefile 最容易看到下列的錯誤訊息
Makefile:2: *** missing separator.  Stop.


但看到後請不要慌張, 這個訊息通常是你的建置規則前面沒有用 tab 所造成的

尋著他後面提示的行號去檢查很快就可以解決
 

 

一堆 .o 一堆 rule

當使用 Makefile 一段時間後, 大致上會碰到的問題就是如果你有一堆 .c 要編譯成 .o 檔的話
手刻一堆 xxx.c -> xxx.o 的 rule 會讓人挺困擾的, 尤其是通常都是 gcc xxx.c -c -o xxx.o 之類的
但如果你是個懶惰牌的好 Programmer 那麼你可能會嘗試寫一些萬用字元的 rule

於是你寫下了以下的 rule

*.o: *.c
 gcc -o *.o  -c *.c

嗚呼! Let's Make
然後你會發現如果有兩個 .c 以上的話就會發現:「幹!不能動」

gcc -o *.o  -c *.c
gcc: fatal error: cannot specify -o with -c, -S or -E with multiple files
compilation terminated.
make: *** [*.o] Error 4

錯誤訊息跟我們抱怨如果指定 -o 加上 -c, -S 或 -E 的話就不能輸入多個檔案
現在假設你還沒有任何的 .o 擋在該資料夾並且有 a.c b.c 要編譯
shell 真實看到的指令變成這樣

gcc -o  -c a.c b.c

然後就引發剛才的錯誤了XD


救命 難道只能寫一堆 rule 了嗎?

萬用字元不能動的主要原因在於 Makefile 為了避免與 shell 使用的萬用字元 * 衝突而選擇了另一個

並且 *.c 跟 *.o 的 * 的部份哪知道會不會一樣, 所以 Makefile 有自己的萬用字元系統

*.o: *.c
 gcc -o *.o  -c *.c

所以在 Makefile 中是使用 % 作為萬用字元, 因此第一直覺會下出類似下面的建置規則

%.o: %.c
 gcc -o %.o  -c %.c

敲入 Make 後發現建置規則是有抓到了, 但是建置指令並沒有將 % 替換程式適當的字串

gcc -o %.o  -c %.c
gcc: error: %.c: No such file or directory
gcc: fatal error: no input files
compilation terminated.
make: *** [a.o] Error 4

主要原因在於建置規則中不是用 % 來表達該萬用字元是用 $@ 及 $^
(當然還有一堆其它 $ 開頭的神奇變數, 不過常用的大概就這些)


Makefile 萬用字元使用方式 %, $@, $^


$@, $^這幾個符號各代表不同意義, 但直接先看範例再來解說吧
 

%.o: %.c
 gcc -o $@  -c $^

其中 $@ 代表建置目標, 所以以要建置 a.o 來看的話 $@ 等於 a.o
接著 $^ 則代表相依目標, 建置 a.o 時會替換成 a.c

從此之後就只要寫一個 .c -> .o 的建置規則在加上一個 link 成執行檔的規則即可!



這些萬用規則也可以拿來作一些方便的應用, 例如有時候你會將 debug 版本跟一般版跟分開放置
則你寫兩個 rule 則可以建置出不同編譯參數且在不同資料夾生成

debug/%.o: %.c
 gcc -o $@  -c $^ -g

release/%.o: %.c
 gcc -o $@  -c $^ -O2

 

 

 

 

https://kitoslab.blogspot.tw/2011/12/makefile.html

    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()