Makefile學(xué)習(xí)

Makefile學(xué)習(xí)


參考自《跟我一起寫Makefile》陳皓


Makefile 的語法規(guī)則

基本語法

target ... : prerequisites ...
    command
    ...
    ...

翻譯成中文大概就是:

一系列目標(biāo)文件:一系列依賴文件
    執(zhí)行的一些命令

target 也就是一個目標(biāo)文件,可以是 Object File 墓懂,也可以是執(zhí)行文件掂碱。還可以是一個標(biāo)簽。

prerequisites 就是要生成那個 target 所需要的文件或是目標(biāo)。

command 也就是 make 需要執(zhí)行的任意的 shell 命令挣轨。

默認(rèn)情況下, make 命令會在當(dāng)前目錄下按順序找尋文件名為"GNUmakefile" "makefile" "Makefile"的文件能曾,并解釋這個文件。一般使用"Makefile"這個文件名凌简。

如果要指定特定的 Makefile上炎,你可以使用 make 的"-f"和"--file"參數(shù),如:make -f Make.Linux 或 make --file Make.AIX雏搂。

更新函數(shù)庫文件

liba(a.o ...):a.o ...
    ar cr liba a.o ...

條件表達(dá)式

條件表達(dá)式的語法為:

<conditional-directive>
<text-if-true>
endif

以及:

<conditional-directive>
<text-if-true>
else <conditional-directive>
<text-if-true>
else
<text-if-false>
endif

其中<conditional-directive>表示條件關(guān)鍵字藕施,這個關(guān)鍵字有四種:

  • ifeq
ifeq (<arg1>, <arg2>)
ifeq '<arg1>' '<arg2>'
ifeq "<arg1>" "<arg2>"
ifeq "<arg1>" '<arg2>'
ifeq '<arg1>' "<arg2>"

比較參數(shù)"arg1"和"arg2"的值是否相同。

  • ifneq
ifneq (<arg1>, <arg2>)
ifneq '<arg1>' '<arg2>'
ifneq "<arg1>" "<arg2>"
ifneq "<arg1>" '<arg2>'
ifneq '<arg1>' "<arg2>"

比較參數(shù)"arg1"和"arg2"的值是否相同凸郑,如果不同裳食,則為真。

  • ifdef
ifdef <variable-name>

如果變量<variable-name>的值非空芙沥,那到表達(dá)式為真诲祸。否則,表達(dá)式為假而昨。當(dāng)然救氯,<variable-name>同樣可以是一個函數(shù)的返回值。注意歌憨,ifdef 只是測試一個變量是否有值着憨,其并不會把變量擴(kuò)展到當(dāng)前位置。

  • ifndef
ifndef <variable-name>

和 ifdef 是意思相反务嫡。

偽目標(biāo)

"偽目標(biāo)"并不是一個文件享扔,只是一個標(biāo)簽,由于"偽目標(biāo)"不是文件植袍,所以 make 無法生成它的依賴關(guān)系和決定它是否要執(zhí)行惧眠。我們只有通過顯示地指明這個"目標(biāo)"才能讓其生效。當(dāng)然于个,"偽目標(biāo)"的取名不能和文件名重名氛魁,不然其就失去了"偽目標(biāo)"的意義了。

當(dāng)然,為了避免和文件重名的這種情況秀存,我們可以使用一個特殊的標(biāo)記".PHONY"來顯示地指明一個目標(biāo)是"偽目標(biāo)"捶码,向 make 說明,不管是否有這個文件或链,這個目標(biāo)就是"偽目標(biāo)"惫恼。

.PHONY : clean

多目標(biāo)

bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@

上述規(guī)則等價于:

bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.ggenerate text.g -little > littleoutput

靜態(tài)模式

<targets ...>: <target-pattern>: <prereq-patterns ...>
<commands>
...

targets 定義了一系列的目標(biāo)文件,可以有通配符。是目標(biāo)的一個集合澳盐。

target-parrtern 是指明了 targets 的模式,也就是的目標(biāo)集模式祈纯。

