美思 [GNU Make] Makefile 教學:即使是新手也可以馬上開始寫 Makefile

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

我們這裡展示一個初階的 (naive) Makefile,本例摘自筆者先前練資料結構的微型程式。在這裡,我們刻意地少用 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 是用 Autotools 或 CMake 自動生成的,而自動生成的 Makefile 往往很冗長而難以閱讀。但即使我們不用特殊的 Makefile 語法,仍然可以寫出可用的 Makefile。

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

關於作者

身為資訊領域碩士,美思認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

美思喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,美思將所學寫成文章,放在這個網站上和大家分享。