當(dāng)前位置:首頁(yè) > 嵌入式 > 嵌入式教程
[導(dǎo)讀]到此為止,讀者已經(jīng)了解了如何在Linux下使用編輯器編寫代碼,如何使用gcc把代碼編譯成可執(zhí)行文件,還學(xué)習(xí)了如何使用gdb來調(diào)試程序,那么,所有的工作看似已經(jīng)完成了,為什么還需要make這個(gè)工程管理器呢?

3.5make工程管理器

到此為止,讀者已經(jīng)了解了如何在Linux下使用編輯器編寫代碼,如何使用gcc把代碼編譯成可執(zhí)行文件,還學(xué)習(xí)了如何使用gdb來調(diào)試程序,那么,所有的工作看似已經(jīng)完成了,為什么還需要make這個(gè)工程管理器呢?

所謂工程管理器,顧名思義,是用于管理較多的文件。讀者可以試想一下,由成百上千個(gè)文件構(gòu)成的項(xiàng)目,如果其中只有一個(gè)或少數(shù)幾個(gè)文件進(jìn)行了修改,按照之前所學(xué)的gcc編譯工具,就不得不把這所有的文件重新編譯一遍,因?yàn)榫幾g器并不知道哪些文件是最近更新的,而只知道需要包含這些文件才能把源代碼編譯成可執(zhí)行文件,于是,程序員就不得不重新輸入數(shù)目如此龐大的文件名以完成最后的編譯工作。

編譯過程分為編譯、匯編、鏈接階段,其中編譯階段僅檢查語法錯(cuò)誤以及函數(shù)與變量是否被正確地聲明了,在鏈接階段則主要完成函數(shù)鏈接和全局變量的鏈接。因此,那些沒有改動(dòng)的源代碼根本不需要重新編譯,而只要把它們重新鏈接進(jìn)去就可以了。所以,人們就希望有一個(gè)工程管理器能夠自動(dòng)識(shí)別更新了的文件代碼,而不需要重復(fù)輸入冗長(zhǎng)的命令行,這樣,make工程管理器就應(yīng)運(yùn)而生了。

實(shí)際上,make工程管理器也就是個(gè)“自動(dòng)編譯管理器”,這里的“自動(dòng)”是指它能夠根據(jù)文件時(shí)間戳自動(dòng)發(fā)現(xiàn)更新過的文件而減少編譯的工作量,同時(shí),它通過讀入makefile文件的內(nèi)容來執(zhí)行大量的編譯工作。用戶只需編寫一次簡(jiǎn)單的編譯語句就可以了。它大大提高了實(shí)際項(xiàng)目的工作效率,而且?guī)缀跛蠰inux下的項(xiàng)目編程均會(huì)涉及它,希望讀者能夠認(rèn)真學(xué)習(xí)本節(jié)內(nèi)容。

3.5.1makefile基本結(jié)構(gòu)

makefile是make讀入的惟一配置文件,因此本節(jié)的內(nèi)容實(shí)際就是講述makefile的編寫規(guī)則。在一個(gè)makefile中通常包含如下內(nèi)容:

n 需要由make工具創(chuàng)建的目標(biāo)體(target),通常是目標(biāo)文件或可執(zhí)行文件;

n 要?jiǎng)?chuàng)建的目標(biāo)體所依賴的文件(dependency_file);

n 創(chuàng)建每個(gè)目標(biāo)體時(shí)需要運(yùn)行的命令(command),這一行必須以制表符(tab鍵)開頭。

它的格式為:

target:dependency_files

command/*該行必須以tab鍵開頭*/

例如,有兩個(gè)文件分別為hello.c和hello.h,創(chuàng)建的目標(biāo)體為hello.o,執(zhí)行的命令為gcc編譯指令:gcc–chello.c,那么,對(duì)應(yīng)的makefile就可以寫為:

#Thesimplestexample

hello.o:hello.chello.h

gcc–chello.c–ohello.o

接著就可以使用make了。使用make的格式為:maketarget,這樣make就會(huì)自動(dòng)讀入makefile(也可以是首字母大寫的Makefile)并執(zhí)行對(duì)應(yīng)target的command語句,并會(huì)找到相應(yīng)的依賴文件。如下所示:

[root@localhostmakefile]#makehello.o

gcc–chello.c–ohello.o

[root@localhostmakefile]#ls

hello.chello.hhello.omakefile

可以看到,makefile執(zhí)行了“hello.o”對(duì)應(yīng)的命令語句,并生成了“hello.o”目標(biāo)體。

注意