prereq-parrterns 是目標(biāo)的依賴模式,它對 target-parrtern 形成的模式再進(jìn)行一次依賴目標(biāo)的定義。

注釋

Makefile 中使用'#'字符作為注釋符叼耙,在'#'之后的是注釋部分腕窥,當(dāng)你真正想用到'#'字符時,可以用反斜杠進(jìn)行轉(zhuǎn)義筛婉,如'\#'簇爆。


Makefile 使用變量

普通變量

a = main.o # 定義變量a的值為main.o
var = aa

$a   # 調(diào)用變量
$(a) # 調(diào)用變量
${a}
$(var) # 調(diào)用變量
${var}

多行變量

define two-lines
echo foo
echo $(bar)
endef

自動化變量

  • $@ 表示規(guī)則中的目標(biāo)文件集。在模式規(guī)則中爽撒,如果有多個目標(biāo)入蛆,那么,"$@"就是匹配于目標(biāo)中模式定義的集合硕勿。

  • $% 僅當(dāng)目標(biāo)是函數(shù)庫文件中安寺,表示規(guī)則中的目標(biāo)成員名。例如首尼,如果一個目標(biāo)是"foo.a(bar.o)"挑庶,那么,"$%"就是"bar.o"软能,"$@"就是"foo.a"迎捺。如果目標(biāo)不是函數(shù)庫文件(Unix 下是[.a],Windows 下是[.lib])查排,那么凳枝,其值為空。

  • $< 依賴目標(biāo)中的第一個目標(biāo)名字跋核。如果依賴目標(biāo)是以模式(即"%")定義的岖瑰,那么"$<"將是符合模式的一系列的文件集。注意砂代,其是一個一個取出來的蹋订。

  • $? 所有比目標(biāo)新的依賴目標(biāo)的集合。以空格分隔刻伊。

  • $^ 所有的依賴目標(biāo)的集合露戒。以空格分隔椒功。如果在依賴目標(biāo)中有多個重復(fù)的,那個這個變量會去除重復(fù)的依賴目標(biāo)智什,只保留一份动漾。

  • $+ 這個變量很像"$^",也是所有依賴目標(biāo)的集合荠锭。只是它不去除重復(fù)的依賴目標(biāo)旱眯。

  • $* 這個變量表示目標(biāo)模式中"%"及其之前的部分。如果目標(biāo)是"dir/a.foo.b"证九,并且目標(biāo)的模式是"a.%.b"删豺,那么,"$*"的值就是"dir/a.foo"甫贯。這個變量對于構(gòu)造有關(guān)聯(lián)的文件名是比較有較。如果目標(biāo)中沒有模式的定義看蚜,那么"$*"也就不能被推導(dǎo)出叫搁,但是,如果目標(biāo)文件的后綴是 make 所識別的供炎,那么"$*"就是除了后綴的那一部分渴逻。例如:如果目標(biāo)是"foo.c",因為".c"是 make 所能識別的后綴名音诫,所以惨奕,"$*"的值就是"foo"。這個特性是 GNU make 的竭钝,很有可能不兼容于其它版本的 make梨撞,所以,你應(yīng)該盡量避免使用"$*"香罐,除非是在隱含規(guī)則或是靜態(tài)模式中卧波。如果目標(biāo)中的后綴是 make 所不能識別的,那么"$*"就是空值庇茫。

  • $(@D) 表示"$@"的目錄部分(不以斜杠作為結(jié)尾)港粱,如果"$@"值是"dir/foo.o",那么"$(@D)"就是"dir"旦签,而如果"$@"中沒有包含斜杠的話查坪,其值就是"."(當(dāng)前目錄)。

  • $(@F) 表示"$@"的文件部分宁炫,如果"$@"值是"dir/foo.o"偿曙,那么"$(@F)"就是"foo.o"。

  • $(F)羔巢、$(D)遥昧、$(%D)覆醇、$(%F)$(<D)炭臭、$(<F)永脓、$(D)**、**$(F)鞋仍、$(+D)常摧、$(+F)$(?D)威创、$(?F)** 同理分別表示對應(yīng)文件的目錄部分和文件部分落午。

