Linux學習筆記——例說makefile 單個C檔案

xukai871105發表於2014-07-02
0.前言
    從學習C語言開始就慢慢開始接觸makefile,查閱了很多的makefile的資料但總感覺沒有真正掌握makefile,如果自己動手寫一個makefile總覺得非常吃力。所以特意藉助部落格總結makefile的相關知識,通過例子說明makefile的具體用法。
    例說makefile分為以下幾個部分,更多內容請參考【例說makefile索引博文
    1.只有單個C檔案   
    2.含有多個C檔案    
    3.需要包括標頭檔案路徑
    4.增加巨集定義
    5.增加系統共享庫
    6.增加自定義共享庫
    7.一個實際的例子

    【程式碼倉庫】——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=gcc
CFLAGS=-Wall -std=gnu99

$(TARGET):$(OBJS)
# @echo TARGET:$@
# @echo OBJECTS:$^
 [tab]$(CC) -o $@ $^

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 $@ $^ 
            $@和$^為自動化變數,$@指目標檔案,此處為可執行檔案test,$^指去除重複的依賴檔案,此處為test.o
            $(CC) -o $@ $^ 最終變化為 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.c
gcc -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=gcc
CFLAGS=-Wall -std=gnu99

$(TARGET):$(OBJS)
#	@echo TARGET:$@
#	@echo OBJECTS:$^
 [tab]$(CC) -o $@ $^

clean:
 [tab]rm -rf $(TARGET) $(OBJS)

%.o:%.c
 [tab]$(CC) $(CFLAGS) -o $@ -c $<
    【變化說明】
    【1】OBJS = $(SRCS:.c=.o) 變數替換函式,把所有的*.c檔案替換為*.o檔案。該函式和
            OBJS = $(patsubst %.c,%.o,$(SRCS))具有相同效果。
    【2】$<為自動化變數,指第一個目標檔案,此處為test.c
            替換變數和自動化變數之後:
            test.o:test.c
            [tab]gcc -Wall -std=gnu99 -o test.o -c test.c

4.總結
    【1】gcc指令執行順序——先編譯目標檔案,後連結成可執行檔案
    【2】自動化變數
            $@ 當前規則的目標檔案
            $< 第一個依賴檔案
            $^ 去除重複的所有依賴檔案

  

相關文章