嵌入式linux基礎(chǔ)之makefile
在linux中我們使用gcc來編譯單個文件,然而我們在工作中可不單單只有一個文件,因此面對大工程我們可以使用makefile來對整個項目工程進(jìn)行編譯。
那什么是makefile,其實就是定義了一整套編譯規(guī)則的一個文件,然后使用make才啟動這項規(guī)則,下面先來介紹一下make 這個命令
執(zhí)行make命令的時候,首先CPU會去搜索這三個文件
“GNU-makefile”、“makefile”和“Makefile”。其按順序找這三個文件,一旦找到,就開始讀取這個文件并執(zhí)行
還要記住make的環(huán)境變量是MAKEFILES
如果你的當(dāng)前環(huán)境中定義了環(huán)境變量 MAKEFILES ,那么,make 會把這個變量中的值做一個類似于include 的動作,把這個MAKEFILES的變量指包含進(jìn)去;
make的工作步驟
讀入所有的 Makefile。
讀入被 include 的其它 Makefile。
初始化文件中的變量。
推導(dǎo)隱晦規(guī)則,并分析所有規(guī)則。
為所有的目標(biāo)文件創(chuàng)建依賴關(guān)系鏈。
根據(jù)依賴關(guān)系,決定哪些目標(biāo)要重新生成。
執(zhí)行生成命令
make的參數(shù)
make命令的參數(shù)有許多種,然而我們也沒必要全部記住,重要的2個先記住
主要記住參數(shù)-f和-C
-f: ? 指定需要執(zhí)行的 makefile文件
-C: 指定讀取 makefile 的目錄。如果有多個“-C”參數(shù),make 的解釋是
后面的路徑以前面的作為相對路徑,并以最后的目錄作為被指定目錄。如:“make -C ~hchen/test
-C prog”等價于“make -C ~hchen/test/prog”。
合并使用實例:
make -C a/ -f Makefile.build
意思是到a目錄里面找到Makefile.build,并執(zhí)行
makefile基礎(chǔ)
介紹完make之后,接下來,來看一下makefile的規(guī)則,其實整個規(guī)則是圍繞著這三個概念
目標(biāo):依賴
規(guī)則
當(dāng)依賴時間? >? 目標(biāo),說明有需要更改,makefile才會執(zhí)行規(guī)則(規(guī)則有些地方也叫命令)
目標(biāo)就是我們需要生成的文件,比如可執(zhí)行文件;目標(biāo)也有偽目標(biāo)
偽目標(biāo)用.PHONY來定義
.PHONY ?XXX文件 定義為假想目標(biāo),就不會去判斷目標(biāo)是否存在
依賴就是生成目標(biāo)需要的文件
規(guī)則也叫命令,就是執(zhí)行這項規(guī)則去生成這個目標(biāo),其實大部分的規(guī)則其實也就是采用上一篇GCC編譯規(guī)則去生成目標(biāo)
實例:
main: main.o input.o calcu.o
????gcc -o main main.o input.o calcu.o
規(guī)則有分顯示規(guī)則和隱示規(guī)則
顯示規(guī)則:代碼中有寫出來的,可直接根據(jù)代碼推導(dǎo);
隱示規(guī)則:代碼中沒寫,是make指令自己的規(guī)則,隱示規(guī)則是重點,在介紹隱示規(guī)則之前
????????????????????先讀一下這張表,名為“自動化變量表”

隱含規(guī)則:
重點記住這幾條即可
1、只要 make 看到一個 .o 文件,它就會自動的把 .c (或者.cpp,根據(jù)其設(shè)置的環(huán)境變量而定)文件加在依賴關(guān)系中,并根據(jù)環(huán)境變量自動推導(dǎo)其相關(guān)規(guī)則
2、%的作用,比如當(dāng)sub.o找到不到依賴的時候,回來這一條做匹配;
例如:

上面找不到.o的規(guī)則的會去第6行執(zhí)行
3、同一個目標(biāo),一條規(guī)則有命令,另一個沒有,他們的依賴會合并在一起
例如:

