《跟我一起學(xué)Makefile》學(xué)習(xí)筆記

最近兩天花時(shí)間讀了一下陳皓老師的《跟我一起寫Makefile》,這篇文章非常地詳細(xì)地介紹了make的用法以及Makefile的常用寫法,感謝耗子老師~本文是在學(xué)習(xí)陳皓的《跟我一起寫Makefile》的過(guò)程中,對(duì)一些比較實(shí)用的內(nèi)容做的筆記绢记。

Makefile介紹:

  • Makefile的規(guī)則

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

    1.target可以是目標(biāo)文件、可執(zhí)行文件炉旷、偽目標(biāo)

    2.prerequisites是生成target所需要的文件或目標(biāo)

    3.command是需要執(zhí)行的命令窘行,其所在行必須以一個(gè)tab開始

    4.核心規(guī)則:如果prerequisites中有一個(gè)或以上的文件比target更新的話,那么command所定義的命令就會(huì)被執(zhí)行

  • make會(huì)在makefile里尋找第一個(gè)目標(biāo)文件,如果找到則將其作為最終的目標(biāo)文件

  • makefile的變量是一個(gè)字符串,類似于C語(yǔ)言中的宏

  • make具有自動(dòng)推導(dǎo)的功能罐盔,比如有一個(gè)目標(biāo)是any.o,那么any.c就會(huì)是any.o的依賴文件(如果我們沒(méi)有定義這個(gè)規(guī)則)。還有下面這個(gè)例子:

    objects = main.o first.o second.o \
          third.o end.o
    
    edit : $(objects)
        cc -o edit $(objects)
    
  • makefile中只有行注釋,使用'#'字符

  • include關(guān)鍵字可以把別的makefile包含進(jìn)來(lái):
    include filename;
    如果文件沒(méi)有指定絕對(duì)或相對(duì)路徑,make會(huì)在當(dāng)前目錄下尋找,然后試圖在指定的編譯參數(shù)里尋找包含路徑

書寫規(guī)則:

  • 在makefile中,'-'號(hào)一般用來(lái)表示出錯(cuò)時(shí)不要退出,繼續(xù)執(zhí)行

  • make支持三個(gè)通配符:"*" "?" "~"

  • 如果想要讓通配符在變量中展開,比如objects是所有.o文件名的集合,可以這樣:

    objects:=$(wildcard \*.o)

  • Makefile中的特殊變量VPATH用來(lái)添加文件路徑,多個(gè)路徑間以:號(hào)分隔六孵,例如:
    VPATH = src:../headers

全小寫的vpath是make的關(guān)鍵字劫窒,它可以指定不同文件在不同的目錄中主巍。其用法如下:

  1. vpath pattern directories 為符合pattern模式的文件指定搜索目錄directories
  2. vpath pattern 清除符合模式pattern的文件的搜索目錄
  3. vpath 清除所有已經(jīng)設(shè)置了的文件搜索目錄

vpath中的pattern需要包含%,比如:
vpath %.h ../headers 要求make在"../headers"目錄下搜索所有頭文件(如果當(dāng)前目錄沒(méi)有的話)

  • .PHONY是一個(gè)特殊標(biāo)記,顯式地指出一個(gè)目標(biāo)是偽目標(biāo),這樣make不會(huì)認(rèn)為其是一個(gè)文件去尋找其生成規(guī)則了
  • 目標(biāo)和偽目標(biāo)都可以成為依賴挪凑,比如:
.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff
    rm program

cleanobj :
    rm *.o
cleandiff :
    rm *.diff
  • $@這個(gè)變量表示著目前規(guī)則中所有目標(biāo)的集合

  • 靜態(tài)模式的語(yǔ)法:

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

    ...

    targets定義一系列目標(biāo),可以有通配符,是目標(biāo)的一個(gè)集合

    target-pattern是指明targets的模式,也就是目標(biāo)集模式

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

    例子:

    objects = foo.o bar.o
    
    all: $(objects)
    
    $(objects): %.o : %.c
    $(CC) -c $(CFLAGS) $&lt; -o $@
    

    其中$<表示所有依賴的目標(biāo)集(foo.c bar.c), $@表示所有的目標(biāo)集(foo.o bar.o)

書寫命令:

  • make通常會(huì)將執(zhí)行的命令輸出到屏幕上,在命令前加@可以阻止這個(gè)輸出
  • 如果有多條命令并且后面的命令需要用到前面的接鍋,需要卸載同一行上檬果,之間用;隔開
    例如:
    exec:
    cd /home/david
    pwd
    
    exec:
    cd /home/david; pwd
    

執(zhí)行第一個(gè)exec, pwd打印當(dāng)前目錄,第二個(gè)是/home/david

  • 如果我們有一個(gè)子目錄叫subdir,在總的makefile里可以這樣寫:
    subsys:
    cd subdir; $(MAKE)
    
    或者是:
    subsys:
    $(MAKE) -C subdir
    
  • 如果要給下層makefile傳遞參數(shù),可以這樣:
export var=value

或者:

var=value
export

