Makefile偽目標(biāo)、多目標(biāo)、靜態(tài)模式與變量基礎(chǔ)用法

一、make的工作方式

  1. 讀入所有的 Makefile。

  2. 讀入被 include 的其它 Makefile。

  3. 初始化文件中的變量。

  4. 推導(dǎo)隱晦規(guī)則,并分析所有規(guī)則。

  5. 為所有的目標(biāo)文件創(chuàng)建依賴關(guān)系鏈。

  6. 根據(jù)依賴關(guān)系,決定哪些目標(biāo)要重新生成。

  7. 執(zhí)行生成命令。

    1-5為第一階段;
    6-7為第二階段;
    

第一階段中,如果定義的變量被使用了,那么,make 會(huì)把其展開(kāi)在使用的位置。但 make 并不會(huì)完全馬上展開(kāi),make 使用的是拖延戰(zhàn)術(shù),如果變量出現(xiàn)在依賴關(guān)系的規(guī)則中,那么僅當(dāng)這條依賴被決定要使用了,變量才會(huì)在其內(nèi)部展開(kāi)。

makefile只有一個(gè)最終目標(biāo),第一條規(guī)則的目標(biāo)為最終目標(biāo)。

二、偽目標(biāo)

偽目標(biāo) PHONY英文釋義:假的,欺騙的。
就是告訴make這個(gè)不是真正意義上的target,make不需要自動(dòng)生成依賴關(guān)系和推導(dǎo)規(guī)則。

.PHONY: clean
clean:
    -rm run *.o

關(guān)鍵字.PHONY告訴make,不管當(dāng)前目錄是否有“clean”這個(gè)文件,clean都是偽目標(biāo)。
如果不加.PHONY,恰好存在名為clean文件時(shí),執(zhí)行make clean就會(huì)出現(xiàn)。

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make clean
make: `clean' is up to date.

三、多目標(biāo)

需要生成多個(gè)可執(zhí)行文件的做法。
使用偽目標(biāo)的方法,給偽目標(biāo)指定所依賴的文件。

all: main hello test
.PHONY: all
main:
    gcc -o main main.c
hello:
    gcc -o hello hello.c
test:
    gcc -o test test.c
.PHONY: clean
clean:
    rm main hello test

運(yùn)行結(jié)果:

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make all
gcc -o main main.c
gcc -o hello hello.c
gcc -o test test.c

生成3個(gè)可執(zhí)行文件,只需要一個(gè)make all命令。

同時(shí)也可以使用靜態(tài)模式來(lái)解決多目標(biāo)的問(wèn)題。

四、靜態(tài)模式

語(yǔ)法:
<targets ...>: <target-pattern>: <prereq-patterns ...>
<commands>
....
targets 定義了一系列的目標(biāo)文件,可以有通配符。是目標(biāo)的一個(gè)集合。
target-parrtern 是指明了 targets 的模式,也就是的目標(biāo)集模式。
prereq-parrterns 是目標(biāo)的依賴模式,它對(duì) target-parrtern 形成的模式再進(jìn)行一次依賴目標(biāo)的定義。

專業(yè)術(shù)語(yǔ)看得也是懵懵的。

“$<”和“@”則是自動(dòng)化變量,“\<”為依賴目標(biāo)集和“$@”則是目標(biāo)集。

target = main.o hello.o test.o
all : $(target)
$(target):%.o: %.c
    gcc -c $< -o $@ 

運(yùn)行結(jié)果:

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make all
gcc -c main.c -o main.o 
gcc -c hello.c -o hello.o   
gcc -c test.c -o test.o 

解讀下,all這個(gè)目標(biāo)依賴于target這個(gè)變量?,F(xiàn)在就是打算把依賴的文件修改了,單純懶得重新寫(xiě)依賴關(guān)系。直接在原來(lái)依賴關(guān)系的基礎(chǔ)上修改下。%.o表示當(dāng)前目錄下所有.o文件,類似shell中*.o表示所有文件一樣。%.o: %.c無(wú)非表示所有.o文件文件名后綴修改為.c罷了。
最終顯示出來(lái)的結(jié)果,

target = main.o hello.o test.o
all : $(target)
$(target) : main.c hello.c test.c
    gcc -c $< -o $@

$< 從那些依賴文件中讀?。╩ain.c hello.c test.c這些文件),$@從target這個(gè)變量賦值的多目標(biāo)中讀取。

再配合函數(shù)filter使用,就更加靈活了。filter英文釋義為過(guò)濾器。
filter過(guò)濾函數(shù)用法
$(filter <pattern...>,<text>)
名稱:過(guò)濾函數(shù)——filter。
功能:以<pattern>模式過(guò)濾<text>字符串中的單詞,保留符合模式<pattern>的單詞??梢杂卸鄠€(gè)模式。
返回:返回符合模式<pattern>的字串。

target = main.o hello.o test.o other.a some.so
all : 
    @echo $(filter %.o %.a, $(target))

運(yùn)行結(jié)果:

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make all
main.o hello.o test.o other.a

filter函數(shù)將target變量中包含的所有.o .a文件保留其他文件過(guò)濾。

五、變量的使用

引用變量:(變量名) 使用\字符: $$

變量中的變量
普通定義

VAR1 = $(VAR2)
VAR2 = 666
test:
    @echo $(VAR1)

輸出VAR1的值為666,但是這種方式也有缺點(diǎn),在使用遞歸定義時(shí)出現(xiàn)循環(huán)引用。還有就是如果在變量中使用函數(shù),那么,這種方式會(huì)讓我們的 make 運(yùn)行時(shí)非常慢,更糟糕的是,他會(huì)使用得兩個(gè) make 的函數(shù)“wildcard”和“shell”發(fā)生不可預(yù)知的錯(cuò)誤。因?yàn)槟悴粫?huì)知道這兩個(gè)函數(shù)會(huì)被調(diào)用多少次。

遞歸定義

VAR1 = $(VAR2)
VAR2 = $(VAR1)
test:
    @echo $(VAR1)

運(yùn)行結(jié)果:

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make test
Makefile:1: *** Recursive variable `VAR1' references itself (eventually).  Stop.