變量賦值

  • = 是最基本的賦值

  • := 是覆蓋之前的值

  • ?= 是如果沒有被賦值過就賦予等號后面的值

  • += 是追加等號后面的值


Makefile 使用函數(shù)

函數(shù)調(diào)用語法

$(<function> <arguments>)
${<function> <arguments>}

字符串處理函數(shù)

  • 字符串替換函數(shù)——subst
$(subst <from>, <to>, <text>)

功能:把字符串<text>中的<from>字符串替換成<to>。

返回:函數(shù)返回被替換過后的字符串肚豺。

  • 模式字符串替換函數(shù)——patsubst
$(patsubst <pattern>, <replacement>, <text>)

功能:查找<text>中的單詞(單詞以"空格"溃斋、"Tab"、"回車"或"換行"分隔)是否符合模式<pattern>吸申,如果匹配的話,則以<replacement>替換梗劫。這里,<pattern>可以包括通配符"%",表示任意長度的字符串截碴。如果<replacement>中也包含"%"梳侨,那么,<replacement>中的這個"%"將是<pattern>中的那個"%"所代表的字符串日丹。(可以用""來轉(zhuǎn)義走哺,以"%"來表示真實含義的"%"字符)

返回:函數(shù)返回被替換過后的字符串。

  • 去空格函數(shù)——strip
$(strip <string>)

功能:去掉<string>字符串中開頭和結(jié)尾的空字符哲虾。

返回:返回被去掉空格的字符串值丙躏。

  • 查找字符串函數(shù)——findstring
$(findstring <find>, <in>)

功能:在字符串<in>中查找<find>字符串。

返回:如果找到束凑,那么返回<find>彼哼,否則返回空字符串。

  • 過濾函數(shù)——filter
$(filter <pattern...>, <text>)

功能:以<pattern>模式過濾<text>字符串中的單詞湘今,保留符合模式<pattern>的單詞敢朱。可以有多個模式摩瞎。

返回:返回符合模式<pattern>的字符串拴签。

  • 反過濾函數(shù)——filter-out
$(filter-out <pattern...>, <text>)

功能:以<pattern>模式過濾<text>字符串中的單詞,去除符合模式<pattern>的單詞旗们◎玖ǎ可以有多個模式。

返回:返回不符合模式<pattern>的字符串上渴。

  • 排序函數(shù)——sort
$(sort <list>)

功能:給字符串<list>中的單詞排序(升序)岸梨。

返回:返回排序后的字符串喜颁。

  • 取單詞函數(shù)——word
$(word <n>, <text>)

功能:取字符串<text>中第<n>個單詞。(從一開始)

返回:返回字符串<text>中第<n>個單詞曹阔。如果<n>比<text>中的單詞數(shù)要大,那么返回空字符串半开。

  • 取單詞串函數(shù)——wordlist
$(wordlist <s>, <e>, <text>)

功能:從字符串<text>中取從<s>開始到<e>的單詞串。<s>和<e>是一個數(shù)字赃份。

返回:返回字符串<text>中從<s>到<e>的單詞字符串寂拆。如果<s>比<text>中的單詞數(shù)要大,那么返回空字符串抓韩。如果<e>大于<text>的單詞數(shù)纠永,那么返回從<s>開始,到<text>結(jié)束的單詞串谒拴。

  • 單詞個數(shù)統(tǒng)計函數(shù)——words
$(words <text>)

功能:統(tǒng)計<text>中字符串中的單詞個數(shù)尝江。

返回:返回<text>中的單詞數(shù)。

  • 首單詞函數(shù)——firstword
$(firstword <text>)

功能:取字符串<text>中的第一個單詞英上。

返回:返回字符串<text>的第一個單詞炭序。

文件名操作函數(shù)

  • 取目錄函數(shù)——dir
$(dir <names...>)

功能:從文件名序列<names>中取出目錄部分。目錄部分是指最后一個反斜杠("/")之前的部分善延。如果沒有反斜杠少态,那么返回"./"城侧。

