0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

makefile都有哪些語(yǔ)法?

xCb1_yikoulinux ? 來源:一口Linux ? 作者:一口Linux ? 2022-05-06 16:07 ? 次閱讀

Make簡(jiǎn)介:

  • 工程管理器,顧名思義,是指管理較多的文件
  • Make工程管理器也就是個(gè)“自動(dòng)編譯管理器”,這里的“自動(dòng)”是指它能夠根據(jù)文件時(shí)間戳自動(dòng)發(fā)現(xiàn)更新過的文件而減少編譯的工作量,同時(shí),它通過讀入Makefile文件的內(nèi)容來執(zhí)行大量的編譯工作
  • ==Make將只編譯改動(dòng)的代碼文件,而不用完全編譯。==

會(huì)不會(huì)寫makefile,從一個(gè)側(cè)面說明了一個(gè)人是否具備完成大型工程的能力,makefile關(guān)系到了整個(gè)工程的編譯規(guī)則。一個(gè)工程中的源文件不計(jì)數(shù),其按類型、功能、模塊分別放在若干個(gè)目錄中,makefile定義了一系列的規(guī)則來指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進(jìn)行更復(fù)雜的功能操作,因?yàn)閙akefile就像一個(gè)Shell腳本一樣,其中也可以執(zhí)行操作系統(tǒng)的命令。makefile帶來的好處就是——“自動(dòng)化編譯”,一旦寫好,只需要一個(gè)make命令,整個(gè)工程完全自動(dòng)編譯,極大的提高了軟件開發(fā)的效率

Makefile基本結(jié)構(gòu):

  • Makefile是Make讀入的唯一配置文件
    • 由make工具創(chuàng)建的目標(biāo)體(target),通常是目標(biāo)文件或可執(zhí)行文件
    • 要?jiǎng)?chuàng)建的目標(biāo)體所依賴的文件(dependency_file)
    • 創(chuàng)建每個(gè)目標(biāo)體時(shí)需要運(yùn)行的命令(command)

==注意:== 命令行前面必須是一個(gè)”**==TAB==** 鍵”,否則編譯錯(cuò)誤為:*** missing separator. Stop.

例如:c9dd6d18-ccef-11ec-bce3-dac502259ad0.png

Makefile格式:

target:dependcy_files
command

target //目標(biāo) : target也就是一個(gè)目標(biāo)文件,可以是Object File,也可以是執(zhí)行文件。還可以是一個(gè)標(biāo)簽(Label)

dependcy_files //生成目標(biāo)所要的目標(biāo)文件: dependcy_files 就是,要生成那個(gè)target所需要的文件或是目標(biāo)。

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

這是一個(gè)文件的依賴關(guān)系,也就是說,target這一個(gè)或多個(gè)的目標(biāo)文件依賴于dependcy_files中的文件,其生成規(guī)則定義在command中。**==說白一點(diǎn)就是說,dependcy_files中如果有一個(gè)以上的文件比target文件要新的話,command所定義的命令就會(huì)被執(zhí)行。這就是Makefile的規(guī)則。也就是Makefile中最核心的內(nèi)容。==**

==【注】==:在看別人寫的Makefile文件時(shí),你可能會(huì)碰到以下三個(gè)變量:$@$^,$<代表的意義分別是:

他們?nèi)齻€(gè)是十分重要的三個(gè)變量,所代表的含義分別是:

**$@:目標(biāo)文件,$^: 所有的依賴文件,$<:第一個(gè)依賴文件**。

這個(gè)變量的問題,我們?cè)谙旅胬^續(xù)講解。

復(fù)雜一些的例子:

sunq:kang.oyul.o
gcckang.oyul.o-osunq
kang.o:kang.ckang.h
gcc-Wall-O-g-ckang.c-okang.o
yul.o:yul.cyul.h
gcc-Wall-O-g-cyul.c-oyul.o
clean:
rm*.otest

注釋:—Wall : 表示允許發(fā)出gcc所有有用的報(bào)警信息—c : 只是編譯不連接,生成目標(biāo)文件" .o "—o file : 表示把輸出文件輸出到file里

我們可以把這個(gè)內(nèi)容保存在文件為“Makefile”或“makefile”的文件中,然后在該目錄下直接輸入命令“make”就可以生成執(zhí)行文件sunq。如果要?jiǎng)h除執(zhí)行文件和所有的中間目標(biāo)文件,那么,只要簡(jiǎn)單地執(zhí)行一下“make clean”就可以了。在這個(gè)makefile中,==目標(biāo)文件(target)包含:執(zhí)行文件sunq和中間目標(biāo)文件(*.o),依賴文件(prerequisites)就是冒號(hào)后面的那些 .c 文件和 .h文件。每一個(gè) .o 文件都有一組依賴文件,而這些 .o 文件又是執(zhí)行文件 sunq的依賴文件。依賴關(guān)系的實(shí)質(zhì)上就是說明了目標(biāo)文件是由哪些文件生成的==,換言之,目標(biāo)文件是哪些文件更新的。