在makefile中的每一個(gè)command前必須有“Tab”符,否則在運(yùn)行make命令時(shí)會(huì)出錯(cuò)。

3.5.2makefile變量

上面示例的makefile在實(shí)際中是幾乎不存在的,因?yàn)樗^于簡(jiǎn)單,僅包含兩個(gè)文件和一個(gè)命令,在這種情況下完全不必要編寫makefile而只需在shell中直接輸入即可,在實(shí)際中使用的makefile往往是包含很多的文件和命令的,這也是makefile產(chǎn)生的原因。下面就可給出稍微復(fù)雜一些的makefile進(jìn)行講解。

david:kang.oyul.o

gcckang.obar.o-omyprog

kang.o:kang.ckang.hhead.h

gcc–Wall–O-g–ckang.c-okang.o

yul.o:bar.chead.h

gcc-Wall–O-g–cyul.c-oyul.o

在這個(gè)makefile中有3個(gè)目標(biāo)體(target),分別為david、kang.o和yul.o,其中第一個(gè)目標(biāo)體的依賴文件就是后兩個(gè)目標(biāo)體。如果用戶使用命令“makedavid”,則make管理器就是找到david目標(biāo)體開始執(zhí)行。

這時(shí),make會(huì)自動(dòng)檢查相關(guān)文件的時(shí)間戳。首先,在檢查“kang.o”、“yul.o”和“david”3個(gè)文件的時(shí)間戳之前,它會(huì)向下查找那些把“kang.o”或“yul.o”作為目標(biāo)文件的時(shí)間戳。比如,“kang.o”的依賴文件為“kang.c”、“kang.h”、“head.h”。如果這些文件中任何一個(gè)的時(shí)間戳比“kang.o”新,則命令“gcc–Wall–O-g–ckang.c-okang.o”將會(huì)執(zhí)行,從而更新文件“kang.o”。在更新完“kang.o”或“yul.o”之后,make會(huì)檢查最初的“kang.o”、“yul.o”和“david”3個(gè)文件,只要文件“kang.o”或“yul.o”中的至少有一個(gè)文件的時(shí)間戳比“david”新,則第二行命令就會(huì)被執(zhí)行。這樣,make就完成了自動(dòng)檢查時(shí)間戳的工作,開始執(zhí)行編譯工作。這也就是make工作的基本流程。

接下來,為了進(jìn)一步簡(jiǎn)化編輯和維護(hù)makefile,make允許在makefile中創(chuàng)建和使用變量。變量是在makefile中定義的名字,用來代替一個(gè)文本字符串,該文本字符串稱為該變量的值。在具體要求下,這些值可以代替目標(biāo)體、依賴文件、命令以及makefile文件中其他部分。在makefile中的變量定義有兩種方式:一種是遞歸展開方式,另一種是簡(jiǎn)單方式。

遞歸展開方式定義的變量是在引用該變量時(shí)進(jìn)行替換的,即如果該變量包含了對(duì)其他變量的引用,則在引用該變量時(shí)一次性將內(nèi)嵌的變量全部展開,雖然這種類型的變量能夠很好地完成用戶的指令,但是它也有嚴(yán)重的缺點(diǎn),如不能在變量后追加內(nèi)容(因?yàn)檎Z句:CFLAGS=$(CFLAGS)-O在變量擴(kuò)展過程中可能導(dǎo)致無窮循環(huán))。

為了避免上述問題,簡(jiǎn)單擴(kuò)展型變量的值在定義處展開,并且只展開一次,因此它不包含任何對(duì)其他變量的引用,從而消除變量的嵌套引用。

遞歸展開方式的定義格式為:VAR=var。

簡(jiǎn)單擴(kuò)展方式的定義格式為:VAR:=var。

make中的變量使用均使用的格式為:$(VAR)。

注意

變量名是不包括“:”、“#”、“=”以及結(jié)尾空格的任何字符串。同時(shí),變量名中包含字母、數(shù)字以及下劃線以外的情況應(yīng)盡量避免,因?yàn)樗鼈兛赡茉趯肀毁x予特別的含義。

變量名是大小寫敏感的,例如變量名“foo”、“FOO”、和“Foo”代表不同的變量。

推薦在makefile內(nèi)部使用小寫字母作為變量名,預(yù)留大寫字母作為控制隱含規(guī)則參數(shù)或用戶重載命令選項(xiàng)參數(shù)的變量名。

下面給出了上例中用變量替換修改后的makefile,這里用OBJS代替kang.o和yul.o,用CC代替gcc,用CFLAGS代替“-Wall-O–g”。這樣在以后修改時(shí),就可以只修改變量定義,而不需要修改下面的定義實(shí)體,從而大大簡(jiǎn)化了makefile維護(hù)的工作量。

