一般來說,無論是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...