標籤:makefile
0.前言 從學習C語言開始就慢慢開始接觸makefile,查閱了很多的makefile的資料但總感覺沒有真正掌握makefile,如果自己動手寫一個makefile總覺得非常吃力。所以特意藉助部落格總結makefile的相關知識,通過例子說明makefile的具體用法。 例說makefile大致分為4個部分 1.只有單個C檔案 2.含有多個C檔案 3.需要包括標頭檔路徑 4.一個較為複雜的例子 【代碼倉庫】——makefile-example 代碼倉庫位於bitbucket,可藉助TortoiseHg(GUI工具)複製代碼或者在網頁中直接下載zip包。
1.複習gcc指令 一個非常簡單的C檔案——test.c 【test.c】
#include <stdio.h>int main(void){ int a = 3; int b = 2; printf("a=%d\n",a); printf("b=%d\n",b); return 0;}
【最簡單方法】 gcc test.c -o test 最終產生可執行檔test。 【執行test】 ./test 【輸出結果】 a=3 b=5 【不正確的寫法】 請注意以下寫法並不正確。 gcc -c test.c -o test
【詳細步驟分解】編譯——連結 無論gcc指令的參數如何變化,從源檔案變為可執行檔只需要兩步,第一步源檔案編譯為目標檔案,第二步從目標檔案連結為可執行檔。在最簡單的指令——gcc test.c -o test中使用了一處GCC的隱含規則,所有編譯和連結這兩個關鍵步驟展現的不明顯。那麼下面通過指令讓“不明顯”變得“明顯”。【1】由c檔案編譯為目標檔案 【寫法1】 gcc -c test.c -o test.o 【寫法2】——順序可以顛倒 gcc -o test.o -c test.c 【寫法3】——適當簡寫 可以適當簡寫,充分利用GCC的預設規則,*.o檔案由同名的*.c檔案編譯得到。 gcc -c test.c 【寫法4】——有點奇怪 還可以這樣寫,雖然看起來有點奇怪,但只執行結果卻是一樣的。makefile檔案似乎更喜歡這種方式。 gcc -c -o test.o test.c
【2】把目標檔案連結為可執行檔 【寫法1】 gcc test.o -o test 【寫法2】——順序可以顛倒 順序可以顛倒,makefile檔案似乎更喜歡這種方式。 gcc -o test test.o
2.編寫makefile檔案 【makefile】 請替換其中的[tab],並以代碼倉庫中的makefile檔案為主。
# 可執行檔TARGET = test# 依賴目標OBJS = test.o# 指令編譯器和選項CC=gccCFLAGS=-Wall -std=gnu99$(TARGET):$(OBJS)# @echo TARGET:[email protected]# @echo OBJECTS:$^ [tab]$(CC) -o [email protected] $^clean: [tab]rm -rf $(TARGET) $(OBJS)
【具體說明】 【1】TARGET=test test為最後可執行檔,linux中的可執行檔就是windows中的exe檔案 【2】OBJS = test.o test.o對應test.c,利用makefile的隱含規則,test.o由test.c編譯得到。 【3】CC=gcc 指定編譯器為gcc 【4】CFLAGS=-Wall -std=gnu99 使能所有警告,指定編譯器標準為gnu99 【5】 $(CC) -o [email protected] $^ [email protected]和$^為自動化變數,[email protected]指目標檔案,此處為可執行檔test,$^指去除重複的依賴檔案,此處為test.o $(CC) -o [email protected] $^ 最終變化為 gcc -o test test.o。gcc -o test test.o和【詳細步驟】連結部分的指令完全相同。那麼makefile和gcc指令便建立了聯絡。 可以通過@echo指令在makefile執行過程中列印自動化變數,通過這種方式調試makefile加速錯誤修正。
【編譯】 make clean && make 先執行make clean再執行make產生可執行檔
【控制台輸出】gcc -Wall -std=gnu99 -c -o test.o test.cgcc -o test test.o
【分析】 若去除-Wall -std=gnu99,那麼以上兩句簡化為gcc -c -o test.o test.c 和編譯過程方法【4】相同gcc -o test test.o 和執行過程方法【2】相同 那麼makefile和gcc指令便建立了關係,理解起來也方便多了。
3.再完善一些 【makefile】 請替換其中的[tab],並以代碼倉庫中的makefile檔案為主
# 可執行檔TARGET=test# C檔案SRCS = test.c# 目標檔案OBJS = $(SRCS:.c=.o)# 指令編譯器和選項CC=gccCFLAGS=-Wall -std=gnu99$(TARGET):$(OBJS)#@echo TARGET:[email protected]#@echo OBJECTS:$^ [tab]$(CC) -o [email protected] $^clean: [tab]rm -rf $(TARGET) $(OBJS)%.o:%.c [tab]$(CC) $(CFLAGS) -o [email protected] -c $<
【變化說明】 【1】OBJS = $(SRCS:.c=.o) 此處並沒有使用GCC的預設規則而重新制定了規則,為以後加入標頭檔尋找路徑做準備。 【2】$<為自動化變數,指第一個目標檔案,此處為test.c 替換變數和自動化變數之後: test.o:test.c [tab]gcc -Wall -std=gnu99 -o test.o -c test.c
4.總結 【1】gcc指令執行順序——先編譯目標檔案,後連結成可執行檔 【2】自動化變數 [email protected] 當前規則的目標檔案 $< 第一個依賴檔案 $^ 去除重複的所有依賴檔案