經(jīng)變量替換后的makefile如下所示:

OBJS=kang.oyul.o

CC=gcc

CFLAGS=-Wall-O-g

david:$(OBJS)

$(CC)$(OBJS)-odavid

kang.o:kang.ckang.h

$(CC)$(CFLAGS)-ckang.c-okang.o

yul.o:yul.cyul.h

$(CC)$(CFLAGS)-cyul.c-oyul.o

可以看到,此處變量是以遞歸展開方式定義的。

makefile中的變量分為用戶自定義變量、預(yù)定義變量、自動(dòng)變量及環(huán)境變量。如上例中的OBJS就是用戶自定義變量,自定義變量的值由用戶自行設(shè)定,而預(yù)定義變量和自動(dòng)變量為通常在makefile都會(huì)出現(xiàn)的變量,它們的一部分有默認(rèn)值,也就是常見的設(shè)定值,當(dāng)然用戶可以對(duì)其進(jìn)行修改。

預(yù)定義變量包含了常見編譯器、匯編器的名稱及其編譯選項(xiàng)。表3.15列出了makefile中常見預(yù)定義變量及其部分默認(rèn)值。

表3.15 makefile中常見的預(yù)定義變量

預(yù)定義變量

含義

AR

庫(kù)文件維護(hù)程序的名稱,默認(rèn)值為ar

AS

匯編程序的名稱,默認(rèn)值為as

CC

C編譯器的名稱,默認(rèn)值為cc

CPP

C預(yù)編譯器的名稱,默認(rèn)值為$(CC)–E

CXX

C++編譯器的名稱,默認(rèn)值為g++

FC

Fortran編譯器的名稱,默認(rèn)值為f77

RM

文件刪除程序的名稱,默認(rèn)值為rm–f

ARFLAGS

庫(kù)文件維護(hù)程序的選項(xiàng),無默認(rèn)值

ASFLAGS

匯編程序的選項(xiàng),無默認(rèn)值

CFLAGS

C編譯器的選項(xiàng),無默認(rèn)值

CPPFLAGS

C預(yù)編譯的選項(xiàng),無默認(rèn)值

CXXFLAGS

C++編譯器的選項(xiàng),無默認(rèn)值

FFLAGS

Fortran編譯器的選項(xiàng),無默認(rèn)值

可以看出,上例中的CC和CFLAGS是預(yù)定義變量,其中由于CC沒有采用默認(rèn)值,因此,需要把“CC=gcc”明確列出來。

由于常見的gcc編譯語句中通常包含了目標(biāo)文件和依賴文件,而這些文件在makefile文件中目標(biāo)體所在行已經(jīng)有所體現(xiàn),因此,為了進(jìn)一步簡(jiǎn)化makefile的編寫,就引入了自動(dòng)變量。自動(dòng)變量通??梢源砭幾g語句中出現(xiàn)目標(biāo)文件和依賴文件等,并且具有本地含義(即下一語句中出現(xiàn)的相同變量代表的是下一語句的目標(biāo)文件和依賴文件)。表3.16列出了makefile中常見的自動(dòng)變量。

表3.16 makefile中常見的自動(dòng)變量

自動(dòng)變量

含義

$*

不包含擴(kuò)展名的目標(biāo)文件名稱

$+

所有的依賴文件,以空格分開,并以出現(xiàn)的先后為序,可能包含重復(fù)的依賴文件

$<

第一個(gè)依賴文件的名稱

$?

所有時(shí)間戳比目標(biāo)文件晚的依賴文件,并以空格分開

$@

目標(biāo)文件的完整名稱

$^

所有不重復(fù)的依賴文件,以空格分開

$%

如果目標(biāo)是歸檔成員,則該變量表示目標(biāo)的歸檔成員名稱

自動(dòng)變量的書寫比較難記,但是在熟練了之后使用會(huì)非常方便,請(qǐng)讀者結(jié)合下例中的自動(dòng)變量改寫的makefile進(jìn)行記憶。

OBJS=kang.oyul.o

CC=gcc

CFLAGS=-Wall-O-g

david:$(OBJS)

$(CC)$^-o$@

kang.o:kang.ckang.h

$(CC)$(CFLAGS)-c$<-o$@

yul.o:yul.cyul.h

$(CC)$(CFLAGS)-c$<-o$@