在定義好依賴關(guān)系后,后續(xù)的那一行定義了如何生成目標(biāo)文件的操作系統(tǒng)命令,**==一定要以一個(gè)Tab鍵作為開頭==**。記住,make并不管命令是怎么工作的,他只管執(zhí)行所定義的命令。make會(huì)比較targets文件和dependcy_files文件的修改日期,如果dependcy_files文件的日期要比targets文件的日期要新,或者target不存在的話,那么,make就會(huì)執(zhí)行后續(xù)定義的命令。

1. make是如何工作的

大多數(shù)的make都支持“makefile”和“Makefile”這兩種默認(rèn)文件名,你可以使用別的文件名來書寫Makefile,比如:“Make.Linux”,“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“--file”參數(shù),如:**make -f Make.Linuxmake --file Make.AIX**。

在默認(rèn)的方式下,也就是我們只輸入make命令。那么,

  1. make會(huì)在當(dāng)前目錄下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它會(huì)找文件中的第一個(gè)目標(biāo)文件(target),在上面的例子中,他會(huì)找到“sunq”這個(gè)文件,并把這個(gè)文件作為最終的目標(biāo)文件。
  3. 如果sunq文件不存在,或是sunq所依賴的后面的 .o文件的文件修改時(shí)間要比sunq這個(gè)文件新,那么,他就會(huì)執(zhí)行后面所定義的命令來生成sunq這個(gè)文件。
  4. 如果sunq所依賴的.o文件不存在,那么make會(huì)在當(dāng)前文件中找目標(biāo)為.o文件的依賴性,如果找到則再根據(jù)那一個(gè)規(guī)則生成.o文件。(這有點(diǎn)像一個(gè)堆棧的過程)
  5. 當(dāng)然,你的C文件和H文件是存在的啦,于是make會(huì)生成 .o 文件,然后再用 .o文件聲明make的終極任務(wù),也就是執(zhí)行文件sunq了。

這就是整個(gè)make的依賴性,make會(huì)一層又一層地去找文件的依賴關(guān)系,直到最終編譯出第一個(gè)目標(biāo)文件。在找尋的過程中,如果出現(xiàn)錯(cuò)誤,比如最后被依賴的文件找不到,那么make就會(huì)直接退出,并報(bào)錯(cuò),而對(duì)于所定義的命令的錯(cuò)誤,或是編譯不成功,make根本不理。make只管文件的依賴性,即,如果在我找了依賴關(guān)系之后,冒號(hào)后面的文件還是不在,那么對(duì)不起,我就不工作啦。

make工作時(shí)的執(zhí)行步驟入下:(想來其它的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步為第一個(gè)階段,6-7為第二個(gè)階段。第一個(gè)階段中,如果定義的變量被使用了,那么,make會(huì)把其展開在使用的位置。但make并不會(huì)完全馬上展開,make使用的是拖延戰(zhàn)術(shù),如果變量出現(xiàn)在依賴關(guān)系的規(guī)則中,那么僅當(dāng)這條依賴被決定要使用了,變量才會(huì)在其內(nèi)部展開。

2.makefile文件中的依賴關(guān)系理解

假設(shè)當(dāng)前工程目錄為object/,該目錄下有6個(gè)文件,分別是:main.c、abc.c、xyz.c、abc.h、xyz.h和Makefile。其中main.c包含頭文件abc.h和xyz.h,abc.c包含頭文件abc.h,xyz.c包含頭文件xyz.h,而abc.h又包含了xyz.h。它們的依賴關(guān)系如圖。c9f7b8a8-ccef-11ec-bce3-dac502259ad0.pngMakefile應(yīng)該寫成這個(gè)樣子(假設(shè)生成目標(biāo)main):

main:main.oabc.oxyz.o
gccmain.oabc.oxyz.o-omain
main.o:main.cabc.hxyz.h
gcc-cmain.c–omain.o-g
abc.o:abc.cabc.hxyz.h
gcc-cabc.c–oabc.o-g
xyz.o:xyz.cxyz.h
gcc-cxyz.c-oxyz.o-g
.PHONY:clean
clean:
rmmainmain.oabc.oxyz.o-f

3. Makefile書寫規(guī)則

規(guī)則包含兩個(gè)部分,一個(gè)是==依賴關(guān)系==,一個(gè)是==生成目標(biāo)的方法==。

在Makefile中,規(guī)則的順序是很重要的,因?yàn)椋?*==Makefile中只應(yīng)該有一個(gè)最終目標(biāo)==,其它的目標(biāo)都是被這個(gè)目標(biāo)所連帶出來的,所以 ==一定要讓make知道你的最終目標(biāo)是什么== 。一般來說,定義在Makefile中的目標(biāo)可能會(huì)有很多,但是第一條規(guī)則中的目標(biāo)將被確立為最終的目標(biāo)==如果第一條規(guī)則中的目標(biāo)有很多個(gè),那么,第一個(gè)目標(biāo)會(huì)成為最終的目標(biāo)==。make所完成的也就是這個(gè)目標(biāo)。**

3.1 規(guī)則舉例

foo.o:foo.cdefs.h#foo模塊
cc-c-gfoo.c

