- 建置規則 : 該目標要如何完成?
- 檔案相依性 : 如果 xxx 更新的話, 代表我要跟著更新(或著是重新編譯)
就開始一步一步分析並從頭開始寫, 我們的目標是要建置 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 來建置程式的好處 :
- 節省打編譯指令的時間
- 建立相依性後, 可自動偵測是否需重建
只要你在建置時在 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
留言列表