makefile基礎知識linux
一、賦值符號的區別:shell
= 是最基本的賦值,用到了以後才賦值,不能在變量後追加內容
:= 是覆蓋以前的值,當即賦值,能夠在變量後追加內容 ?= 是若是沒有被賦值過就賦予等號後面的值 += 是添加等號後面的值函數
二、自動變量:工具
$< 第一個依賴文件的名稱
$? 全部的依賴文件,以空格分開,這些依賴文件的修改日期比目標的建立日期晚
$@ 目標的完整名稱
$^ 全部的依賴文件,以空格分開,不包含重複的依賴文件ui
三、經常使用的函數:spa
1. $(patsubst %.c,%.o,x.c.cbar.c)
把字串「x.c.cbar.c」符合模式[%.c]的單詞替換成[%.o],返回結果是「x.c.o bar.o」
2.$(filter <pattern...>,<text> )
以<pattern>模式過濾<text>字符串中的單詞,保留符合模式<pattern>的單詞。能夠有多個模式。
3.$(filter-out <pattern...>,<text> )
4.$(foreach <var>,<list>,<text> )
把參數<list>中的單詞逐一取出放到參數<var>所指定的變量中, 而後再執行<text>所包含的表達式。每一次<text>會返回一個字符串,循環這個過程。
5.shell函數,例如files := $(shell echo *.c).net
通用的makefile文件的編譯過程:code
從頂層開始遞歸進入子目錄,當進入到一個目錄的最底層時,開始使用編譯器編譯,再將該層的全部.o文件打包成build-in.o,返回它的上一層目錄再遞歸進入子目錄,當編譯完全部的子目錄後,就開始編譯頂層的.c文件,最後將頂層的.o文件和頂層每一個子目錄的build-in.o連接成咱們的目標文件。blog
實戰:遞歸
假如一個目錄結構以下:
a
----d
----a.c
b
----b.c
c
----c.c
main.c
makefile
makefile.built
頂層的Makefile
#定義各個編譯用到的工具
CROSS_COMPILE = #交叉編譯器 arm-none-Linux-gnueabi- AS = $(CROSS_COMPILE)as #彙編器 LD = $(CROSS_COMPILE)ld #鏈接器 CC = $(CROSS_COMPILE)gcc #編譯器 CPP = $(CC) -E #預處理 AR = $(CROSS_COMPILE)ar #歸檔文件 NM = $(CROSS_COMPILE)nm #列出object文件中的符號 STRIP = $(CROSS_COMPILE)strip #丟棄目標文件中的符號 OBJCOPY = $(CROSS_COMPILE)objcopy #轉換目標文件格式 OBJDUMP = $(CROSS_COMPILE)objdump #反彙編 export AS LD CC CPP AR NM #將變量導出供下一個makefile使用 export STRIP OBJCOPY OBJDUMP CFLAGS := -Wall -O2 -g #CFLAGS 指定編譯參數
#CFLAGS += -I $(shell pwd)/include
LDFLAGS := export CFLAGS LDFLAGS TOPDIR := $(shell pwd) export TOPDIR TARGET := test obj-y += main.o #obj-y main.o 編譯連接進項目 obj-y += a/ obj-y += b/ obj-y += c/ all :
# make的遞歸執行,make的「-C」選項,是首先進入子目錄然後再執行make。
#當須要將一個普通命名的文件做爲makefile文件時,須要使用make的「-f」、「--file」或者「--makefile」選項來指定。 make -C ./ -f $(TOPDIR)/Makefile.build $(CC) $(LDFLAGS) -o $(TARGET) built-in.o clean: rm -f $(shell find -name "*.o") #刪除命令,默認是 rm -f rm -f $(shell find -name "*.d") rm -f $(TARGET)
#執行make時,目標「all」被做爲終極目標。
#僞目標」並非一個文件,只是一個標籤,因爲「僞目標」不是文件,因此make沒法生成它的依賴關係和決定它 是否要執行。
#咱們只有經過顯示地指明這個「目標」才能讓其生效。
#爲了不和文件重名的這種狀況,咱們能夠使用一個特殊的標記「.PHONY」來顯示地指明一個目標是「僞目標」,向make說明,
#無論是否有這個文件,這個目標就是「僞目標」。 .PHONY:all clean
Makefile.build
PHONY := build #定義一個PHONY變量 build : #開頭說明build僞目標,使其成爲Makefile.build的第一個目標 obj-y := subdir-y := include Makefile __subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) #篩選出當前目錄的目標變量中的子目錄,而且去掉/,在這裏咱們得到了子目錄的名字 subdir-y += $(__subdir-y) subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o) #對於subdir-y裏面的每個值(目錄),增長一個相應的目錄/built-in.o的變量值 cur_objs := $(filter-out %/, $(obj-y)) # 獲得obj-y中的.o文件 dep_files := $(foreach f,$(cur_objs),.$(f).d) # .$(f).d 第一個.表示隱藏的 後面的.表示後綴 dep_files := $(wildcard $(dep_files))
#ifneq ($(dep_files),) # include $(dep_files) #endif PHONY += $(subdir-y) build : $(subdir-y) built-in.o $(subdir-y): make -C $@ -f $(TOPDIR)/Makefile.build built-in.o : $(cur_objs) $(subdir_objs) $(LD) -r -o $@ $^ dep_file = .$@.d %.o : %.c $(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $< .PHONY : $(PHONY)
子目錄下的Makefile
obj-y += a.o
obj-y += d/
就是添加該目錄下的文件和子目錄,子目錄要以 / 結尾。