轉載於 : http://www.cnblogs.com/lidabo/p/4521123.html
一 makefile的作用 Makefile是用於自動編譯和鏈接的,一個工程有很多文件組成,每一個文件的改變都會導致工程的重新鏈接,但是不是所有的文件都需要重新編譯,Makefile中記錄有文件的信 息,在make時會決定在鏈接的時候需要重新編譯哪些文件。Makefile的宗旨就是:讓編譯器知道要編譯一個文件需要依賴其他的哪些文件。當那些依賴文件有了改變,編譯器會自動發現最終的生成文件已經過時,而應該重新編譯相應的模塊。 makefile帶來的好處就是—"自動化編譯",一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發的效率。默認的情況下,make命令會在當前目錄下按順序找尋文件名為"GNUmakefile"、"makefile"、"Makefile"的文件,找到了解釋這個文件。當然也可以使用make -f DIR/makefile 來指定用於makefile文件 二 makefile語法簡述 2.1 makefile規則 target ... : dependencies ... command target目標文件,可以是Object File,也可以是執行文件,還可以是一個標簽 dependencies就是,要生成那個target所需要的文件或是目標。 command也就是make需要執行的命令。(任意的Shell命令,可以有若干行) 這是一個文件的依賴關系,也就是說,target這一個或多個的目標文件依賴於dependencies中的文件,其生成規則定義在command中。dependencies 中如果有一個以上的文件時間要比target文件要新的話,command所定義的命令就會被執行。這就是 Makefile的規則。也就是Makefile中最核心的內容。在Makefile中的命令,必須要以[Tab]鍵開始。 2.2 變量定義 Makefile中變量的定義一般有兩種: =和:=。 =符號定義的變量叫延時變量,只有在使用的時候才擴展開來; :=符號定義的變量為立即變量,一旦定義就擴展。 使用=定義的變量不能追加新值,使用:=定義的變量可以使用+=追加新值 2.3 文件指示 在Makefile使用include關鍵字可以把別的Makefile包含進來,這很像C語言的#include,被包含的文件會原模原樣的放在當前文件的包含位置。include的語法是:include <filename> filename可以是當前操作系統Shell的文件模式(可以保含路徑和通配符)
2.4 偽目標 偽目標並不是一個文件,只是一個標簽,由於偽目標不是文件,所以make無法生成它的依賴關系和決定 它是否要執行。我們只有通過顯示地指明這個目標才能讓其生效。當然,偽目標的取名不能和文件名重名,不然其就失去了偽目標的意義了。當然,為了避免和文件重名的這種情況,我們可以使用一個特殊的標記.PHONY來顯示地指明一個目標是偽目標,向make說明,不管是否有這個文件,這個目標就是偽目標。 2.5 自動化變量 $< 第一個依賴文件的名稱 $? 所有的依賴文件,以空格分開,這些依賴文件的修改日期比目標的創建日期晚 $@ 目標的完整名稱 $^ 所有的依賴文件,以空格分開,不包含重復的依賴文件 三 通用的makefile實例 工程必備: 頂層Makefile 頂層Makefile.build 子目錄Makefile 編譯過程: 從頂層開始遞歸進入子目錄,當進入到一個目錄的最底層時,開始使用GCC編譯,再將該層的所有.o文件打包成build-in.o,返回它的上一層目錄再遞歸進入子目錄,當編譯完所有的子目錄后,就開始編譯頂層的.c文件,最后將頂層的.o文件和頂層每個子目錄的build-in.o鏈接成我們的目標文件 頂層Makefile解析(隨工程而變): #----------------------------------------------指定編譯工具鏈---------------------------------------------------
CROSS_COMPILE = #指定編譯器種類
AS = $(CROSS_COMPILE)as # LD = $(CROSS_COMPILE)ld #鏈接工具
CC = $(CROSS_COMPILE)gcc #編譯工具
CPP = $(CC) -E # AR = $(CROSS_COMPILE)ar #打包工具
NM = $(CROSS_COMPILE)nm # STRIP = $(CROSS_COMPILE)strip #優化工具
OBJCOPY = $(CROSS_COMPILE)objcopy # OBJDUMP = $(CROSS_COMPILE)objdump # export AS LD CC CPP AR NM #將定義的變量導出,方便其他makefile使用
export STRIP OBJCOPY OBJDUMP #將定義的變量導出,方便其他makefile使用
CFLAGS := -Wall -O2 -g #編譯器參數
CFLAGS += -I $(shell pwd)/include #指定編譯器頭文件(根據實際項目手動修改)
LDFLAGS := -lm -lfreetype -lvga #指定編譯器鏈接庫(根據實際項目手動修改)
export CFLAGS LDFLAGS #將定義的變量導出,方便其他makefile使用
TOPDIR := $(shell pwd) #獲得當前程序的頂層目錄
export TOPDIR #輸出頂層目錄
TARGET := show_file #編譯后的程序名(根據實際項目手動修改)
#-------------------------頂層要生成的.o文件以及頂層文件夾(根據實際項目手動修改)------------------
obj-y += main.o obj-y += display/ obj-y += draw/ obj-y += encoding/ obj-y += fonts/
#--------------------------------------------頂層的第一個規則(默認規則)-----------------------------------------
all : make -C ./ -f $(TOPDIR)/Makefile.build #進入當前目錄,使用頂層的makefile.build進行編譯
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o #將編譯好的built-in.o文件鏈接生成我們的目標文件
#------------------------------------------------頂層的清除規則-------------------------------------------------------
clean: rm -f $(shell find -name "*.o") #刪除所有的.o文件
rm -f $(shell find -name "*.d") #刪除所有的.d文件
rm -f $(TARGET) #刪除目標文件
.PHONY:all clean 頂層Makefile.build解析(無需改動): PHONY := __build #定義一個PHONY變量
__build: #開頭說明__build偽目標,使其成為Makefile.build的第一個目標
obj-y := #定義當前目錄的目標變量,初始值為空
subdir-y := #定義當前目錄的子目錄變量,初始值為空
include Makefile #將當前目錄的Makefile包含進來,初始化obj-y
#obj-y:=a.o b.o c/ d/
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) #篩選出當前目錄的目標變量中的子目錄,並且去掉/
#$(filter %/, $(obj-y)):c/ d/
#__subdir-y:c d
subdir-y += $(__subdir-y) #將開始定義的subdir-y賦值為__subdir-y
#subdir-y:c d
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o) #對於subdir-y里面的每一個值(目錄),增加一個相應的目錄/built-in.o的變量值
#subdir_objs:c/built-in.o d/built-in.o
cur_objs := $(filter-out %/, $(obj-y)) #得到obj-y中的.o文件
#cur_objs:a.o b.o
dep_files := $(foreach f,$(cur_objs),.$(f).d) #對於所有的.o文件,定義它的依賴文件名
#dep_files: .a.d .b.d
dep_files := $(wildcard $(dep_files)) ifneq ($(dep_files),) #根據依賴文件名,判斷依賴文件是否存在,存在就包含就來
include $(dep_files) endif PHONY += $(subdir-y) #將$(subdir-y)也加入到變量PHONY中
--------------------------------------------Makefile. build的第一個規則-------------------------------------------------------------- __build : $(subdir-y) built-in.o #第一個規則
$(subdir-y): #第一個規則的第一個依賴規則
make -C $@ -f $(TOPDIR)/Makefile.build #依次進入該子目錄變量里面存儲的值,使用的Makefile.build進行編譯
built-in.o : $(cur_objs) $(subdir_objs) #第一個規則的第二個依賴規則
$(LD) -r -o $@ $^ #該規則的命令:將該目錄下的.o和$(subdir_obj)打包成built-in.o文件
dep_file = .$@.d #
%.o : %.c #第一個規則的第二個依賴規則的依賴規則
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $< #用於將目錄下所有的.c文件編譯成.o文件
.PHONY : $(PHONY) #將PHONY聲明為偽目標
子目錄Makefile(隨工程而變): 子目錄的Makefile就是包含該目錄下所有的目標文件名和子目錄文件夾名。 例如任何一個子目錄可寫成: objs-y := a.o objs-y += b.o objs-y += c/ objs-y += d/ 四 示例工程 http://pan.baidu.com/share/link?shareid=145262&uk=101680913