一起玩轉Makefile

2021-09-28 15:14:59 字數 3386 閱讀 9871

一般來說,無論是c或者c++工程,首先要把原始檔編譯成中間**檔案,在windows下也就是 .obj 檔案,unix下是 .o 檔案,即 object file,這個動作叫做編譯(compile)。然後再把大量的object file、resource和依賴的庫檔案合成執行檔案,這個動作叫作鏈結(link)。   

先定義三個檔案: hellomake.c, hellofunc.c, and hellomake.h

hellomake.c

hellofunc.c

hellomake.h

#include

int main()

#include

#include

void myprinthellomake(void)

/*example include file

*/void myprinthellomake(void);

通過如下命令來編譯上面的三個檔案:

gcc -o hellomake hellomake.c hellofunc.c -i.
上面的命令會編譯hellomake.c和hellofunc.c 2個檔案,然後鏈結生成乙個hellomake的可執行檔案。

"-i." 代表gcc 在當前目錄下開始搜尋標頭檔案。如果不使用makefile, 每次修改、更新或新增檔案,我們要反覆執行上面的命令進行重新編譯和鏈結。

最簡單的乙個makefile 就是把編譯命令儲存一下,每次直接執行make命令就可以完成編譯和鏈結

makefile 1

hellomake: hellomake.c hellofunc.c

gcc -o hellomake hellomake.c hellofunc.c -i.

makefile版本1 指明了一條編譯規則,":"左邊指明了規則的目標物件,右邊指明了依賴的相關原始檔,如果右邊的相關檔案有改動,這個規則在執行make時就會被觸發執行。第二行開始空乙個tab空格,gcc執行編譯和鏈結命令。

版本1是只包含一條規則的編譯指令,而一般的專案工程會有多條編譯命令,開發迭代的過程中需要修改相關的編譯工具或標頭檔案路徑,我們就要會去修改每條具體的規則,為了更高效一點,我們可以把公用的工具和路徑以macro的形式先宣告後使用。具體d的優化方案參考版本2:

makefile 2

cc=gcc

cflags=-i.

hellomake: hellomake.o hellofunc.o

$(cc) -o hellomake hellomake.o hellofunc.o $(cflags)

版本2定義幾個macro:cc和cflags。它告訴我們如何在構建和編譯的過程中使用這些巨集。cc是c編譯器要使用的命令,cflags指明了編譯要搜尋的標頭檔案路徑。版本2已經可以解決很多小型專案的編譯的流程,但是還有個問題就是如果我們修改了.**件,而makefile又沒有定義相關的依賴規則,對應的.c檔案沒有變動所以不會重新編譯,這是個很常見的問題。

為了修復這個問題,我們需要為.h 和.c增加額外的依賴規則。當.h 和 .c 檔案變化時,我們執行make要觸發編譯。版本3新增了一條規則去修復這個問題。

makefile 3

cc=gcc

cflags=-i.

deps = hellomake.h

%.o: %.c $(deps)

$(cc) -c -o $@ $< $(cflags)

hellomake: hellomake.o hellofunc.o

$(cc) -o hellomake hellomake.o hellofunc.o

版本3新增了乙個macro deps, 這個巨集定義了所有標頭檔案的集合,這樣做的好處是:某些標頭檔案可能被很多.c檔案包含,如果不提取出來,新增乙個.h 就必須得修改相應的依賴規則,這是很不友好的。正如本文開始所描述的編譯過程,編譯會先生成乙個.o檔案,我們可以針對.o定義乙個依賴規則,"%" 萬用字元代表所有中間編譯生成的目標物件,這些物件依賴.c 檔案和相應的乙個或多個標頭檔案,一旦這些檔案中的某些檔案發生變化時,這條編譯規則會被觸發。"-c" 代表我們要生成.o目標檔案, "-o $@" 代表 編譯規則中":"左邊的所有物件, "$<" 代表使用依賴列表的第一項規則。

作為乙個通用標準,hellomake依賴的.o也可能在其他的目標鏈結檔案中引入,所以這條規則我們可以提取出來,使用macro通配,如版本4: $@ 和 $^ 代表最終鏈結hellomake規則的":"左右兩邊的內容:

makefile 4

cc=gcc

cflags=-i.

deps = hellomake.h

obj = hellomake.o hellofunc.o

%.o: %.c $(deps)

$(cc) -c -o $@ $< $(cflags)

hellomake: $(obj)

$(cc) -o $@ $^ $(cflags)

一般的工程專案會把頭檔案.h、原始檔.c、庫檔案以及source分開放在不同的目錄裡面,同時編譯生成的中間.o的結果檔案希望隔離儲存,鏈結完成之後在bin檔案儲存可執行目標檔案, 其它.o及中間結果可以刪除。我們需要增加額外的macro,只要執行make clean 就可以刪除相應的中間檔案,此處為了避免和可能存在的clean目標或檔案衝突,我們引入偽目標.phony, 它可以儲存以clean為目標的檔案,避免覆蓋。

makefile 5

idir =../include

cc=gcc

cflags=-i$(idir)

odir=obj

ldir =../lib

libs=-lm

_deps = hellomake.h

deps = $(patsubst %,$(idir)/%,$(_deps))

_obj = hellomake.o hellofunc.o

obj = $(patsubst %,$(odir)/%,$(_obj))

$(odir)/%.o: %.c $(deps)

$(cc) -c -o $@ $< $(cflags)

hellomake: $(obj)

$(cc) -o $@ $^ $(cflags) $(libs)

.phony: clean

clean:

rm -f $(odir)/*.o *~ core $(incdir)/*~

經過不斷的改造,版本5開起來是個非常規範的makefile檔案,它定義模板規則已經依賴的編譯規則,抽取公用的macro來適配所以的規則,這樣可以更方便的增加規則到makefile檔案裡面去。

跟我一起來玩轉Makefile 一)

乙個c工程 o主程式模組 100個c檔案 liba.a 功能模組a 1000個c檔案和100 個 件 libb.a功能模組b make和makefile的存在正是為了解決上述兩個問題 1.makefile檔案幫助我們記錄了整個專案工程的所需編譯的檔案列表,這樣我們在編譯時僅需輸入簡單的make命令就...

一起學Makefile(一)

make和makefile makefile檔案幫助我們記錄了整個專案工程的所有需要編譯的檔案列表,這樣我們在編譯時僅需要輸入簡單的make命令就能編譯出我們期望的結果。makefile檔案反映了整個專案中各個模組的依賴關係,這樣我們改動了某些原始檔以後,僅需簡單的輸入make命令,make工具就會...

跟我一起寫 Makefile

概述 什麼是makefile?或許很多winodws的程式設計師都不知道這個東西,因為那些windows的ide都為你做了這個工作,但我覺得要作乙個好的和professional的程式設計師,makefile還是要懂。這就好像現在有這麼多的html的編輯器,但如果你想成為乙個專業人士,你還是要了解h...