返回:返回文件名序列<names>的目錄部分易遣。

  • 取文件函數(shù)——notdir
$(notdir <names...>)

功能:從文件名序列<names>中取出非目錄部分。非目錄部分是指最后一個反斜杠("/")之后的部分嫌佑。

返回:返回文件名序列<names>的非目錄部分豆茫。

  • 取后綴函數(shù)——suffix
$(suffix <names...>)

功能:從文件名序列<names>中取出各個文件名的后綴。

返回:返回文件名序列<names>的后綴序列屋摇,如果文件沒有后綴揩魂,則返回空字符串。

  • 取前綴函數(shù)——basename
$(basename <names...>)

功能:從文件名序列<names>中取出各個文件名的前綴部分炮温。

返回:返回文件名序列<names>的前綴序列火脉,如果文件沒有前綴,則返回空字符串柒啤。

  • 加后綴函數(shù)——addsuffix
$(addsuffix <suffix>, <names...>)

功能:把后綴<suffix>加到<names>中的每個單詞后面倦挂。

返回:返回加過后綴的文件名序列。

  • 加前綴函數(shù)——addprefix
$(addprefix <prefix>, <names...>)

功能:把前綴<prefix>加到<names>中的每個單詞前面担巩。

返回:返回加過前綴的文件名序列方援。

  • 連接函數(shù)——join
$(join <list1>, <list2>)

功能:把<list2>中的單詞對應(yīng)地加到<list1>的單詞后面。如果<list1>的單詞個數(shù)要比<list2>的多涛癌,那么犯戏,<list1>中的多出來的單詞將保持原樣送火。如果<list2>的單詞個數(shù)要比<list1>多,那么先匪,<list2>多出來的單詞將被復(fù)制到<list2>中种吸。

返回:返回連接過后的字符串。

foreach函數(shù)

$(foreach <var>, <list>, <text>)

功能:把參數(shù)<list>中的單詞逐一取出放到參數(shù)<var>所指定的變量中,然后再執(zhí)行<text>所包含的表達(dá)式胚鸯。每一次<text>會返回一個字符串,循環(huán)過程中, <text>的所返回的每個字符串會以空格分隔,最后當(dāng)整個循環(huán)結(jié)束時,<text>所返回的每個字符串所組成的整個字符串(以空格分隔)將會是 foreach 函數(shù)的返回值骨稿。

返回:<text>所返回的每個字符串所組成的整個字符串(以空格分隔)。

if函數(shù)

$(if <condition>, <then-part>)
$(if <condition>, <then-part>, <else-part>)

功能:<condition>參數(shù)是 if 的表達(dá)式,如果其返回的為非空字符串姜钳,那么這個表達(dá)式就相當(dāng)于返回真坦冠,于是,<then-part>會被計算哥桥,否則<else-part>會被計算辙浑。

返回:如果<condition>為真(非空字符串),那個<then-part>會是整個函數(shù)的返回值拟糕,如果<condition>為假(空字符串)判呕,那么<else-part>會是整個函數(shù)的返回值,此時如果<else-part>沒有被定義送滞,那么侠草,整個函數(shù)返回空字符串。

所以犁嗅,<then-part>和<else-part>只會有一個被計算边涕。

call函數(shù)

$(call <expression>, <parm1>, <parm2>, <parm3> ...)

功能:當(dāng) make 執(zhí)行這個函數(shù)時,<expression>參數(shù)中的變量褂微,如$(1)功蜓,$(2),$(3)等宠蚂,會被參數(shù)<parm1>式撼,<parm2>,<parm3>依次取代求厕。

返回:<expression>的返回值就是 call 函數(shù)的返回值著隆。

origin函數(shù)

$(origin <variable>)

