target ... : prerequisites ... shell
commandexpress
target爲目標文件,但是.o文件,但是執行文件,還但是標籤(Label)。prerequisites是生成target所須要的文件或目標。<TAB>command就是make須要執行的命令(任意的shell命令)函數
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.oui
將須要編譯的文件賦值給變量objects,在makefile中用$(objects)來調用。命令行
xx.o : test.h 排序
xx.o依賴的xx.c不用寫,若是有xx.c 那麼make會自動推到加上。只須要寫額外的其餘依賴便可。ip
.PHONY : clean
clean :
-rm edit $(objects)字符串
爲了不和文件重名的這種狀況,咱們可使用一個特殊的標記「.PHONY」來顯示地指明一個目標是「僞目標」(也可不加)。.PHONY 意思表示clean 是一個「僞目標」,而在rm 命令前面加了一個小減號的意思就是,也許某些文件出現問題,但不要管,繼續作後面的事。get
include foo.make *.mk $(bar)string
包含別的Makefile。
* ? [...]
通配符
VPATH = src:../headers
「src」和「../headers」,make會按照這個順序進行搜索源文件。目錄由「冒號」分隔。(固然,當前目錄永遠是最高優先搜索的地方)
vpath %.h ../headers
vpath <pattern> <directories>
爲符合模式<pattern>的文件指定搜索目錄<directories>。
vpath <pattern>
清除符合模式<pattern>的文件的搜索目錄。
vpath
清除全部已被設置好了的文件搜索目錄。
vapth使用方法中的<pattern>須要包含「%」字符。「%」的意思是匹配零或若干字符,例如,「%.h」表示全部以「.h」結尾的文件。<pattern>指定了要搜索的文件集,而<directories>則指定了<pattern>的文件集的搜索的目錄
gcc -MM main.c
自動找尋源文件中包含的頭文件,並生成一個依賴關係。-M會把標準庫的頭文件包含進來。-MM只包含defs.h這種自定義的頭文件
-rm -f *.o
命令行前加一個減號「-」(在Tab鍵以後),標記爲無論命令出不出錯都認爲是成功的.
cd /home/hchen; pwd
cd若是起做用了,pwd會打印出「/home/hchen」
cd subdir && $(MAKE) 等價 $(MAKE) -C subdir
有一個子目錄叫subdir,這個目錄下有個Makefile文件,來指明瞭這個目錄下文件的編譯規則。定義$(MAKE)宏變量的意思是,也許咱們的make須要一些參數,因此定義成一個變量比較利於維護。
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
若是Makefile中出現一些相同命令序列,那麼咱們能夠爲這些相同的命令序列定義一個變量. 使用的時候就用$(run-yacc)
objects = program.o foo.o utils.o
program : $(objects)
cc -o program $(objects)
$(objects) : defs.h
在Makefile中的定義的變量,就像是C/C++語言中的宏同樣,他表明了一個文本字串,在Makefile中執行的時候其會自動原模原樣地展開在所使用的地方。其與C/C++所不一樣的是,你能夠在Makefile中改變其值。
x := foo
y := $(x) bar
x := later
其等價於:
y := foo bar
x := later
這種方法,前面的變量不能使用後面的變量,只能使用前面已定義好了的變量
FOO ?= bar
若是FOO沒有被定義過,那麼變量FOO的值就是「bar」,若是FOO先前被定義過,那麼這條語將什麼也不作
$(var:a=b)
把變量「var」中全部以「a」字串「結尾」的「a」替換成「b」字串
objects = main.o foo.o bar.o utils.o
objects += another.o
追加變量值
define two-lines
echo foo
echo $(bar)
endef
define指示符後面跟的是變量的名字,而重起一行定義變量的值,定義是以endef關鍵字結束。其工做方式和「=」操做符同樣。變量的值能夠包含函數、命令、文字,或是其它變量。由於命令須要以[Tab]鍵開頭,因此若是你用define定義的命令變量中沒有以[Tab]鍵開頭,那麼make就不會把其認爲是命令。
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o
prog.o : prog.c
$(CC) $(CFLAGS) prog.c
無論全局的$(CFLAGS)的值是什麼,在prog目標,以及其所引起的全部規則中(prog.o foo.o bar.o的規則),$(CFLAGS)的值都是「-g」
<conditional-directive>-------------------------- ifeq (<arg1>, <arg2>)---------------反義詞ifneq 以及 ifdef <variable-name>若是變量<variable-name>的值非空,那到表達式爲真
<text-if-true>
endif
以及:
<conditional-directive>
<text-if-true>
else
<text-if-false>
endif
比較參數「arg1」和「arg2」的值是否相同,執行不一樣邏輯
$(<function> <arguments>)
函數調用,很像變量的使用,也是以「$」來標識的。
$(subst <from>,<to>,<text>)
把字串<text>中的<from>字符串替換成<to>
$(patsubst <pattern>,<replacement>,<text>)
查找<text>中的單詞(單詞以「空格」、「Tab」或「回車」「換行」分隔)是否符合模式<pattern>,若是匹配的話,則以<replacement>替換。這裏,<pattern>能夠包括通配符「%」,表示任意長度的字串。若是<replacement>中也包含「%」,那麼,<replacement>中的這個「%」將是<pattern>中的那個「%」所表明的字串。(能夠用「\」來轉義,以「\%」來表示真實含義的「%」字符)
$(strip <string>)
去掉<string>字串中開頭和結尾的空字符。
$(findstring <find>,<in>)
在字串<in>中查找<find>字串。若是找到,那麼返回<find>,不然返回空字符串
$(filter <pattern...>,<text>)
以<pattern>模式過濾<text>字符串中的單詞,保留符合模式<pattern>的單詞。能夠有多個模式。返回符合模式<pattern>的字串。
$(filter-out <pattern...>,<text>)
以<pattern>模式過濾<text>字符串中的單詞,去除符合模式<pattern>的單詞。能夠有多個模式。返回不符合模式<pattern>的字串。
$(sort <list>)
給字符串<list>中的單詞排序(升序)。返回排序後的字符串。
$(word <n>,<text>)
取字符串<text>中第<n>個單詞。(從一開始)。返回字符串<text>中第<n>個單詞。若是<n>比<text>中的單詞數要大,那麼返回空字符串。
$(wordlist <s>,<e>,<text>)
從字符串<text>中取從<s>開始到<e>的單詞串。<s>和<e>是一個數字。返回字符串<text>中從<s>到<e>的單詞字串。若是<s>比<text>中的單詞數要大,那麼返回空字符串。若是<e>大於<text>的單詞數,那麼返回從<s>開始,到<text>結束的單詞串。
$(words <text>)
統計<text>中字符串中的單詞個數。返回<text>中的單詞數。
$(firstword <text>)
取字符串<text>中的第一個單詞。返回字符串<text>的第一個單詞。
$(dir <names...>)
從文件名序列<names>中取出目錄部分。目錄部分是指最後一個反斜槓(「/」)以前的部分。若是沒有反斜槓,那麼返回「./」。返回文件名序列<names>的目錄部分。
$(notdir <names...>)
從文件名序列<names>中取出非目錄部分。非目錄部分是指最後一個反斜槓(「 /」)以後的部分。返回文件名序列<names>的非目錄部分。
$(suffix <names...>)
從文件名序列<names>中取出各個文件名的後綴。返回文件名序列<names>的後綴序列,若是文件沒有後綴,則返回空字串。
$(basename <names...>)
從文件名序列<names>中取出各個文件名的前綴部分。返回文件名序列<names>的前綴序列,若是文件沒有前綴,則返回空字串。
$(addsuffix <suffix>,<names...>)
把後綴<suffix>加到<names>中的每一個單詞後面。返回加事後綴的文件名序列。
$(addprefix <prefix>,<names...>)
把前綴<prefix>加到<names>中的每一個單詞後面。返回加過前綴的文件名序列。
$(join <list1>,<list2>)
把<list2>中的單詞對應地加到<list1>的單詞後面。若是<list1>的單詞個數要比<list2>的多,那麼,<list1>中的多出來的單詞將保持原樣。若是<list2>的單詞個數要比<list1>多,那麼,<list2>多出來的單詞將被複制到<list2>中。返回鏈接事後的字符串。
$(foreach <var>,<list>,<text>)
把參數<list>中的單詞逐一取出放到參數<var>所指定的變量中,而後再執行<text>所包含的表達式。每一次<text>會返回一個字符串,循環過程當中,<text>的所返回的每一個字符串會以空格分隔,最後當整個循環結束時,<text>所返回的每一個字符串所組成的整個字符串(以空格分隔)將會是foreach函數的返回值。
$(if <condition>,<then-part>)或$(if <condition>,<then-part>,<else-part>)
$(call <expression>,<parm1>,<parm2>,<parm3>...)
當make執行這個函數時,<expression>參數中的變量,如$(1),$(2),$(3)等,會被參數<parm1>,<parm2>,<parm3>依次取代。而<expression>的返回值就是call函數的返回值
$(origin <variable>)
<variable>是變量的名字,不該該是引用。因此你最好不要在<variable>中使用「$」字符。Origin函數會以其返回值來告訴你這個變量的「出生狀況」.
contents := $(shell cat foo)
files := $(shell echo *.c)
這個函數會新生成一個Shell程序來執行命令
$(error <text ...>)
產生一個致命的錯誤,<text ...>是錯誤信息。注意,error函數不會在一被使用就會產生錯誤信息,因此若是你把其定義在某個變量中,並在後續的腳本中使用這個變量,那麼也是能夠的
$(warning <text ...>)
這個函數很像error函數,只是它並不會讓make退出,只是輸出一段警告信息,而make繼續執行。
.PHONY: all
all: prog1 prog2 prog3 prog4
咱們可使用「make all」命令來編譯全部的目標(若是把all置成第一個目標,那麼只需執行「make」)
自動化變量及其說明
$@
表示規則中的目標文件集。在模式規則中,若是有多個目標,那麼,"$@"就是匹配於目標中模式定義的集合。
$%
僅當目標是函數庫文件中,表示規則中的目標成員名。例如,若是一個目標是"foo.a (bar.o)",那麼,"$%"就是"bar.o","$@"就是"foo.a"。若是目標不是函數庫文件(Unix下是[.a],Windows下是[.lib]),那麼,其值爲空。
$<
依賴目標中的第一個目標名字。若是依賴目標是以模式(即"%")定義的,那麼"$<"將是符合模式的一系列的文件集。注意,其是一個一個取出來的。
$?
全部比目標新的依賴目標的集合。以空格分隔。
$^
全部的依賴目標的集合。以空格分隔。若是在依賴目標中有多個重複的,那個這個變量會去除重複的依賴目標,只保留一份。
$+
這個變量很像"$^",也是全部依賴目標的集合。只是它不去除重複的依賴目標。
$*
這個變量表示目標模式中"%"及其以前的部分。若是目標是"dir/a.foo.b",而且目標的模式是"a.%.b",那麼,"$*"的值就是"dir/a.foo"。這個變量對於構造有關聯的文件名是比較有較。若是目標中沒有模式的定義,那麼"$*"也就不能被推導出,可是,若是目標文件的後綴是make所識別的,那麼"$*"就是除了後綴的那一部分。例如:若是目標是"foo.c",由於".c"是make所能識別的後綴名,因此,"$*"的值就是"foo"。這個特性是GNU make的,頗有可能不兼容於其它版本的make,因此,你應該儘可能避免使用"$*",除非是在隱含規則或是靜態模式中。若是目標中的後綴是make所不能識別的,那麼"$*"就是空值。
你能夠重載內建的隱含規則(或是定義一個全新的),例如你能夠從新構造和內建隱含規則不一樣的命令,如:
%.o : %.c
$(CC) -c $(CPPFLAGS) $(CFLAGS) -D$(date)
你能夠取消內建的隱含規則,只要不在後面寫命令就行。