看到這個(gè)例子,各位應(yīng)該不是很陌生了,前面也已說過,foo.o是我們的目標(biāo),foo.c和defs.h是目標(biāo)所依賴的源文件,而只有一個(gè)命令“cc -c -g foo.c”(以Tab鍵開頭)。這個(gè)規(guī)則告訴我們兩件事

  1. 文件的依賴關(guān)系,foo.o依賴于foo.c和defs.h的文件,如果foo.c和defs.h的文件日期要比f(wàn)oo.o文件日期要新,或是foo.o不存在,那么依賴關(guān)系發(fā)生。

  2. 如果生成(或更新)foo.o文件。也就是那個(gè)cc命令,其說明了,如何生成foo.o這個(gè)文件。(當(dāng)然foo.c文件include了defs.h文件)

4. Makefile 基礎(chǔ)的使用

接下來我們做個(gè)實(shí)例來學(xué)習(xí)下怎么寫 Makefile

寫兩個(gè)c程序ca0bc5be-ccef-11ec-bce3-dac502259ad0.pngca1beac0-ccef-11ec-bce3-dac502259ad0.png寫一個(gè)head.h 頭文件,用來聲明上面的函數(shù)ca34810c-ccef-11ec-bce3-dac502259ad0.png

寫一個(gè)main程序ca453c04-ccef-11ec-bce3-dac502259ad0.pngca564f80-ccef-11ec-bce3-dac502259ad0.png

如果這樣的方式寫,要是改動(dòng)其中文件的時(shí)候,若文件過多,會(huì)很麻煩。

所以Makefile的使用會(huì)帶來很大的驚喜。

Makefile

test:fun1.ofun2.omain.o
gccfun1.ofun2.omain.o-otest
fun2.o:fun2.c
gcc-c-Wallfun2.c-ofun2.o
fun1.o:fun1.c
gcc-c-Wallfun1.c-ofun1.o
main.o:main.c
gcc-c-Wallmain.c-omain.o

Makefile內(nèi)部流程ca67b27a-ccef-11ec-bce3-dac502259ad0.pngca7e0200-ccef-11ec-bce3-dac502259ad0.png若我要改動(dòng)其中的c文件 改動(dòng)fun2.cca921934-ccef-11ec-bce3-dac502259ad0.png改動(dòng)好后,再make 發(fā)現(xiàn)只有fun2.c被重新生成fun2.o ?,因?yàn)閒un2.o是新生成的,也要新生成 test。caac3904-ccef-11ec-bce3-dac502259ad0.png結(jié)果cabdcfa2-ccef-11ec-bce3-dac502259ad0.pngMakefile后文件夾內(nèi)會(huì)生成很多中間文件

cad09b8c-ccef-11ec-bce3-dac502259ad0.png我們需要清理時(shí)呢,我們 ==往往通過make相關(guān)命令來清理== ,而不是rm一個(gè)一個(gè)刪除。

clean:
rm*.otest

cae629e8-ccef-11ec-bce3-dac502259ad0.pngmake + 目標(biāo)名cb0076ea-ccef-11ec-bce3-dac502259ad0.png這樣中間文件都被清理了cb201324-ccef-11ec-bce3-dac502259ad0.png偽目標(biāo):肯定會(huì)被執(zhí)行的文件,重名了cb3eb82e-ccef-11ec-bce3-dac502259ad0.png重名后,發(fā)現(xiàn)clean不工作了,默認(rèn)為它沒被改動(dòng),所以它不工作。如何避免這個(gè)問題呢?

在Makefile中加.PHONY:command
==.PHONY:隱含說明==“.PHONY”表示,clean是個(gè)偽目標(biāo)文件。

.PHONY:clean

cb59977a-ccef-11ec-bce3-dac502259ad0.png這樣就不會(huì)被重名耽誤運(yùn)行了cb6c1bc0-ccef-11ec-bce3-dac502259ad0.png清空目標(biāo)文件的規(guī)則每個(gè)Makefile中都應(yīng)該寫一個(gè)清空目標(biāo)文件(.o和執(zhí)行文件)的規(guī)則,這不僅便于重編譯,也很利于保持文件的清潔。一般的風(fēng)格都是:

clean:

rmedit$(objects)

更為穩(wěn)健的做法是:

.PHONY:clean
clean:
-rmedit$(objects)

前面說過,.PHONY意思表示clean是一個(gè)“偽目標(biāo)”,。而在rm命令前面加了一個(gè)小減號(hào)的意思就是,也許某些文件出現(xiàn)問題,但不要管,繼續(xù)做后面的事。 當(dāng)然,clean的規(guī)則不要放在文件的開頭,不然,這就會(huì)變成make的默認(rèn)目標(biāo),相信誰(shuí)也不愿意這樣。不成文的規(guī)矩是——“clean從來都是放在文件的最后”。

3.makefile文件中的依賴關(guān)系理解

假設(shè)當(dāng)前工程目錄為object/,該目錄下有6個(gè)文件,分別是:main.c、abc.c、xyz.c、abc.h、xyz.h和Makefile。其中main.c包含頭文件abc.h和xyz.h,abc.c包含頭文件abc.h,xyz.c包含頭文件xyz.h,而abc.h又包含了xyz.h。它們的依賴關(guān)系如圖。c9f7b8a8-ccef-11ec-bce3-dac502259ad0.pngMakefile應(yīng)該寫成這個(gè)樣子(假設(shè)生成目標(biāo)main):

