GNU Make 相容的 Makefile 教學:無經驗的 Makefile

PUBLISHED ON MAY 27, 2018 — BUILD AUTOMATION

    我們這裡展示一個初階的 (naive) Makefile,本例摘自筆者先前練資料結構的微型程式。在這裡,我們刻意地不用 Makefile 本身的語法,讓整個 Makefile 看起來更單純:

    all: dynamic
    
    dynamic:
    	gcc -fPIC -c deque_int.c
    	gcc -shared -o libalgodequei.so deque_int.o
    
    static: deque_int.o
    	ar rcs -o libalgodequei.a deque_int.o
    
    test: test_deque_int.out
    	./test_deque_int.out
    	echo $$?
    
    test_deque_int.out: deque_int.o test_deque_int.o
    	gcc -o test_deque_int.out test_deque_int.o deque_int.o
    
    test_deque_int.o:
    	gcc -c test_deque_int.c
    
    deque_int.o:
    	gcc -c deque_int.c
    
    clean:
    	rm -f test_deque_int.out *.o *.so *.a
    
    

    本專案的使用方式如下:

    • makemake dynamic:製作動態函式庫
    • make static:製作靜態函式庫
    • make test:執行測試程式
    • make clean:清除由編譯器生成的檔案

    預設的任務是 *all*,而 all 相依於 *dynamic*,故我們不加入任何參數時,預設動作為製作動態函式庫。節錄程式碼如下:

    all: dynamic
    
    dynamic:
    	gcc -fPIC -c -o deque_int.o deque_int.c
    	gcc -shared -o libalgodequei.so deque_int.o
    

    製作靜態函式庫的任務為 *static*,而 static 相依於 *deque_int.o*。節錄程式碼如下:

    static: deque_int.o
    	ar rcs -o libalgodequei.a deque_int.o
    
    deque_int.o:
    	gcc -c deque_int.c
    

    使用檔案做為任務名稱的好處在於,當我們第二次執行相關的任務時,make 會略過該任務。這樣的設計是由於早期的電腦運行速度較慢,編譯中大型程式往往需花數十分鐘至數小時,若能略去不必要的任務,就可以省下一些編譯程式的時間。

    執行測試程式的任務為 *test*,該任務有兩層的相依性。節錄程式碼如下:

    test: test_deque_int.out
    	./test_deque_int.out
    	echo $$?
    
    test_deque_int.out: deque_int.o test_deque_int.o
    	gcc -o test_deque_int.out test_deque_int.o deque_int.o
    
    test_deque_int.o:
    	gcc -c test_deque_int.c
    
    deque_int.o:
    	gcc -c deque_int.c
    

    看起來比先前的任務略長,但其實只是以 GCC 依序編譯 C 程式碼,如果讀者從任務相依性的源頭追蹤,就知道這段程式碼所代表的意義。(可由下向上閱讀此段程式碼。)

    此處唯一比較有點小技巧的地方在於 echo $$?。在類 Unix 系統中,$? 是一個內建環境變數,表示最後一個程式執行後所回傳的錯誤碼,若為 0 表示程式沒有錯誤,若為其他數字表示程式有某種錯誤。echo $? 表示印出上一個程式的錯誤碼;由於在 Makefile 中,$ (錢字號) 有特殊意義,所以要用 $$ 表示該符號為一個 $ 字串而非 Makefile 的特殊符號。

    清理檔案的任務為 *clean*,讀者應該很容易就知道其意義:

    clean:
    	rm -f test_deque_int.out *.o *.so *.a
    

    一般在網路上看到的 Makefile 都充滿著各種難以理解的符號和規則,越強的高手寫的 Makefile 往往越難理解。但即使我們不用特殊的 Makefile 語法,仍然可以寫出可用的 Makefile。

    現在的軟體專案幾乎都有上版本控制系統,寫 Makefile 時並不需要追求一步到位。即使一開始寫的 Makefile 沒那麼漂亮,只要能夠正確運作,之後再將 Makefile 的語法慢慢修改即可。Makefile 畢竟是軟體專案的設定檔而非文藝作品,最重要的是能夠正確地編譯專案,而不用過度追求語法上的美感或技巧。