另外,在makefile中還可以使用環(huán)境變量。使用環(huán)境變量的方法相對(duì)比較簡(jiǎn)單,make在啟動(dòng)時(shí)會(huì)自動(dòng)讀取系統(tǒng)當(dāng)前已經(jīng)定義了的環(huán)境變量,并且會(huì)創(chuàng)建與之具有相同名稱和數(shù)值的變量。但是,如果用戶在makefile中定義了相同名稱的變量,那么用戶自定義變量將會(huì)覆蓋同名的環(huán)境變量。

3.5.3makefile規(guī)則

makefile的規(guī)則是make進(jìn)行處理的依據(jù),它包括了目標(biāo)體、依賴文件及其之間的命令語句。在上面的例子中,都顯式地指出了makefile中的規(guī)則關(guān)系,如“$(CC)$(CFLAGS)-c$<-o$@”,但為了簡(jiǎn)化makefile的編寫,make還定義了隱式規(guī)則和模式規(guī)則,下面就分別對(duì)其進(jìn)行講解。

1.隱式規(guī)則

隱含規(guī)則能夠告訴make怎樣使用傳統(tǒng)的規(guī)則完成任務(wù),這樣,當(dāng)用戶使用它們時(shí)就不必詳細(xì)指定編譯的具體細(xì)節(jié),而只需把目標(biāo)文件列出即可。make會(huì)自動(dòng)搜索隱式規(guī)則目錄來確定如何生成目標(biāo)文件。如上例就可以寫成:

OBJS=kang.oyul.o

CC=gcc

CFLAGS=-Wall-O-g

david:$(OBJS)

$(CC)$^-o$@

為什么可以省略后兩句呢?因?yàn)閙ake的隱式規(guī)則指出:所有“.o”文件都可自動(dòng)由“.c”文件使用命令“$(CC)$(CPPFLAGS)$(CFLAGS)-cfile.c–ofile.o”來生成。這樣“kang.o”和“yul.o”就會(huì)分別通過調(diào)用“$(CC)$(CFLAGS)-ckang.c-okang.o”和“$(CC)$(CFLAGS)-cyul.c-oyul.o”來生成。

注意

在隱式規(guī)則只能查找到相同文件名的不同后綴名文件,如“kang.o”文件必須由“kang.c”文件生成。

表3.17給出了常見的隱式規(guī)則目錄。

表3.17 makefile中常見隱式規(guī)則目錄

對(duì)應(yīng)語言后綴名

隱式規(guī)則

C編譯:.c變?yōu)?o

$(CC)–c$(CPPFLAGS)$(CFLAGS)

C++編譯:.cc或.C變?yōu)?o

$(CXX)-c$(CPPFLAGS)$(CXXFLAGS)

Pascal編譯:.p變?yōu)?o

$(PC)-c$(PFLAGS)

Fortran編譯:.r變?yōu)?o

$(FC)-c$(FFLAGS)

2.模式規(guī)則

模式規(guī)則是用來定義相同處理規(guī)則的多個(gè)文件的。它不同于隱式規(guī)則,隱式規(guī)則僅僅能夠用make默認(rèn)的變量來進(jìn)行操作,而模式規(guī)則還能引入用戶自定義變量,為多個(gè)文件建立相同的規(guī)則,從而簡(jiǎn)化makefile的編寫。

模式規(guī)則的格式類似于普通規(guī)則,這個(gè)規(guī)則中的相關(guān)文件前必須用“%”標(biāo)明。使用模式規(guī)則修改后的makefile的編寫如下:

OBJS=kang.oyul.o

CC=gcc

CFLAGS=-Wall-O-g

david:$(OBJS)

$(CC)$^-o$@

%.o:%.c

$(CC)$(CFLAGS)-c$<-o$@

3.5.4make管理器的使用

使用make管理器非常簡(jiǎn)單,只需在make命令的后面鍵入目標(biāo)名即可建立指定的目標(biāo),如果直接運(yùn)行make,則建立makefile中的第一個(gè)目標(biāo)。

此外make還有豐富的命令行選項(xiàng),可以完成各種不同的功能。表3.18列出了常用的make命令行選項(xiàng)。

表3.18 make的命令行選項(xiàng)

命令格式

含義

-Cdir

讀入指定目錄下的makefile

-ffile

讀入當(dāng)前目錄下的file文件作為makefile

-I

忽略所有的命令執(zhí)行錯(cuò)誤

-Idir

指定被包含的makefile所在目錄

-n

只打印要執(zhí)行的命令,但不執(zhí)行這些命令

-p

顯示make變量數(shù)據(jù)庫(kù)和隱含規(guī)則

-s

在執(zhí)行命令時(shí)不顯示命令

-w

如果make在執(zhí)行過程中改變目錄,則打印當(dāng)前目錄名

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