main:main.oabc.oxyz.o
gccmain.oabc.oxyz.o-omain
main.o:main.cabc.hxyz.h
gcc-cmain.c–omain.o-g
abc.o:abc.cabc.hxyz.h
gcc-cabc.c–oabc.o-g
xyz.o:xyz.cxyz.h
gcc-cxyz.c-oxyz.o-g
.PHONY:clean
clean:
rmmainmain.oabc.oxyz.o-f

4. 創(chuàng)建和使用變量

為了makefile的易維護(hù),在makefile中我們可以使用變量。makefile的變量也就是一個(gè)字符串,理解成C語(yǔ)言中的宏可能會(huì)更好。

上面makefile例子:

test:fun1.ofun2.omain.o
gccfun1.ofun2.omain.o-otest
fun2.o:fun2.c
gcc-c-Wallfun2.c-ofun2.o
fun1.o:fun1.c
gcc-c-Wallfun1.c-ofun1.o
main.o:main.c
gcc-c-Wallmain.c-omain.o
.PHONY:clean
clean
rm*.otest

比如,我們聲明一個(gè)變量,叫objects,能夠表示obj文件就行了。我們?cè)趍akefile一開始就這樣定義:

objects=fun1.ofun2.omain.o

于是,我們就可以很方便地在我們的makefile中以“**$(objects)**”的方式來使用這個(gè)變量了,于是我們的改良版makefile就變成下面這個(gè)樣子:

objects=fun1.ofun2.omain.o
test:$(objects)
gccfun1.ofun2.omain.o-otest
fun2.o:fun2.c
gcc-c-Wallfun2.c-ofun2.o
fun1.o:fun1.c
gcc-c-Wallfun1.c-ofun1.o
main.o:main.c
gcc-c-Wallmain.c-omain.
.PHONY:clean
clean
rm*.otest

于是如果有新的 .o 文件加入,我們只需簡(jiǎn)單地修改一下 objects 變量就可以了

我們簡(jiǎn)單的總結(jié)一下:

2.1 創(chuàng)建變量的目的:

用來代替一個(gè)文本字符串:

  • 系列文件的名字
  • 傳遞給編譯器的參數(shù)
  • 需要運(yùn)行的程序
  • 需要查找源代碼的目錄
  • 你需要輸出信息的目錄
  • 你想做的其它事情。

2.2 如何定義變量:

變量定義的兩種方式

  • 遞歸展開方式VAR=var
  • 簡(jiǎn)單方式VAR:=var
  • 變量使用$(VAR)=========================
  • 用 ” $ ” 來表示
  • 類似于編程語(yǔ)言中的宏

我們?cè)賮砼e一個(gè)例子:

sunq:kang.oyul.o
gcckang.oyul.o-osunq
kang.o:kang.ckang.h
gcc-Wall-O-g-ckang.c-okang.o
yul.o:yul.cyul.h
gcc-Wall-O-g-cyul.c-oyul.o
.PHONY:clean
clean
rm*.otest

用變量來替換:

OBJS=kang.oyul.o
CC=gcc
CFLAGS=-Wall-O-g

sunq:$(OBJS)
$(CC)$(OBJS)-osunq
kang.o:kang.ckang.h
$(CC)$(CFLAGS)-ckang.c-okang.o
yul.o:yul.cyul.h
$(CC)$(CFLAGS)-cyul.c-oyul.o
.PHONY:clean
clean
rm*.otest
  • 遞歸展開方式VAR=var例子:
foo=$(bar)
bar=$(ugh)
ugh=Huh?

(foo)來進(jìn)行查看

優(yōu)點(diǎn): 它可以向后引用變量缺點(diǎn): 不能對(duì)該變量進(jìn)行任何擴(kuò)展,

例如CFLAGS = $(CFLAGS)-0會(huì)造成死循環(huán)

  • 簡(jiǎn)單方式VAR:=var
m:=mm
x:=$(m)
y:=$(x)bar
x:=later
echo$(x)$(y)

如:m變量的值為mm ,m的值賦給給x

(這個(gè)變量的方式更像是c語(yǔ)言)

==用?=定義變量==

dir:=/foo/bar
FOO?=bar
FOO是?

?含義是,如果FOO沒有被定義過,那么變量FO0的值就是“bar”,如果FOO先前被定義過,那么這條語(yǔ)將什么也不做,其等價(jià)于:

ifeq($(originFOO),undefined)
FOO=bar
endif
  • 為變量添加值

你可以通過 += 為已定義的變量添加新的值

Main=hello.ohello-1.o
Main+=hello-2.o
  • 預(yù)定義變量
-AR 庫(kù)文件維護(hù)程序的名稱,默認(rèn)值為ar。AS匯編程序的名稱默認(rèn)值為as。
-CC C編譯器的名稱,默認(rèn)值為cc。CPPC預(yù)編譯器的名稱,默認(rèn)值 為$(CC) -E。
-CXX C++編譯器的名稱,默認(rèn)值為g++。
-FC FORTRAN編譯器的名稱,默認(rèn)值為 f77
-RM 文件刪除程序的名稱,默認(rèn)值為rm -f
  • 自動(dòng)變量