注意,<variable>是變量的名字呀癣,不應(yīng)該是引用美浦。所以你最好不要在<variable>中使用"$"字符。Origin 函數(shù)會以其返回值來告訴你這個變量的"出生情況"十艾,下面抵代,是 origin函數(shù)的返回值:

  • "undefined"
    如果<variable>從來沒有定義過,origin 函數(shù)返回這個值"undefined"。

  • "default"
    如果<variable>是一個默認(rèn)的定義忘嫉,比如"CC"這個變量荤牍。

  • "environment"
    如果<variable>是一個環(huán)境變量案腺,并且當(dāng) Makefile 被執(zhí)行時,"-e"參數(shù)沒有被打開康吵。

  • "file"
    如果<variable>這個變量被定義在 Makefile 中劈榨。

  • "command line"
    如果<variable>這個變量是被命令行定義的。

  • "override"
    如果<variable>是被 override 指示符重新定義的晦嵌。

  • "automatic"
    如果<variable>是一個命令運行中的自動化變量同辣。

shell函數(shù)

$(shell <shell script>)

功能:shell 函數(shù)也不像其它的函數(shù)。顧名思義惭载,它的參數(shù)應(yīng)該就是操作系統(tǒng) Shell 的命令旱函。它和反引號"`"是相同的功能。

返回:shell 函數(shù)把執(zhí)行操作系統(tǒng)命令后的輸出作為函數(shù)返回描滔。

注意棒妨,這個函數(shù)會新生成一個 Shell 程序來執(zhí)行命令,所以你要注意其運行性能含长,如果你的 Makefile 中有一些比較復(fù)雜的規(guī)則券腔,并大量使用了這個函數(shù),那么對于你的系統(tǒng)性能是有害的拘泞。特別是 Makefile 的隱晦的規(guī)則可能會讓你的 shell 函數(shù)執(zhí)行的次數(shù)比你想像的多得多纷纫。

控制make的函數(shù)

  • error函數(shù)
$(error <text ...>)

產(chǎn)生一個致命的錯誤,make 退出陪腌,<text ...>是錯誤信息辱魁。注意,error 函數(shù)不會在一被使用就會產(chǎn)生錯誤信息偷厦,所以如果你把其定義在某個變量中商叹,并在后續(xù)的腳本中使用這個變量燕刻,那么也是可以的只泼。

  • warning函數(shù)
$(warning <text ...>)

這個函數(shù)很像 error 函數(shù),只是它并不會讓 make 退出卵洗,只是輸出一段警告信息请唱,而 make 繼續(xù)執(zhí)行。


Makefile 自動推導(dǎo)

只要 make 看到一個[.o]文件,它就會自動的把[.c]文件加在依賴關(guān)系中过蹂,并且

$(CC) -c [.c] 

也會被推導(dǎo)出來


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末十绑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子酷勺,更是在濱河造成了極大的恐慌本橙,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脆诉,死亡現(xiàn)場離奇詭異甚亭,居然都是意外死亡贷币,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門亏狰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來役纹,“玉大人,你說我怎么就攤上這事暇唾〈俾觯” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵策州,是天一觀的道長瘸味。 經(jīng)常有香客問我,道長够挂,這世上最難降的妖魔是什么硫戈? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮下硕,結(jié)果婚禮上丁逝,老公的妹妹穿的比我還像新娘。我一直安慰自己梭姓,他們只是感情好霜幼,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著誉尖,像睡著了一般罪既。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铡恕,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天琢感,我揣著相機(jī)與錄音,去河邊找鬼探熔。 笑死驹针,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的诀艰。 我是一名探鬼主播柬甥,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼其垄!你這毒婦竟也來了苛蒲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绿满,失蹤者是張志新(化名)和其女友劉穎臂外,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡漏健,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年辜膝,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漾肮。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡厂抖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出克懊,到底是詐尸還是另有隱情忱辅,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布谭溉,位于F島的核電站墙懂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏扮念。R本人自食惡果不足惜损搬,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望柜与。 院中可真熱鬧巧勤,春花似錦、人聲如沸弄匕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迁匠。三九已至剩瓶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間城丧,已是汗流浹背延曙。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留亡哄,地道東北人枝缔。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像磺平,于是被迫代替她去往敵國和親魂仍。 傳聞我的和親對象是個殘疾皇子拐辽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容