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