- $* 不包含擴(kuò)展名的目標(biāo)文件名稱
-$+ 所有的依賴文件,以空格分開,并以出現(xiàn)的先后為序,可能包含重復(fù)的依賴文件
-$< 第一個(gè)依賴文件的名稱
-$? 所有時(shí)間戳比目標(biāo)文件晚的的依賴文件,并以空格分開
-$@ 目標(biāo)文件的完整名稱
-$^ 所有不重復(fù)的目標(biāo)依賴文件,以空格分開
-$% 如果目標(biāo)是歸檔成員,則該變量表示目標(biāo)的歸檔成員名稱

**$@:目標(biāo)文件$^: 所有的依賴文件,$<:第一個(gè)依賴文件**。這三個(gè)變量十分常見且重要

objects=fun1.ofun2.omain.o
test:$(objects)
gccfun1.ofun2.omain.o-otest
fun2.o:fun2.c
gcc-c-Wallfun2.c-ofun2.o
fun1.o:fun1.c
gcc-c-Wallfun1.c-ofun1.o
main.o:main.c
gcc-c-Wallmain.c-omain.o
.PHONY:clean
clean
rm*.otest

變量修改:

objects=fun1.ofun2.omain.o
CFLAGS=-c-Wall

test:$(objects)
gcc$(objects)-otest
fun2.o:$<
????????gcc?$(CFLAGS)?fun2.c?-o?$@
fun1.o:$<
????????gcc?$(CFLAGS)?fun1.c?-o?$@
main.o:$<
????????gcc?$(CFLAGS)?main.c?-o?$@
.PHONY:clean
clean
?rm?*.o?test

環(huán)境變量

  • make在啟動(dòng)時(shí)會(huì)自動(dòng)讀取系統(tǒng)當(dāng)前已經(jīng)定義了的環(huán)境變量,并且會(huì)創(chuàng)建與之具有相同名稱和數(shù)值的變量
  • 如果用戶在Makefile中定義了相同名稱的變量,那么用戶自定義變量將會(huì)覆蓋同名的環(huán)境變量

==直接運(yùn)行make選項(xiàng)==

-C dir讀入指定目錄下的Makefile
-f file讀入當(dāng)前目錄下的file文件作為Makefile
-i 忽略所有的命令執(zhí)行錯(cuò)誤
-I dir指定被包含的Makefile所在目錄
-n 只打印要執(zhí)行的命令,但不執(zhí)行這些命令
-p 顯示make變量數(shù)據(jù)庫(kù)和隱含規(guī)則
-s 在執(zhí)行命令時(shí)不顯示命令
-w 如果make在執(zhí)行過程中改變目錄,打印當(dāng)前目錄名

-C :dir讀入指定目錄下的Makefile

make -C Makefile/文件下的makefile

cb8ebf18-ccef-11ec-bce3-dac502259ad0.pngcba47c4a-ccef-11ec-bce3-dac502259ad0.png

-f :file 讀入當(dāng)前目錄下的file文件作為Makefile

c make -f Refuel.debug
make -f Refuel.debug clean

就可以把Refuel.debug當(dāng)作Makefile來用

-i :忽略所有的命令執(zhí)行錯(cuò)誤
假如我們?cè)趯懘a時(shí)候, gcc -c -Wall fun2.c o $@寫-o忘記了-這種時(shí)候,我們 make -i ,它會(huì)把小錯(cuò)誤先忽略,把代碼中能正常執(zhí)行的先執(zhí)行,錯(cuò)誤的提示出來,不執(zhí)行

-n :只打印要執(zhí)行的命令,但不執(zhí)行這些命令 不是真的執(zhí)行了命令,而是像模擬了執(zhí)行命令cbbde14e-ccef-11ec-bce3-dac502259ad0.png

U-Boot中我們會(huì)看到一些內(nèi)核的Makefile,config.mk 這樣的文件中羅列了一些變量的聲明cbd4631a-ccef-11ec-bce3-dac502259ad0.png

5. Makefile的隱含規(guī)則

  • ==隱含規(guī)則1:==編譯C程序的隱含規(guī)則——讓make自動(dòng)推導(dǎo)

它可以自動(dòng)推導(dǎo)文件以及文件依賴關(guān)系后面的命令,于是我們就沒必要去在每一個(gè)[.o]文件后都寫上類似的命令,因?yàn)?,我們的make會(huì)自動(dòng)識(shí)別,并自己推導(dǎo)命令。只要make看到一個(gè)[.o]文件,它就會(huì)自動(dòng)的把[.c]文件加在依賴關(guān)系中,如果make找到一個(gè)whatever.o,那么whatever.c,就會(huì)是whatever.o的依賴文件。并且 cc -c whatever.c 也會(huì)被推導(dǎo)出來,于是,我們的makefile再也不用寫得這么復(fù)雜。

objects=fun1.ofun2.omain.o

test:$(objects)
gcc$(objects)-otest

fun2.o:fun2.c
fun1.o:fun1.c
main.o:main.c

.PHONY:clean
clean
rm*.otest

這種方法,也就是make的“隱晦規(guī)則”。上面文件內(nèi)容中,“.PHONY”表示,clean是個(gè)偽目標(biāo)文件。