第5行和第8行合并
重點記住這三條,其他的有遇到在臨時去查
重點記?。?/strong>makefile會想盡辦法生成最終目標(biāo),然后選擇是否刪除中間件(這個用戶可以定義)
重要的知識點匯總
當(dāng)然作為編程腳本,不僅僅這些,把它和C語言作對比,也有以下這些同樣的功能,
引用其它的文件文件的功能
include filename
make 命令開始時,會找尋 include 所指出的其它的文件,并把其內(nèi)容安置在當(dāng)前的位置
make的尋找路徑順序
1、當(dāng)前路徑
2、如果 make 執(zhí)行時,有 -I 或 --include-dir 參數(shù),在這個參數(shù)所指定的目錄下去尋找
3、/usr/local/bin 或 /usr/include
如果有文件沒有找到的話,make 會生成一條警告信息,繼續(xù)載入其它的文件,一旦完成 makefile 的讀取,make 會再重試這些沒有找到,或是不能讀取的文件make 才會出現(xiàn)一條致命信息;
如果你想讓 make 不理那些無法讀取的文件,而繼續(xù)執(zhí)行,你可以在include 前加一個減號“-”。如:-include
文件搜尋功能:
大寫的VPATH
VPATH:
如果沒有指明這個變量,make 只會在當(dāng)前的目錄中去找尋依賴文件和目標(biāo)文件。
如果定義了這個變量,那么,make 就會在當(dāng)前目錄找不到的情況下,到所指定的目錄中去找尋文件了
小寫的vpath
vpath:
主要目的是搜索,搜索什么東西,在哪里搜索?
例如vpath %.h ../headers
搜索.h文件,在headers目錄下搜錯
如遇到連續(xù)的vpath
例如
vpath %.c foo
vpath % blish
vpath %.c bar
搜索.c文件,在foo目錄下搜索,然后這blish,最后在bar目錄下搜索
多目標(biāo)的時候
bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@
等同于
bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.g
generate text.g -little > littleoutput
@ 字符的作用
@ 字符在命令行前,那么,這個命令將不被 make 顯示出來
例如 @echo 1234
如果沒有@的話,會把整條命令都打印出來,有的話只會打印1234
分號的作用
如果你要讓上一條命令的結(jié)果應(yīng)用在下一條命令時,你應(yīng)該使用分號分隔這兩條命令
例如
示例一
exec:
cd /home/hchen
pwd
示例二:
exec:
cd /home/hchen; pwd
當(dāng)我們執(zhí)行 make exec 時,第一個例子中的 cd 沒有作用,pwd 會打印出當(dāng)前的 Makefile 目錄,而
第二個例子中,cd 就起作用了,pwd 會打印出“/home/hchen”
錯誤命令忽略:
有些時候,命令的出錯并不表示就是錯誤的,為了忽略錯誤,我們可以在 Makefile 的命令行前加一個減號 - (在 Tab 鍵之
后),標(biāo)記為不管命令出不出錯都認(rèn)為是成功的
還有一個全局的辦法是,給 make 加上 -i 或是 --ignore-errors 參數(shù),那么,Makefile 中所有命
令都會忽略錯誤
make 的參數(shù)的是 -k 或是 --keep-going ,這個參數(shù)的意思是,如果某規(guī)則中
的命令出錯了,那么就終止該規(guī)則的執(zhí)行,但繼續(xù)執(zhí)行其它規(guī)則。
export ?的作用
傳遞上級變量給子級的makefile用
“嵌套執(zhí)行”中比較有用的參數(shù),-w 或是 --print-directory 會在 make 的過程中輸出
一些信息,讓你看到目前的工作目錄
有兩個變量,一個是 SHELL ,一個是 MAKEFLAGS ,這兩個變量不管你是否 export,
其總是要傳遞到下層 Makefile 中,特別是 MAKEFLAGS 變量,其中包含了 make 的參數(shù)信息
定義命令包
定義一系列命令的集合
定義這種命令序列的語法以 define 開始,以 endef 結(jié)束
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
使用:
foo.c : foo.y
$(run-yacc)
要使用這個命令包,我們就好像使用變量一樣,make在執(zhí)行命令包時,命令包中的每個命令會被依次獨立執(zhí)行
override指示符
我們可能會有這樣的需求;可以通過命令行來指定一些附加的編譯參數(shù),
對一些通用的參數(shù)或者必需的編譯參數(shù)在Makefile中指定,而在命令行中指定一些特殊的參數(shù)。
對于這種需求,我們就需要使用指示符“override”來實現(xiàn)
EXEF = foo
override CFLAGS += -Wall –g
.PHONY : all debug test
all : $(EXEF)
foo : foo.c
………..
………..
$(EXEF) : debug.h
$(CC) $(CFLAGS) $(addsuffix .c,$@) –o $@
debug :
@echo ”CFLAGS = $(CFLAGS)”
執(zhí)行:make CFLAGS=-O2 將顯式編譯“foo”的過程是“cc –O2 –Wall –g foo.c –o foo”。
執(zhí)行“make CFLAGS=-O2 debug”可以查看到變量“CFLAGS”的值為“–O2 –Wall –g”。
另外,這個例子中,如果把變量“CFLAGS”之前的指示符“override”去掉,
使用相同的命令將得到不同的結(jié)果
如果make 指定了“-e”參數(shù),那么,系統(tǒng)環(huán)境變量將覆蓋 Makefile 中定義的變量
變量
變量的使用
$(變量名)
變量的賦值
?“=” 延時賦值,該變量只有在調(diào)用的時候,才會被賦值
?“:=” 直接賦值,與延時賦值相反,使用直接賦值的話,變量的值定義時就已經(jīng)確定了。
?“?=” 若變量的值為空,則進(jìn)行賦值,通常用于設(shè)置默認(rèn)值。
?“+=” 追加賦值,可以往變量后面增加新的內(nèi)容。
變量高級用法
$(var:a=b) 或是 ${var:a=b}
把變量“var”中所有以“a”字串“結(jié)尾”的“a”替換成“b”字串。這里的“結(jié)尾”意思是“空格”或是“結(jié)束符”
實例
foo := a.o b.o c.o
bar := $(foo:.o=.c)
在foo這個變量的值中,把.o結(jié)尾的換成.c
$(bar) 的值就是“a.c b.c c.c”
另外一種變量替換的技術(shù)是以“靜態(tài)模式”(參見前面章節(jié))定義
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
目標(biāo)變量
首先在makefile中定義的變量都是全局變量
prog : CFLAGS = -g
定義在目標(biāo)之后的變量,只在目標(biāo)作用域范圍內(nèi)有效
模式變量
我們可以給定一種“模式”,可以把變量定義
在符合這種模式的所有目標(biāo)上
%.o : CFLAGS = -O
同樣,模式變量的語法和“目標(biāo)變量”一樣
意思是說只有目標(biāo)為.o的文件才能使用這變量
條件判斷
有變量,當(dāng)然也有類似于C語言的 if .....else......條件判斷
條件判斷的關(guān)鍵字有四個
第一個ifeq
比較參數(shù) arg1 和 arg2 的值是否相同
第二個ifneq
ifneq和ifeq相反
第三個條件關(guān)鍵字是 ifdef
ifdef
如果變量的值非空,那到表達(dá)式為真。否則,表達(dá)式為假
第四個條件關(guān)鍵字是 ifndef
ifndef
和ifdef意思相反
后綴規(guī)則:
后綴規(guī)則不允許任何的依賴文件,如果有依賴文件的話,那就不是后綴規(guī)則,那些后綴統(tǒng)統(tǒng)被認(rèn)為是文件名
單后綴:
例如:.c 相當(dāng)于 % : %.c
雙后綴:
.c.o:(相當(dāng)于%.o :?%.c)
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
.c.o 那么其就是雙后綴規(guī)則,意義就是 .c 是源文件的后綴,.o 是目標(biāo)文件的后綴
函數(shù)庫文件的后綴規(guī)則
.c.a:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $.o$(AR) r $@ $.o
$(RM) $.o
其等效于:
(%.o) : %.c$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $.o
$(AR) r $@ $.o$(RM) $.o
函數(shù)
最后介紹一下函數(shù):
函數(shù)包括函數(shù)名和參數(shù)
語法:
$()或者${}
函數(shù)和變量的括號最好一樣,
如使用 $(subst a,b,$(x)) 這樣的形式,而不是 $(subst a,b, ${x}) 的形式
記住格式語法就行,不需要去背,用到的時候這臨時去查
總結(jié):