如果要傳遞所有變量,只需要export就可以了选脊。如果要取消變量,使用unexport恳啥。

  • SHELL和MAKEFLAGS這兩個(gè)變量不管是否export,都要傳遞到下層的makefile中去
  • make的-w參數(shù)在嵌套執(zhí)行中比較有用,作用是讓我們看到當(dāng)前的工作目錄.使用-C參數(shù)時(shí)-w會(huì)自動(dòng)打開
  • make可以將相同的命令序列定義為一個(gè)變量:
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

使用變量

  • 如果要在Makefile中使用"$"字符,需要用"$$"表示
  • 定義變量可以直接用=,也可以用:=钝的。兩者的區(qū)別在于:=使用時(shí),- - 只能用已經(jīng)定義號(hào)的變量,而不是在使用時(shí)再賦值
    ?=操作符表示如果左邊的變量未定義時(shí)將右值賦給它,否則什么也不做.例如:
nullstr:=
space:=$(nullstr) #end of the line

這里需要注意的是,nullstr是空變量,space這行中,最后的)和#之間有一個(gè)空格,所以space被定義成了空格硝桩。

  • 變量值的替換:
    ${var:a=b}表示將var中以a結(jié)尾的內(nèi)容替換成b碗脊,比如:
foo := a.o b.o c.o
bar := $(foo:.o=.c)

那么${bar} = a.c b.c c.c,上面一句等同于:

bar := ${foo:%.o=%.c}

  • +=號(hào)左邊的變量如果沒(méi)有定義過(guò),等同于=
  • 如果一個(gè)變量在前面有定義,那么同一文件里賦值給該變量的=號(hào)會(huì)繼承前一次操作的賦值符,也就是=或:=

使用用條件判斷

  • 條件表達(dá)式的語(yǔ)法:
    conditional-directive

text-if-true

endif

以及:

conditional-directive

text-if-true

else

text-if-false

endif

其中conditional-directive表示條件關(guān)鍵字,包括:

ifeq (arg1, arg2)
ifneq (arg1, arg2)
ifdef var
ifndef var

需要注意的是,ifdef只是測(cè)試一個(gè)變量是否有值,并不會(huì)擴(kuò)展它。也就是說(shuō)如果你定義了一個(gè)空的變量empvar,ifdef empvar 返回true

使用函數(shù)

  • 函數(shù)調(diào)用語(yǔ)法:

    $(function args)

    函數(shù)和參數(shù)之間有空格害碾,多個(gè)參數(shù)之間用,隔開

  • 字符串操作函數(shù)

$(subst from,to,text)

將text中的from替換為to

$(patsubst pattern,replacement,text)

查找text中的單詞是否符合模式pattern,如果匹配則以replacement替換.pattern可以包括通配符%表示任意長(zhǎng)度的字符串.如果replace中也包含%,那么pattern中%代表的字符串和replace中一樣慌随,返回替換過(guò)的字符串

$(strip string)

去掉string中開頭和結(jié)尾的空字符, 返回去掉空格的字符串

$(findstring find,in)

在in中查找find字符串,找到則返回find,否則返回空字符串

$(filter pattern...,text)

以pattern模式過(guò)濾text中的單詞,返回符合模式的字符串

$(filter-out pattern..., text)

與filter相反

$(sort list)

給list中的單詞按照升序排序,會(huì)去掉重復(fù)單詞

$(word n,text)

取出text中的第n個(gè)單詞

$(wordlist ss,e,text)

從text中取出從ss到e的單詞串,b和e是數(shù)字

$(words text)

統(tǒng)計(jì)并返回text中的單詞數(shù)

$(firstword text)

取出text中的第一個(gè)單詞

文件名操作函數(shù)

$(dir names...)

從names中取出目錄部分

$(notdir names...)

和dir相反

$(suffix name...)

從names中取出各個(gè)文件名的后綴

$(basename names...)

從names中取出哥哥文件的前綴

$(addsuffix suffix,names...)

把后綴suffix加到names中每個(gè)單詞后面

$(addprefix prefix,names...)

把prefix加到names中每個(gè)單詞前面

$(join list1,list2)

把list2中的單詞加到list1的對(duì)應(yīng)的單詞后面

foreach 函數(shù)

$(foreach var,list,text)

把參數(shù)list中的單詞逐一取出放到var指定的變量中,然后執(zhí)行text所包含的表達(dá)式, 其中的var作用于僅存在于foreach中

if函數(shù)

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

call函數(shù)

$(call expression;,param1;,param2;,param3;...)

origin函數(shù)

$(origin var)

origin函數(shù)告訴我們var是在哪里定義的,其返回值包括:undefined,default,environment,file,command line,override,automatic

  • shell函數(shù)

shell函數(shù)和"`"是相同的功能

  • 控制make的函數(shù)

error text

產(chǎn)生致命的錯(cuò)誤信息

warning text

產(chǎn)生警告信息

隱含規(guī)則