總結(jié):.o”的目標(biāo)的依賴目標(biāo)會(huì)自動(dòng)推導(dǎo)為“.c”,并且其生成命令是“**$(CC) -c $(CPPFLAGS) $(CFLAGS)**”cbf505a2-ccef-11ec-bce3-dac502259ad0.png

  • 隱含規(guī)則2:鏈接0bject文件的隱含規(guī)則

” 目標(biāo)依賴于“.o”,通過運(yùn)行C的編譯器來運(yùn)行鏈接程序生成(一般是“1d”),其生成命令是:“$(CC)$(LDFLAGS) .0$(LOADLIBES)$(LDLIBS)”。這個(gè)規(guī)則對(duì)于只有一個(gè)源文件的工程有效,同時(shí)也對(duì)多個(gè) Object文件(由不同的源文件生成)的也有效。例如如下

規(guī)則:x : x.o y.o z.o并且“ x.c ”、“ y.c ”和 “ z.c ” 都存在時(shí),隱含規(guī)則將執(zhí)行如下命令:
cc -c x.c -o x.occ -c y.c -o y.occ -c z.c -o z.occ x.o y.o z.o -o x

如果沒有一個(gè)源文件(如上例中的x.c)和你的目標(biāo)名字(如上例中的x)相關(guān)聯(lián),那么,你最好寫出自己的生成規(guī)則,不然,隱含規(guī)則會(huì)報(bào)錯(cuò)的

fun1:fun1.ofun2.omain.o

這樣就不會(huì)報(bào)錯(cuò)。

Makefile 總述

Makefile里主要包含了五個(gè)東西:顯式規(guī)則、隱晦規(guī)則、變量定義、文件指示和注釋。

  1. 顯式規(guī)則。顯式規(guī)則說明了,如何生成一個(gè)或多的的目標(biāo)文件。這是由Makefile的書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令。

  2. 隱晦規(guī)則。由于我們的make有自動(dòng)推導(dǎo)的功能,所以隱晦的規(guī)則可以讓我們比較粗糙地簡(jiǎn)略地書寫Makefile,這是由make所支持的。

  3. 變量的定義。在Makefile中我們要定義一系列的變量,變量一般都是字符串,這個(gè)有點(diǎn)你C語(yǔ)言中的宏,當(dāng)Makefile被執(zhí)行時(shí),其中的變量都會(huì)被擴(kuò)展到相應(yīng)的引用位置上。

  4. 文件指示。其包括了三個(gè)部分,一個(gè)是在一個(gè)Makefile中引用另一個(gè)Makefile,就像C語(yǔ)言中的include一樣;另一個(gè)是指根據(jù)某些情況指定Makefile中的有效部分,就像C語(yǔ)言中的預(yù)編譯#if一樣;還有就是定義一個(gè)多行的命令。有關(guān)這一部分的內(nèi)容,我會(huì)在后續(xù)的部分中講述。

  5. 注釋。Makefile中只有行注釋,和UNIX的Shell腳本一樣,其注釋是用“#”字符,這個(gè)就像C/C++中的“//”一樣。如果你要在你的Makefile中使用“#”字符,可以用反斜框進(jìn)行轉(zhuǎn)義,如:“#”。

VPATH的用法

1. Makefile的 VPATH

VPATH: 虛路徑

  • 在一些大的工程中,有大量的源文件,我們通常的做法是把這許多的源文件分類,并存放在==不同的目錄中==。所以,當(dāng)make需要去找尋文件的依賴關(guān)系時(shí),你可以在文件前加上路徑,但 ==最好的方法是把一個(gè)路徑告訴make,讓make在自動(dòng)去找==。

  • Makefile文件中的特殊變量“VPATH”就是完成這個(gè)功能的,如果沒有指明這個(gè)變量,make只會(huì)在當(dāng)前的目錄中去找尋依賴文件和目標(biāo)文件。如果定義了這個(gè)變量,那么,make就會(huì)在當(dāng)當(dāng)前目錄找不到的情況下,到所指定的目錄中去找尋文件了。

  • VPATH = src:../headers

  • 上面的的定義指定兩個(gè)目錄,“src”和“../headers”,make會(huì)按照這個(gè)順序進(jìn)行搜索。目錄由“冒號(hào)”分隔。(當(dāng)然,當(dāng)前目錄永遠(yuǎn)是最高優(yōu)先搜索的地方)

另一個(gè)設(shè)置文件搜索路徑的方法是使用make的“vpath”關(guān)鍵字(注意,它是全小寫的),這不是變量,這是一個(gè)make的關(guān)鍵字,這和上面提到的那個(gè)VPATH變量很類似,但是它更為靈活。它可以指定不同的文件在不同的搜索目錄中。這是一個(gè)很靈活的功能。它的使用方法有三種:

1.vpath
//為符合模式< pattern>的文件指定搜索目錄

2.vpath
//清除符合模式< pattern>的文件的搜索目錄。

3.vpath
//清除所有已被設(shè)置好了的文件搜索目錄。