使用 :=操作符進(jìn)行賦值,就不會(huì)報(bào)上述錯(cuò)誤。

VAR1 := $(VAR2)
VAR2 := $(VAR1)
test:
    @echo $(VAR1)

“:=”操作符作用?與“=”有啥區(qū)別?

使用“=”操作符

VAR1 = 666
VAR2 = $(VAR1) 233
VAR1 = 555
test:
    @echo $(VAR1)
    @echo $(VAR2)

運(yùn)行結(jié)果:

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make test
555
555 233

再次聲明VAR1變量,原先的值會(huì)被覆蓋。并且VAR2中引用VAR1的變量是makefile展開(kāi)后的最終值。

使用“:=”操作符

VAR1 := 666
VAR2 := $(VAR1) 233
VAR1 := 555
test:
    @echo $(VAR1)
    @echo $(VAR2)

運(yùn)行結(jié)果:

root@chenwr-pc:/home/workspace/my_workspace/study/makefile# make test
555
666 233

值得一提的是,這種方法,前面的變量不能使用后面的變量,只能使用前面已定義好了的變量。因此VAR2中的引用的VAR1只能使用之前定義賦值的值。

如何定義一個(gè)值為空格的變量?

null :=
space := $(null) #  
test:
    @echo hello$(space)world

運(yùn)行結(jié)果:

hello world

$(null) #注意中間有個(gè)空格

“?=”操作符的作用
變量之前定義后,則不執(zhí)行這條語(yǔ)句,如果變量沒(méi)有被定義,則進(jìn)行賦值。

VAR1 := 666
VAR1 ?= 777
test:
    @echo $(VAR1)

輸出:666

VAR1 :=
VAR1 ?= 777
test:
    @echo $(VAR1)

輸出:空

VAR1 ?= 777
test:
    @echo $(VAR1)

輸出:777

大致歸納一下

  • = 是最基本的賦值
  • := 是覆蓋之前的值 (“:=”表示變量的值決定于它在makefile中的位置,而不是整個(gè)makefile展開(kāi)后的最終值。)
  • ?= 是如果沒(méi)有被賦值過(guò)就賦予等號(hào)后面的值
  • += 是添加等號(hào)后面的值
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 來(lái)自陳浩的一片老文,但絕對(duì)營(yíng)養(yǎng)。 示例工程:3 個(gè)頭文件*.h,和 8 個(gè) C 文件*.c。 初 編譯過(guò)程,源文件...
    周筱魯閱讀 4,779評(píng)論 0 17
  • makefile關(guān)系到整個(gè)工程的編譯規(guī)則,一個(gè)工程中的源文件不計(jì)其數(shù),按其類型、功能、模塊分別放在若干的目錄當(dāng)中,...
    Joe_HUST閱讀 1,977評(píng)論 0 3
  • 1.Makefile規(guī)范 target 這 一 個(gè) 或 多 個(gè) 的 目 標(biāo) 文 件 依 賴 于prerequisi...
    G風(fēng)閱讀 2,081評(píng)論 0 3
  • makefile 介紹 make命令執(zhí)行時(shí),需要一個(gè) makefile 文件,以告訴make命令如何去編譯和鏈接程...
    Stan_Z閱讀 1,724評(píng)論 2 15
  • 愛(ài)要大膽說(shuō)出來(lái),不然她怎么會(huì)知道你的心意。女孩子都不是很喜歡被動(dòng)的男人,如果總是想等待女孩主動(dòng)開(kāi)口的話,那么你或許...
    左小祺閱讀 422評(píng)論 1 12

友情鏈接更多精彩內(nèi)容