自動(dòng)化變量
$@: 表示規(guī)則中的目標(biāo)文件集笛园。在模式規(guī)則中研铆,如果有多個(gè)目標(biāo),那么凶赁,“$@”就是匹配于目標(biāo)中模式定義的集合虱肄。
$%: 僅當(dāng)目標(biāo)是函數(shù)庫(kù)文件中交煞,表示規(guī)則中的目標(biāo)成員名攻冷。例如偶垮,如果一個(gè)目標(biāo)是“foo.a(bar.o)”,那么“$%”是“bar.o”丧蘸,“$@”就是“foo.a”渡紫。如果目標(biāo)不是函數(shù)庫(kù)文件(Unix 下是[.a],Windows 下是[.lib])侈沪,那么其值為空。

$<: 依賴目標(biāo)中的第一個(gè)目標(biāo)名字晚凿。如果依賴目標(biāo)是以模式(即“%”)定義的亭罪,那么“$<;”將是符合模式的一系列的文件集。注意歼秽,其是一個(gè)一個(gè)取出來(lái)的应役。

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

$^: 所有的依賴目標(biāo)的集合箩祥。以空格分隔院崇。如果在依賴目標(biāo)中有多個(gè)重復(fù)的,那個(gè)這個(gè)變量會(huì)去除重復(fù)的依賴目標(biāo)袍祖,只保留一份底瓣。

$+: 這個(gè)變量很像“$^”,也是所有依賴目標(biāo)的集合蕉陋。只是它不去除重復(fù)的依賴目標(biāo)。

$*: 這個(gè)變量表示目標(biāo)模式中“%”及其之前的部分垦梆。如果目標(biāo)是“dir/a.foo.b”杠氢,并且目標(biāo)的模式是“a.%.b”,那么,“$”的值就是“dir/a.foo”晃琳。這個(gè)變量對(duì)于構(gòu)造有關(guān)聯(lián)的文件名是比較有較围段。如果目標(biāo)中沒(méi)有模式的定義灸芳,那么“$”也就不能被推導(dǎo)出,但是,如果目標(biāo)文件的后綴是make 所識(shí)別的寻定,那么“$”就是除了后綴的那一部分。例如:如果目標(biāo)是“foo.c”,因?yàn)椤?c”是make 所能識(shí)別的后綴名处硬,所以件豌,“$”的值就是“foo”。這個(gè)特性是GNU make 的惫谤,很有可能不兼容于其它版本的make险污,所以窖式,你應(yīng)該盡量避免使用“$”阁簸,除非是在隱含規(guī)則或是靜態(tài)模式中饶米。如果目標(biāo)中的后綴是make所不能識(shí)別的匈棘,那么“$”就是空值队秩。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鸟蟹,一起剝皮案震驚了整個(gè)濱河市建钥,隨后出現(xiàn)的幾起案子欲险,更是在濱河造成了極大的恐慌然低,老刑警劉巖刚照,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異薄风,居然都是意外死亡困肩,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)例证,“玉大人漠秋,你說(shuō)我怎么就攤上這事÷悖” “怎么了求晶?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵档插,是天一觀的道長(zhǎng)则剃。 經(jīng)常有香客問(wèn)我娄柳,道長(zhǎng)蕉朵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任敷存,我火速辦了婚禮墓造,結(jié)果婚禮上堪伍,老公的妹妹穿的比我還像新娘锚烦。我一直安慰自己,他們只是感情好帝雇,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布涮俄。 她就那樣靜靜地躺著,像睡著了一般尸闸。 火紅的嫁衣襯著肌膚如雪彻亲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天吮廉,我揣著相機(jī)與錄音苞尝,去河邊找鬼。 笑死宦芦,一個(gè)胖子當(dāng)著我的面吹牛宙址,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播调卑,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼抡砂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼大咱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起注益,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤碴巾,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后丑搔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厦瓢,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年啤月,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了旷痕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡顽冶,死狀恐怖欺抗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情强重,我是刑警寧澤绞呈,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站间景,受9級(jí)特大地震影響佃声,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜倘要,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一圾亏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧封拧,春花似錦志鹃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至捧杉,卻和暖如春陕见,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背味抖。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工评甜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仔涩。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓忍坷,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子承匣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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

  • 來(lái)自陳浩的一片老文蓖乘,但絕對(duì)營(yíng)養(yǎng)。 示例工程:3 個(gè)頭文件*.h韧骗,和 8 個(gè) C 文件*.c嘉抒。 初 編譯過(guò)程,源文件...
    周筱魯閱讀 4,683評(píng)論 0 17
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理袍暴,服務(wù)發(fā)現(xiàn)些侍,斷路器,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • makefile的規(guī)則 組成 target prerequisites commandtarget這一個(gè)或多個(gè)的目...
    Neucrack閱讀 2,746評(píng)論 0 3
  • makefile關(guān)系到整個(gè)工程的編譯規(guī)則政模,一個(gè)工程中的源文件不計(jì)其數(shù)岗宣,按其類型、功能淋样、模塊分別放在若干的目錄當(dāng)中耗式,...
    Joe_HUST閱讀 1,872評(píng)論 0 3
  • @(linux 編程)[開發(fā)技能, 工具使用] What is GNU Make Make 是控制工程中通過(guò)源碼生...
    orientlu閱讀 11,320評(píng)論 0 26