vapth使用方法中的< pattern>需要包含“%”字符。“%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”結(jié)尾的文件。< pattern>指定了要搜索的文件集,而< directories>則指定了的文件集的搜索的目錄。例如:

vpath%.h../headers

該語(yǔ)句表示,要求make在“../headers”目錄下搜索所有以“.h”結(jié)尾的文件。(如果某文件在當(dāng)前目錄沒有找到的話)

我們可以連續(xù)地使用vpath語(yǔ)句,以指定不同搜索策略。如果連續(xù)的vpath語(yǔ)句中出現(xiàn)了相同的< pattern>,或是被重復(fù)了的< pattern>,那么,make會(huì)按照vpath語(yǔ)句的先后順序來執(zhí)行搜索。如:

vpath %.c foo

vpath % blish

vpath %.c bar

其表示“.c”結(jié)尾的文件,先在“foo”目錄,然后是“blish”,最后是“bar”目錄。

vpath %.c foo:bar

vpath % blish而上面的語(yǔ)句則表示“.c”結(jié)尾的文件,先在“foo”目錄,然后是“bar”目錄,最后才是“blish”目錄。

分布不同路徑的程序。在不同的目錄下寫了程序,如果不用VPATH如何去寫makefile呢?cc12aa9e-ccef-11ec-bce3-dac502259ad0.png

cc3b94ea-ccef-11ec-bce3-dac502259ad0.png在這里插入圖片描述

cc5ffd94-ccef-11ec-bce3-dac502259ad0.pngcca5c338-ccef-11ec-bce3-dac502259ad0.png==不同文件我們?cè)趺磩h除不想要的中間文件呢?==通過指令:find ./ -name "*.o",找到所有.o的文件我們輸入指令:find ./ -name "*.o" -exec rm {} ;,意思為,我把找到的結(jié)果拿來給rm去刪除,ccdaf30a-ccef-11ec-bce3-dac502259ad0.png這樣.o文件就在不同的目錄下刪除了cd0b0798-ccef-11ec-bce3-dac502259ad0.png

2. Makefile 中 VPATH使用

cd2d66ee-ccef-11ec-bce3-dac502259ad0.pngcd5c66e2-ccef-11ec-bce3-dac502259ad0.pngcd7f1214-ccef-11ec-bce3-dac502259ad0.png

嵌套的Makefile

每個(gè)文件都一個(gè)自己的makefile,makefile互相調(diào)用子makefile案例:

我們看到有許多目錄和外部makefile,在每個(gè)目錄下有.c程序和子makefilecd9b38b8-ccef-11ec-bce3-dac502259ad0.png在第一個(gè)目錄f1中的子makefile是把f1.c 生成為f1.o放到了OBJS_DIR obj中cdc62046-ccef-11ec-bce3-dac502259ad0.pngcdefd558-ccef-11ec-bce3-dac502259ad0.png

  • 我們注意到有一句@echo $(SUBDIRS)

  • @(RM)并不是我們自己定義的變量,那它是從哪里來的呢? 就是make -f

  • make -C $@

  • export CC OBJS BIN OBJS_DIR BIN_DIR :是讓子makefile也可以調(diào)用

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 操作系統(tǒng)
    +關(guān)注

    關(guān)注

    37

    文章

    6694

    瀏覽量

    123147
  • 編譯
    +關(guān)注

    關(guān)注

    0

    文章

    649

    瀏覽量

    32776
  • Makefile
    +關(guān)注

    關(guān)注

    1

    文章

    125

    瀏覽量

    19158

原文標(biāo)題:Linux C基礎(chǔ)——” Makefile “ 文件管理大師你拜訪過嘛?

