1.Makefile簡(jiǎn)介
Makefile是和make工具一起配合使用的,用于組織管理項(xiàng)目源代碼的編譯和鏈接。
make工具用于找出修改過的文件,根據(jù)依賴關(guān)系,找出受影響的相關(guān)文件,最后按照規(guī)則單獨(dú)編譯這些文件。
Makefile文件則記錄依賴關(guān)系和編譯規(guī)則。
Makefile的本質(zhì):無論多么復(fù)雜的語法,都是為了更好地解決項(xiàng)目文件之間的依賴關(guān)系。
2.Makefile規(guī)則介紹
Makefile的一個(gè)規(guī)則由目標(biāo)、依賴、命令組成,其語法結(jié)構(gòu)如下所示:
目標(biāo):依賴的文件或者是其他目標(biāo)命令1 命令2 ...
一個(gè)規(guī)則可以有多個(gè)命令行,每一條命令占一行。注意:每一個(gè)命令行必須以[Tab]字符開始,[Tab]字符告訴 make 此行是一個(gè)命令行。make 按照命令完成相應(yīng)的動(dòng)作。這也是書寫 Makefile 中容易產(chǎn)生,而且比較隱蔽的錯(cuò)誤。
3.Makefile偽目標(biāo)
偽目標(biāo)不代表一個(gè)真正的文件名,在執(zhí)行 make 時(shí)可以指定這個(gè)目標(biāo)來執(zhí)行其所在規(guī)則定義的命令,有時(shí)也可以將一個(gè)偽目標(biāo)稱為標(biāo)簽。
使用偽目標(biāo)有兩點(diǎn)原因:
(1).避免在我們的 Makefile 中定義的只執(zhí)行命令的目標(biāo)(此目標(biāo)的目的是為了執(zhí)行一系列命令,而不需要?jiǎng)?chuàng)建這個(gè)目標(biāo))和工作目錄下的實(shí)際文件出現(xiàn)名字沖突。
(2).提高執(zhí)行 make 時(shí)的效率,特別是對(duì)于一個(gè)大型的工程來說,編譯的效率也許你同樣關(guān)心。
將一個(gè)目標(biāo)聲明為偽目標(biāo)的方法是將它作為特殊目標(biāo)".PHONY"的依賴。在書寫偽目標(biāo)規(guī)則時(shí),首先需要聲明目標(biāo)是一個(gè)偽目標(biāo),之后才是偽目標(biāo)的規(guī)則定義。目標(biāo)"clean"的書寫格式應(yīng)該如下:
.PHONY:clean clean: rm*.otemp
4.Makefile的變量
在 Makefile 中,變量是一個(gè)名字(像是 C 語言中的宏),代表一個(gè)文本字符串。在 Makefile 的目標(biāo)、依賴、命令中引用變量的地方,變量會(huì)被它的值所取代。
變量名是不包括":"、"#"、"="、前置空白和尾空白的任何字符串。變量名最好使用字母、數(shù)字和下劃線進(jìn)行定義,對(duì)于其他的特殊符號(hào)不建議使用到變量名的定義中。
變量名是大小寫敏感的。變量"foo"、"Foo"和"FOO"指的是三個(gè)不同的變量。
變量的引用方式是:"$(VARIABLE_NAME)" 或者 "${VARIABLE_NAME}" 來引用一個(gè)變量的定義。
Makefile的變量包含系統(tǒng)環(huán)境變量,自定義變量和自動(dòng)化變量。
4.1.系統(tǒng)環(huán)境變量
使用系統(tǒng)環(huán)境變量需要注意以下幾點(diǎn):
(1).在 Makefile 中對(duì)一個(gè)變量的定義或者以 make 命令行形式對(duì)一個(gè)變量的定義,都將覆蓋同名的系統(tǒng)環(huán)境變量(注意:它并不改變系統(tǒng)環(huán)境變量定義,被修改的環(huán)境變量只在 make 執(zhí)行過程有效)。而 make 使用"-e"參數(shù)時(shí),Makefile 和命令行定義的變量不會(huì)覆蓋同名的環(huán)境變量,make 將使用系統(tǒng)環(huán)境變量中這些變量的定義值。
(2).make的遞歸調(diào)用中,所有的系統(tǒng)環(huán)境變量會(huì)被傳遞給下一級(jí)make。默認(rèn)情況下,只有系統(tǒng)環(huán)境變量和通過命令行方式定義的變量才會(huì)被傳遞給子make進(jìn)程。在Makefile中定義的普通變量需要傳遞給子make時(shí)需要使用"export"指示符來對(duì)它聲明。
4.2.自定義變量
在Makefile中自定義變量比較簡(jiǎn)單,下面簡(jiǎn)單的區(qū)分下各個(gè)符號(hào)的含義:
(1).延遲賦值:"=";
使用"="號(hào)定義變量時(shí),如果定義的變量存在對(duì)其他變量的引用,那么定義的變量并不會(huì)立即展開對(duì)其他變量的引用,而是在真正使用到該變量時(shí)才進(jìn)行展開。例如下述例子中,只有在echo "(A),雖然在定義變量B之前A的值為123,但是在執(zhí)行echo "$(B)"時(shí),A的最終值為456,因此會(huì)輸出456。
(2).立即賦值:":=";
立即賦值是相對(duì)于延遲賦值的,使用":="號(hào)定義變量時(shí),如果定義的變量存在對(duì)其他變量的引用,那么定義的變量會(huì)立即展開對(duì)其他變量的引用??梢越Y(jié)合下面的例子進(jìn)行理解。
(3).為空賦值(條件賦值):"?=";
使用"?="號(hào)定義變量時(shí),只有定義的變量在之前沒有賦值的情況下才會(huì)對(duì)這個(gè)變量進(jìn)行賦值??梢越Y(jié)合下面的例子進(jìn)行理解。
(4).追加賦值:"+=";
使用"+="符號(hào),可以對(duì)變量的值進(jìn)行追加。可以結(jié)合下面的例子進(jìn)行理解。
例子:
#延遲賦值 A=123 B=$(A) A=456 #立即賦值 C=123 D:=$(C) C=456 #空賦值 E?=123 E?=456 #追加賦值 F?=123 F+=456 .PHONY:all all: echo"$(B)"#結(jié)果:456 echo"$(D)"#結(jié)果:123 echo"$(E)"#結(jié)果:123 echo"$(F)"#結(jié)果:123456
4.3.自動(dòng)化變量
Makefile中常用的自動(dòng)化變量如下描述:
$<:第一個(gè)依賴文件;
$^:全部的依賴文件;
$@:目標(biāo);
5.Makefile條件分支
條件分支語法如下:
ifeq(var1,var2) ... else ... endif ifneq(var1,var2) ... else ... endif
例子:
ARCH?=x86 ifeq($(ARCH),x86) CC=gcc else CC=arm-linux-gnueabihf-gcc endif
6.Makefile的常用函數(shù)
Makefile還是提供了比較多的函數(shù)供我們使用,這里介紹下常用的幾個(gè)函數(shù)。
6.1.patsubst
$(patsubst PATTERN,REPLACEMENT,TEXT)
函數(shù)名稱:模式替換函數(shù) - patsubst。
函數(shù)功能:搜索"TEXT"中以空格分開的單詞,將符合模式"PATTERN"替換為"REPLACEMENT"。參數(shù)"PATTERN"中可以使用模式通配符"%"來代表一個(gè)單詞中的若干字符。如果參數(shù)"REPLACEMENT"中也包含一個(gè)"%",那么"REPLACEMENT"中的"%"將是"PATTERN"中的那個(gè)"%"所代表的字符串。在"PATTERN"和"REPLACEMENT"中,只有第一個(gè)"%"被作為模式字符來處理,之后出現(xiàn)的不再作模式字符(作為一個(gè)字符)。在參數(shù)中如果需要將第一個(gè)出現(xiàn)的"%"作為字符本身而不作為模式字符時(shí),可使用反斜杠""進(jìn)行轉(zhuǎn)義處理。
返回值:替換后的新字符串。函數(shù)說明:參數(shù)"TEXT"單詞之間的多個(gè)空格在處理時(shí)被合并為一個(gè)空格,并忽略前導(dǎo)和結(jié)尾空格。
如果感覺上述的文字說明有點(diǎn)不太好理解,那么看看下面的示例吧,之后再結(jié)合示例看上面的文字說明應(yīng)該就比較好理解了,示例如下:
.PHONY:all all: echo"$(patsubst%.c,%.o,x.c.cbar.c)"#結(jié)果:x.c.obar.o
上述示例的運(yùn)行結(jié)果:把字串"x.c.c bar.c"中以.c 結(jié)尾的單詞替換成以.o 結(jié)尾的字符。函數(shù)的返回結(jié)果是"x.c.o bar.o"。
6.2.notdir
$(notdir NAMES…)
函數(shù)名稱:取文件名函數(shù) - notdir。
函數(shù)功能:從文件名序列"NAMES…"中取出非目錄部分。目錄部分是指最后一個(gè)斜線("/")(包括斜線)之前的部分。刪除所有文件名中的目錄部分,只保留非目錄部分。
返回值:文件名序列"NAMES…"中每一個(gè)文件的非目錄部分。
函數(shù)說明:如果"NAMES…"中存在不包含斜線的文件名,則不改變這個(gè)文件名。以反斜線結(jié)尾的文件名,是用空串代替,因此當(dāng)"NAMES…"中存在多個(gè)這樣的文件名時(shí),返回結(jié)果中分割各個(gè)文件名的空格數(shù)目將不確定!這是此函數(shù)的一個(gè)缺陷。
示例:
.PHONY:all all: echo"$(notdirsrc/foo.chacks)"#結(jié)果:foo.chacks
6.3.wildcard
$(wildcard PATTERN)
函數(shù)名稱:獲取匹配模式文件名函數(shù) - wildcard。
函數(shù)功能:列出當(dāng)前目錄下所有符合模式"PATTERN"格式的文件名。
返回值:空格分割的、存在當(dāng)前目錄下的所有符合模式"PATTERN"的文件名。
函數(shù)說明:"PATTERN"使用shell可識(shí)別的通配符,包括"?"(單字符)、"*"(多字符)等。
示例:
.PHONY:all all: echo"$(wildcard*.c)"#結(jié)果:當(dāng)前目錄下所有.c源文件列表
6.4.foreach
$(foreach VAR,LIST,TEXT)
函數(shù)"foreach"不同于其它函數(shù)。它是一個(gè)循環(huán)函數(shù)。類似于 Linux shell 中的for 語句。
函數(shù)名稱:循環(huán)函數(shù) - foreach。
函數(shù)功能:這個(gè)函數(shù)的工作過程是這樣的:如果需要(存在變量或者函數(shù)的引用),首先展開變量"VAR"和"LIST"的引用;而表達(dá)式"TEXT"中的變量引用不展開。執(zhí)行時(shí)把"LIST"中使用空格分割的單詞依次取出賦值給變量"VAR",然后執(zhí)行"TEXT"表達(dá)式。重復(fù)直到"LIST"的最后一個(gè)單詞(為空時(shí)結(jié)束)。"TEXT"中的變量或者函數(shù)引用在執(zhí)行時(shí)才被展開,因此如果在"TEXT"中存在對(duì)"VAR"的引用,那么"VAR"的值在每一次展開式將會(huì)到的不同的值。
返回值:空格分割的多次表達(dá)式"TEXT"的計(jì)算的結(jié)果。
備注:函數(shù)中參數(shù)"VAR"是一個(gè)局部的臨時(shí)變量,它只在"foreach"函數(shù)的上下文中有效,它的定義不會(huì)影響其它部分定義的同名"VAR"變量的值。
示例:
.PHONY:all dirs:=abcd files:=$(foreachdir,$(dirs),$(wildcard$(dir)/*)) all: echo"$(files)"#結(jié)果:files是abcd4個(gè)目錄下所有文件組成的文件列表.
示例分析:例子中,"TEXT"的表達(dá)式為 $(wildcard $(dir)/*)。表達(dá)式第一次執(zhí)行時(shí)將展開為 $(wildcard a/*);第二次執(zhí)行時(shí)將展開為 $(wildcard b/*);第三次展開為 $(wildcard c/*); ...;以此類推。
7.其他
默認(rèn)規(guī)則:.o文件默認(rèn)使用對(duì)應(yīng)的.c文件來進(jìn)行編譯。
-
命令
+關(guān)注
關(guān)注
5文章
683瀏覽量
22011 -
源代碼
+關(guān)注
關(guān)注
96文章
2945瀏覽量
66730 -
編譯
+關(guān)注
關(guān)注
0文章
657瀏覽量
32852 -
Makefile
+關(guān)注
關(guān)注
1文章
125瀏覽量
19181
原文標(biāo)題:Makefile學(xué)習(xí)與使用-一篇文章帶你了解
文章出處:【微信號(hào):嵌入式那些事,微信公眾號(hào):嵌入式那些事】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論