2013年1月8日 星期二

快快樂樂 Makefile 入門教學 Part.II 泛用規則/萬用字元應用

這邊文章主要是 快快樂樂 Makefile 入門教學 的續集, 主要針對的對象依然初學者

要談的主題則是在 Makefile 中萬用字元跟泛用規則的應用, 可以讓整個 Makefile 盡量變得簡潔有力

並且一窺 Makefile 的內部推導邏輯

一堆 .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


小結

Makefile 會了萬用字元後, 建置規則就可以寫的簡潔又好看

在加上 .c/.cpp 與 .h/.hpp 相依性自動建立就很完整了

預計會在弄一篇文章寫產生 .c/.cpp 與 .h/.hpp 相依性的:P

沒有留言:

張貼留言