文章出處:【微信號(hào):yikoulinux,微信公眾號(hào):一口Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Verilog語(yǔ)法中運(yùn)算符的用法

    verilog語(yǔ)法中使用以下兩個(gè)運(yùn)算符可以簡(jiǎn)化我們的位選擇代碼。
    的頭像 發(fā)表于 10-25 15:17 ?223次閱讀
    Verilog<b class='flag-5'>語(yǔ)法</b>中運(yùn)算符的用法

    關(guān)于Makefile自動(dòng)生成-autotools的使用

    在Linux應(yīng)用開發(fā)中,編寫Makefile是一項(xiàng)必備技能,因?yàn)樗x了工程中所有文件的編譯順序、規(guī)則和依賴關(guān)系,決定了哪些文件需要編譯以及它們的編譯順序。 雖然對(duì)初級(jí)開發(fā)者而言,編寫復(fù)雜
    的頭像 發(fā)表于 07-25 15:50 ?1441次閱讀
    關(guān)于<b class='flag-5'>Makefile</b>自動(dòng)生成-autotools的使用

    FPGA學(xué)習(xí)筆記---基本語(yǔ)法

    Verilog語(yǔ)法是指硬件能夠?qū)崿F(xiàn)的語(yǔ)法。它的子集很小。常用的RTL語(yǔ)法結(jié)構(gòu)如下: 1、模塊聲明:module ... end module 2、端口聲明:input, output, inout
    發(fā)表于 06-23 14:58

    快來用Makefile管理工程,提高工作效率!

    一、makefile簡(jiǎn)介Makefile是一種特別設(shè)計(jì)用來幫助項(xiàng)目的構(gòu)建管理的文件。它定義了編譯器和IDE工程管理系統(tǒng)自動(dòng)執(zhí)行的命令集合,主要用于自動(dòng)化編譯,減輕重復(fù)性任務(wù)的負(fù)擔(dān)。Makefile
    的頭像 發(fā)表于 05-18 08:10 ?290次閱讀
    快來用<b class='flag-5'>Makefile</b>管理工程,提高工作效率!

    linux系統(tǒng)中Makefile的使用方法

    Makefile是一種編譯控制文件,廣泛用于項(xiàng)目的自動(dòng)化構(gòu)建。它定義了一系列的規(guī)則來指導(dǎo)構(gòu)建的過程。通過Makefile,開發(fā)者可以輕松管理大型項(xiàng)目的編譯鏈接、清理等任務(wù)。本文將從Makefile
    的頭像 發(fā)表于 05-11 08:49 ?584次閱讀

    C語(yǔ)言Makefile入門到精通全攻略

    Makefile是一種編譯控制文件,廣泛用于項(xiàng)目的自動(dòng)化構(gòu)建。它定義了一系列的規(guī)則來指導(dǎo)構(gòu)建的過程。
    發(fā)表于 04-28 15:02 ?1176次閱讀

    Makefile可以做什么?Makefile的基本格式

    Makefile可以根據(jù)指定的依賴規(guī)則和文件是否有修改來執(zhí)行命令。常用來編譯軟件源代碼,只需要重新編譯修改過的文件,使得編譯速度大大加快。
    的頭像 發(fā)表于 01-25 11:18 ?644次閱讀

    全面而詳細(xì)的Makefile使用手冊(cè)

    Makefile是一種編譯控制文件,廣泛用于項(xiàng)目的自動(dòng)化構(gòu)建。它定義了一系列的規(guī)則來指導(dǎo)構(gòu)建的過程。
    的頭像 發(fā)表于 01-24 12:35 ?829次閱讀

    Makefile簡(jiǎn)介和使用方法

    Makefile是和make工具一起配合使用的,用于組織管理項(xiàng)目源代碼的編譯和鏈接。
    的頭像 發(fā)表于 12-26 12:24 ?1563次閱讀

    oracle和mysql語(yǔ)法區(qū)別大嗎

    Oracle和MySQL是兩種不同的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)(RDBMS)。雖然它們都是遵循SQL標(biāo)準(zhǔn),但在語(yǔ)法和特性上仍存在一些區(qū)別。以下是對(duì)Oracle和MySQL語(yǔ)法區(qū)別的詳細(xì)說明: 數(shù)據(jù)類型
    的頭像 發(fā)表于 12-06 10:26 ?1090次閱讀

    oracle case when 語(yǔ)法介紹

    Oracle的CASE WHEN語(yǔ)法是一種在數(shù)據(jù)庫(kù)查詢中使用的條件語(yǔ)句,它提供了一種在SELECT語(yǔ)句中根據(jù)條件對(duì)結(jié)果進(jìn)行轉(zhuǎn)換或篩選的方法。在本文中,我們將詳細(xì)介紹Oracle的CASE WHEN
    的頭像 發(fā)表于 12-06 10:21 ?1670次閱讀

    oracle的update語(yǔ)法

    Oracle是一種強(qiáng)大的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),具有廣泛的應(yīng)用,UPDATE語(yǔ)句是用于修改數(shù)據(jù)庫(kù)中現(xiàn)有記錄的重要操作之一。在本文中,我們將詳細(xì)介紹Oracle的UPDATE語(yǔ)法及其用法。 首先,我們
    的頭像 發(fā)表于 12-05 16:22 ?2288次閱讀

    javascript的基本語(yǔ)法遵循的標(biāo)準(zhǔn)

    JavaScript是一種腳本語(yǔ)言,用于為網(wǎng)站添加交互性和動(dòng)態(tài)性的功能。它的基本語(yǔ)法遵循ECMAScript標(biāo)準(zhǔn),這是一種由Ecma國(guó)際組織制定的語(yǔ)言標(biāo)準(zhǔn)。本文將詳細(xì)介紹JavaScript
    的頭像 發(fā)表于 12-03 11:35 ?2663次閱讀

    java switch case的語(yǔ)法規(guī)則

    在Java中,switch case語(yǔ)句是一種用于多分支選擇的控制流語(yǔ)句。它允許根據(jù)某個(gè)表達(dá)式的值來執(zhí)行不同的代碼塊。下面是關(guān)于switch case語(yǔ)法規(guī)則的詳細(xì)解釋。 基本語(yǔ)法 switch語(yǔ)句
    的頭像 發(fā)表于 11-30 14:40 ?2095次閱讀

    select語(yǔ)句的基本語(yǔ)法

    、詳實(shí)、細(xì)致地解釋SELECT語(yǔ)句的基本語(yǔ)法以及關(guān)鍵部分。 SELECT語(yǔ)句的基本語(yǔ)法如下: SELECT 列名 1 , 列名 2 , ... FROM 表名 WHERE 條件 上述語(yǔ)法可以分為三個(gè)
    的頭像 發(fā)表于 11-17 16:23 ?1838次閱讀