

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、<p> 第9章 基于ARM9和Linux嵌入式系統(tǒng)設(shè)計(jì)</p><p> 本章將學(xué)習(xí)如何進(jìn)行嵌入式Linux系統(tǒng)的開(kāi)發(fā)。讀完本章,讀者將了解以下內(nèi)容:</p><p> ● 嵌入式Linux的開(kāi)發(fā)環(huán)境。</p><p> ● Linux開(kāi)發(fā)工具GNU gcc的使用。</p><p> ● GNU make命令和make
2、file 文件。</p><p><b> ● GDB調(diào)試器。</b></p><p> ● 嵌入式Linux下C語(yǔ)言編程。</p><p> ● 嵌入式Linux引導(dǎo)程序。</p><p> ●嵌入式Linux 下程序調(diào)試應(yīng)用舉例。</p><p> 9.1 嵌入式Linux的開(kāi)發(fā)環(huán)
3、境</p><p> 嵌入式系統(tǒng)是以應(yīng)用為中心,以計(jì)算機(jī)技術(shù)為基礎(chǔ)、軟硬件均可裁剪、適應(yīng)應(yīng)用系統(tǒng)對(duì)功能、可靠性、成本、體積、功耗嚴(yán)格要求的專(zhuān)用計(jì)算機(jī)系統(tǒng)。其發(fā)展已有二十多年的歷史,國(guó)際上也出現(xiàn)了一些著名的嵌入式操作系統(tǒng),如VxWorks,Palm OS,Windows CE等,但這些操作系統(tǒng)均屬于商品化產(chǎn)品,價(jià)格昂貴且由于源代碼不公開(kāi)導(dǎo)致了諸如對(duì)設(shè)備的支持,應(yīng)用軟件的移植等一系列的問(wèn)題。而Linux作為一種優(yōu)秀
4、的免費(fèi)操作系統(tǒng),近幾年在嵌入式領(lǐng)域異軍突起,成為了最有潛力的嵌入式操作系統(tǒng)。</p><p> 9.1.1 嵌入式Linux開(kāi)發(fā)環(huán)境建立</p><p> 進(jìn)行項(xiàng)目開(kāi)發(fā)前,首先要做的是搭建一套基于Linux操作系統(tǒng)的應(yīng)用開(kāi)發(fā)環(huán)境,一般由目標(biāo)板和宿主機(jī)所構(gòu)成。目標(biāo)板用于運(yùn)行操作系統(tǒng)和系統(tǒng)應(yīng)用軟件,目標(biāo)板所用到的操作系統(tǒng)的內(nèi)核編譯、應(yīng)用程序的開(kāi)發(fā)和調(diào)試規(guī)則需要通過(guò)宿主機(jī)來(lái)完成。開(kāi)發(fā)環(huán)境對(duì)硬
5、件沒(méi)有特殊的要求,但是為了雙方之間建立連接關(guān)系,關(guān)鍵的接口(包括串口、以太網(wǎng)口和USB口等)是必不可少的。</p><p> 嵌入式Linux 開(kāi)發(fā)環(huán)境有幾個(gè)方案:</p><p> (1)在WINDOWS 下安裝Linux虛擬機(jī)后,目前大多情況下使用VWare軟件;</p><p> ?。?)直接安裝 Linux 操作系統(tǒng)。</p><p&
6、gt; 若使用純LINUX操作系統(tǒng)開(kāi)發(fā)環(huán)境。多數(shù)使用的開(kāi)發(fā)環(huán)境為RedHat 9,RedHat 9支持中文,并且包含了絕大部分的開(kāi)發(fā)工具,不用擔(dān)心裝了Linux就不能使用WinDows的問(wèn)題。一般的情況都是用戶(hù)已經(jīng)有了WINDOWS 操作系統(tǒng),再安裝Linux,Linux 會(huì)自動(dòng)安裝一個(gè)叫作GRUB 的啟動(dòng)引導(dǎo)軟件,可以選擇引導(dǎo)多個(gè)操作系統(tǒng)??涩F(xiàn)在的微型計(jì)算機(jī)的CPU速度快,內(nèi)存容量大,因此,相當(dāng)多的ARM嵌入式系統(tǒng)的開(kāi)發(fā)人員使用在W
7、INDOWS 下安裝Linux虛擬機(jī),這樣,開(kāi)發(fā)人員就可在WINDOWS 和Linux兩種操作系統(tǒng)下任意切換使用。給開(kāi)發(fā)人員帶來(lái)許多方便。</p><p> 9.1.2 嵌入式Linux開(kāi)發(fā)的一般過(guò)程</p><p> 嵌入式Linux融合了嵌入式和Linux的特點(diǎn),其開(kāi)發(fā)與一般的應(yīng)用程序開(kāi)發(fā)相比有著自己的特點(diǎn),下面簡(jiǎn)要的介紹一下嵌入式Linux開(kāi)發(fā)的一般過(guò)程。</p>
8、<p> 了解硬件是首要的一步,這是嵌入式開(kāi)發(fā)的特點(diǎn)決定的。了解硬件指的是了解整個(gè)硬件,判斷硬件對(duì)于當(dāng)前的應(yīng)用來(lái)說(shuō)是否合適。嵌入式系統(tǒng)中需要使用到CPU和各種外圍設(shè)備,由此需要收集相關(guān)硬件的資料,包括CPU,芯片手冊(cè)和各種外圍設(shè)備的手冊(cè)以及相關(guān)的各種電路圖等,并對(duì)整體系統(tǒng)有較深入的了解。</p><p> 了解硬件后,下一步就該準(zhǔn)備需要使用的Linux工具以及其他工具,這些工具包括針對(duì)所用CPU的編
9、譯器/匯編器/連接器、相應(yīng)的庫(kù)工具、目標(biāo)文件分析/管理工具、符號(hào)查看器等。由于Linux的開(kāi)放性,針對(duì)不同目標(biāo)平臺(tái)的Linux工具都可在網(wǎng)上免費(fèi)得到,這些工具的絕大部分都由GNU提供。所需要的其他工具還包括硬件廠商提供給公司的工具,如編程器、下載工具和查錯(cuò)器等。所有這些工具對(duì)以后的開(kāi)發(fā)、調(diào)試等都可說(shuō)是必不可少的。</p><p> 做好以上的準(zhǔn)備工作后,就要進(jìn)入實(shí)質(zhì)性的工作階段了。首先需要安排內(nèi)存地址,如SDR
10、AM的內(nèi)存地址,F(xiàn)lash的內(nèi)存地址等,這需要與實(shí)際應(yīng)用和硬件狀況相結(jié)合來(lái)考慮,要根據(jù)硬件的限制以及實(shí)際應(yīng)用的需要對(duì)內(nèi)存地址進(jìn)行合理的安排,同時(shí)要注意內(nèi)存地址應(yīng)具有一定的伸縮性,以便于將來(lái)需要改動(dòng)時(shí)所做的變動(dòng)達(dá)到最小。一般來(lái)說(shuō),嵌入式Linux的內(nèi)存地址安排體現(xiàn)在連接腳本當(dāng)中。</p><p> 接著就該進(jìn)入編寫(xiě)啟動(dòng)代碼和機(jī)器相關(guān)代碼階段了。各種不同目標(biāo)系統(tǒng),甚至相同目標(biāo)系統(tǒng)的啟動(dòng)代碼和機(jī)器相關(guān)代碼也是不相同的
11、。啟動(dòng)代碼一般需要完成硬件初始化、裝載內(nèi)核、安裝根文件系統(tǒng)以及開(kāi)始內(nèi)核執(zhí)行的工作,不同目標(biāo)平臺(tái)的啟動(dòng)代碼一般可通過(guò)參考Linux下已有的啟動(dòng)代碼和相關(guān)CPU的手冊(cè)進(jìn)行編寫(xiě)。</p><p> 啟動(dòng)代碼和機(jī)器相關(guān)代碼編程完成,并可以啟動(dòng)系統(tǒng)后,下一步就可以開(kāi)始驅(qū)動(dòng)程序的編寫(xiě)了。嵌入式Linux系統(tǒng)驅(qū)動(dòng)程序開(kāi)發(fā)與普通Linux開(kāi)發(fā)并沒(méi)有太大的區(qū)別,都需要對(duì)相關(guān)的硬件作出了解,同時(shí)需要遵循Linux編寫(xiě)驅(qū)動(dòng)程序的一些
12、規(guī)則,編寫(xiě)完一個(gè)驅(qū)動(dòng)程序后,一般還要寫(xiě)一個(gè)相應(yīng)的測(cè)試程序以便隨時(shí)進(jìn)行測(cè)試。Linux下各種不同類(lèi)型的設(shè)備都有相當(dāng)多的驅(qū)動(dòng)程序源碼可以參考,因此實(shí)際編寫(xiě)時(shí)更多的時(shí)間是花在對(duì)特定硬件特性的熟悉上。</p><p> 除了以上提到的這些步驟外,進(jìn)行實(shí)際開(kāi)發(fā)時(shí),很多時(shí)候還要進(jìn)行庫(kù)(這里所提到的庫(kù)均指C庫(kù))、GUI和系統(tǒng)程序的移植。這是因?yàn)榍度胧絃inux中所用的庫(kù)一般不能直接使用標(biāo)準(zhǔn)庫(kù),而需要進(jìn)行精簡(jiǎn),雖然已有精簡(jiǎn)的C
13、庫(kù),如uClibc等可供使用,但還是需要經(jīng)常對(duì)其進(jìn)行修改。嵌入式Linux常用的GUI有Microwindows、MiniGUI、QT/Embedded、TinyX等,各自均有其使用的場(chǎng)合,所針對(duì)的目標(biāo)平臺(tái)和應(yīng)用層次也不一樣,必須根據(jù)實(shí)際需要進(jìn)行選擇。系統(tǒng)程序如mount、ls等有些是應(yīng)用時(shí)所必需的,有些則是進(jìn)行調(diào)試時(shí)所需要的,初始時(shí)則需要一些通用的系統(tǒng)程序。</p><p> 9.2 Linux開(kāi)發(fā)工具的使
14、用</p><p> 9.2.1 Linux開(kāi)發(fā)工具GNU gcc的使用</p><p> 在Linux平臺(tái)下,GNU gcc編譯器,即可以編譯Linux操作系統(tǒng)下運(yùn)行的應(yīng)用程序,又可以編譯Linux內(nèi)核本身,甚至可以交叉編譯運(yùn)行于其他CPU上的程序。下面介紹編譯程序GCC在編譯應(yīng)用程序的過(guò)程的具體用法、GCC的常用選項(xiàng)、模式和警告選項(xiàng)。</p><p>&l
15、t;b> GCC簡(jiǎn)介</b></p><p> 通常所說(shuō)的GCC是GNU Compiler Collection的簡(jiǎn)稱(chēng),除了編譯程序之外,它還含其他相關(guān)工具,所以它能把易于人類(lèi)使用的高級(jí)語(yǔ)言編寫(xiě)的源代碼構(gòu)建成計(jì)算機(jī)能夠直接執(zhí)行的二進(jìn)制代碼。GCC是Linux平臺(tái)下最常用的編譯程序,是Linux平臺(tái)編譯器的事實(shí)標(biāo)準(zhǔn)。同時(shí),在Linux平臺(tái)下的嵌入式開(kāi)發(fā)領(lǐng)域,GCC也是用得最普遍的一種編譯器。G
16、CC之所以被廣泛采用,是因?yàn)樗苤С指鞣N不同的目標(biāo)體系結(jié)構(gòu)。例如,它既支持基于宿主的開(kāi)發(fā)(簡(jiǎn)單講就是要為某平臺(tái)編譯程序,就在該平臺(tái)上編譯),也支持交叉編譯(即在A平臺(tái)上編譯的程序是供平臺(tái)B使用的)。目前,GCC支持的體系結(jié)構(gòu)有40余種,常見(jiàn)的有x86系列、Arm、PowerPC等。同時(shí),GCC還能運(yùn)行在不同的操作系統(tǒng)上,如Linux、Solaris、Windows等。除了上面講的之外,GCC除了支持C語(yǔ)言外,還支持多種其他語(yǔ)言,例如C+
17、+、Ada、Java、Objective-C、Fortram、Pascal等。</p><p> GCC常用模式及選項(xiàng)</p><p> gcc最基本的用法是:</p><p> gcc [options] file... </p><p> 其中option是以“-”開(kāi)始的各種選項(xiàng),file是相關(guān)的文件名。在使用gcc的時(shí),必須給出
18、必要的選項(xiàng)和文件名。gcc的整個(gè)編譯過(guò)程分別是:預(yù)處理、編譯,匯編和鏈接。</p><p> 表9.1 gcc編譯器中常用選項(xiàng)</p><p> 例如,$ gcc -o hello hello.c ,gcc編譯器就會(huì)生成一個(gè)hello的可執(zhí)行文件。在hello.c的當(dāng)前目錄下執(zhí)行./hello。</p><p> gcc編譯器生成的目標(biāo)文件默認(rèn)格式為elf(e
19、xecutive linked file)格式,這是Linux系統(tǒng)所采用的可執(zhí)行鏈接文件的通用文件格式。elf格式由若干個(gè)段(section)組成,如果沒(méi)有特別指明,由標(biāo)準(zhǔn)c源代碼生成的目標(biāo)文件中包含以下段:</p><p> ● .text(正文段)包含程序的指令代碼,</p><p> ● .data(數(shù)據(jù)段)包含固定的數(shù)據(jù),如常量,字符串等,</p><p&g
20、t; ● .bss(未初始化數(shù)據(jù)段)包含未初始化的變量和數(shù)組等。</p><p> GCC常用兩種模式:編譯模式和編譯連接模式。下面以一些命令來(lái)說(shuō)明各種模式的使用方法。為簡(jiǎn)單起見(jiàn),假設(shè)全部的源代碼都在一個(gè)文件test.c中。</p><p> $ gcc -o test </p><p> 此命令是把源文件test.c直接編譯成可執(zhí)行程序test。&l
21、t;/p><p> $ gcc -c test.c </p><p> 此命令是把源文件test.c編譯成不可執(zhí)行目標(biāo)文件test.o。默認(rèn)情況下,生成的目標(biāo)文件名為test.o,但也可以為輸出文件指定名稱(chēng),如下所示:</p><p> $ gcc -c test.c –o mytest.o</p><p> 此命令是把源文件test.
22、c編譯成不可執(zhí)行目標(biāo)文件test.o。</p><p> 下面的命令將同時(shí)編譯3個(gè)源文件,即first.c、second.c和 third.c,然后將它們連接成一個(gè)可執(zhí)行程序test。命令如下:</p><p> $ gcc -o test first.c second.c third.c</p><p> 3.其他常用選項(xiàng)的使用</p>
23、;<p> 許多情況下,頭文件和源文件會(huì)單獨(dú)存放在不同的目錄中。例如,假設(shè)存放源文件的子目錄名為./src,而包含文件則放在層次的其他目錄下,如./inc。當(dāng)在./src 目錄下進(jìn)行編譯工作時(shí),如何告訴GCC到哪里找頭文件呢?方法如下所示:</p><p> $ gcc test.c –I../inc -o test</p><p> 上面的命令告訴GCC包含文件存放在
24、./inc 目錄下,在當(dāng)前目錄的上一級(jí)。如果在編譯時(shí)需要的包含文件存放在多個(gè)目錄下,可以使用多個(gè)-I 來(lái)指定各個(gè)目錄。如:</p><p> $ gcc test.c –I../inc –I../../inc2 -o test</p><p> 這里指出了另一個(gè)包含子目錄inc2,較之前目錄它還要在再上兩級(jí)才能找到。另外,還可以在編譯命令行中定義符號(hào)常量。為此,可以簡(jiǎn)單的在命令行中使用
25、-D選項(xiàng)即可,如下例所示:</p><p> $ gcc –D TEST_CONFIGURATION test.c -o test</p><p> 上面的命令與在源文件中加入下列命令是等效的:</p><p> #define TEST_CONFIGURATION</p><p><b> 4. 警告功能</b>
26、;</p><p> 當(dāng)GCC在編譯過(guò)程中檢查出錯(cuò)誤時(shí),它就會(huì)中止編譯;但檢測(cè)到警告時(shí)卻能繼續(xù)編譯生成可執(zhí)行程序,因?yàn)榫嬷皇轻槍?duì)程序結(jié)構(gòu)的診斷信息,它不能說(shuō)明程序一定有錯(cuò)誤,而是存在風(fēng)險(xiǎn),或者可能存在錯(cuò)誤。雖然GCC提供了非常豐富的警告,但前提是已經(jīng)啟用了它們,否則它不會(huì)報(bào)告這些檢測(cè)到的警告。</p><p> 在眾多的警告選項(xiàng)之中,最常用的就是-Wall選項(xiàng)。該選項(xiàng)能發(fā)現(xiàn)程序中一系
27、列的常見(jiàn)錯(cuò)誤警告,該選項(xiàng)用法舉例如下:</p><p> $ gcc -Wall test.c -o test</p><p> 該選項(xiàng)相當(dāng)于同時(shí)使用了下列所有的選項(xiàng):</p><p> ● unused-function:遇到僅聲明過(guò)但尚未定義的靜態(tài)函數(shù)時(shí)發(fā)出警告。</p><p> ● unused-label:遇到聲明過(guò)但不使用
28、的標(biāo)號(hào)的警告。</p><p> ● unused-parameter:從未用過(guò)的函數(shù)參數(shù)的警告。</p><p> ● unused-variable:在本地聲明但從未用過(guò)的變量的警告。</p><p> ● unused-value:僅計(jì)算但從未用過(guò)的值的警告。</p><p> ● format:檢查對(duì)printf和scanf等
29、函數(shù)的調(diào)用,確認(rèn)各參數(shù)類(lèi)型和格式串中的一致。</p><p> ● implicit-int:警告沒(méi)有規(guī)定類(lèi)型的聲明。</p><p> ● implicit-function-:在函數(shù)在未經(jīng)聲明就使用時(shí)給予警告。</p><p> ● char-subscripts:警告把char類(lèi)型作為數(shù)組下標(biāo)。</p><p> ● missi
30、ng-braces:聚合初始化兩邊缺少大括號(hào)。</p><p> ● Parentheses:在某些情況下如果忽略了括號(hào),編譯器就發(fā)出警告。</p><p> ● return-type:如果函數(shù)定義了返回類(lèi)型,而默認(rèn)類(lèi)型是int型,編譯器就發(fā)出警告。同時(shí)警告那些不帶返回值的 return語(yǔ)句,如果他們所屬的函數(shù)并非void類(lèi)型。</p><p> ● seq
31、uence-point:出現(xiàn)可疑的代碼元素時(shí),發(fā)出報(bào)警。</p><p> ● Switch:如果某條switch語(yǔ)句的參數(shù)屬于枚舉類(lèi)型,但是沒(méi)有對(duì)應(yīng)的case語(yǔ)句使用枚舉元素,編譯器就發(fā)出警告(在switch語(yǔ)句中使用default分支能夠防止這個(gè)警告)。超出枚舉范圍的case語(yǔ)句同樣會(huì)導(dǎo)致這個(gè)警告。</p><p> ● strict-aliasing:對(duì)變量別名進(jìn)行最嚴(yán)格的檢查。
32、</p><p> ● unknown-pragmas:使用了不允許的#pragma。</p><p> ● Uninitialized:在初始化之前就使用自動(dòng)變量。</p><p> 需要注意的是,各警告選項(xiàng)既然能使之生效,當(dāng)然也能使之關(guān)閉。比如假設(shè)我們想要使用-Wall來(lái)啟用個(gè)選項(xiàng),同時(shí)又要關(guān)閉unused警告,利益通過(guò)下面的命令來(lái)達(dá)到目的:</p&
33、gt;<p> $ gcc -Wall -Wno-unused test.c -o test</p><p> 下面是使用-Wall選項(xiàng)的時(shí)候沒(méi)有生效的一些警告項(xiàng):</p><p> ● cast-align:一旦某個(gè)指針類(lèi)型強(qiáng)制轉(zhuǎn)換時(shí),會(huì)導(dǎo)致目標(biāo)所需的地址對(duì)齊邊界擴(kuò)展,編譯器就發(fā)出警告。例如,某些機(jī)器上只能在2或4字節(jié)邊界上訪問(wèn)整數(shù),如果在這種機(jī)型上把char *強(qiáng)制
34、轉(zhuǎn)換成int *類(lèi)型, 編譯器就發(fā)出警告。</p><p> ● sign-compare:將有符號(hào)類(lèi)型和無(wú)符號(hào)類(lèi)型數(shù)據(jù)進(jìn)行比較時(shí)發(fā)出警告。</p><p> ● missing-prototypes :如果沒(méi)有預(yù)先聲明函數(shù)原形就定義了全局函數(shù),編譯器就發(fā)出警告。即使函數(shù)定義自身提供了函數(shù)原形也會(huì)產(chǎn)生這個(gè)警告。這樣做的目的是檢查沒(méi)有在頭文件中聲明的全局函數(shù)。</p>&l
35、t;p> ● packed:當(dāng)結(jié)構(gòu)體帶有packed屬性但實(shí)際并沒(méi)有出現(xiàn)緊縮式給出警告。</p><p> ● padded:如果結(jié)構(gòu)體通過(guò)充填進(jìn)行對(duì)齊則給出警告。</p><p> ● unreachable-code:如果發(fā)現(xiàn)從未執(zhí)行的代碼時(shí)給出警告。</p><p> ● inline:如果某函數(shù)不能內(nèi)嵌(inline),無(wú)論是聲明為inline
36、或者是指定了-finline-functions 選項(xiàng),編譯器都將發(fā)出警告。 </p><p> ● disabled-optimization:當(dāng)需要太長(zhǎng)時(shí)間或過(guò)多資源導(dǎo)致不能完成某項(xiàng)優(yōu)化時(shí)給出警告。</p><p> 9.2.2 GDB調(diào)試器簡(jiǎn)介 </p><p> Linux系統(tǒng)中包含了GNU 調(diào)試程序gdb,它是一個(gè)用來(lái)調(diào)試C和 C++ 程序的調(diào)試器
37、??梢允钩绦蜷_(kāi)發(fā)者在程序運(yùn)行時(shí)觀察程序的內(nèi)部結(jié)構(gòu)和內(nèi)存的使用情況。gdb 提供如下功能:</p><p> ● 運(yùn)行程序,設(shè)置所有的能影響程序運(yùn)行的參數(shù)和環(huán)境。</p><p> ● 控制程序在指定的條件下停止運(yùn)行。 </p><p> ● 當(dāng)程序停止時(shí),可以檢查程序的狀態(tài)。</p><p> ● 修改程序的錯(cuò)誤,并重新運(yùn)行程序。
38、</p><p> ● 動(dòng)態(tài)監(jiān)視程序中變量的值。 </p><p> ● 可以單步執(zhí)行代碼,觀察程序的運(yùn)行狀態(tài)。 </p><p> gdb程序調(diào)試的對(duì)象是可執(zhí)行文件,而不是程序的源代碼文件。然而,并不是所有的可執(zhí)行文件都可以用gdb調(diào)試。如果要讓產(chǎn)生的可執(zhí)行文件可以用來(lái)調(diào)試,需在執(zhí)行g(shù)cc指令編譯程序時(shí),加上-g參數(shù),指定程序在編譯時(shí)包含調(diào)試信息。調(diào)試信息包
39、含程序里的每個(gè)變量的類(lèi)型和在可執(zhí)行文件里的地址映射以及源代碼的行號(hào)。gdb 利用這些信息使源代碼和機(jī)器碼相關(guān)聯(lián)。</p><p><b> 1.gdb的啟動(dòng)</b></p><p> 在終端窗口中,有兩種方法運(yùn)行g(shù)db,即在終端窗口的命令行中直接輸入gdb命令或gdb filename命令運(yùn)行g(shù)db,下面分別介紹。</p><p><
40、b> 方法1:</b></p><p> 先啟動(dòng)gdb后執(zhí)行file filename命令。即</p><p><b> gdb</b></p><p> file filename</p><p> 執(zhí)行上述兩條命令就可啟動(dòng)gdb,并裝入可執(zhí)行的程序filename。</p>
41、<p><b> 方法2:</b></p><p> 啟動(dòng)gdb的同時(shí)裝入可執(zhí)行的程序。即</p><p> gdb filename</p><p> 其中,filename是要調(diào)試的可執(zhí)行文件。用這種方式運(yùn)行g(shù)db可以直接指定想要調(diào)試的程序。這和啟動(dòng)gdb后執(zhí)行file filename命令效果完全一樣。</p>
42、;<p> 啟動(dòng)gdb后,就可以使用gdb的命令調(diào)試程序。</p><p> 2.gdb的基本命令</p><p> gdb中的命令主要分為以下幾類(lèi):工作環(huán)境相關(guān)命令、設(shè)置斷點(diǎn)與恢復(fù)命令、源代碼查看命令、查看運(yùn)行數(shù)據(jù)相關(guān)命令及修改運(yùn)行參數(shù)命令。gdb的命令可以通過(guò)help命令進(jìn)行查找命令所屬的種類(lèi)(class),可以從相關(guān)class找到相應(yīng)命令。如下所示:</p&
43、gt;<p> (gdb) help 此命令可列出命令的種類(lèi)。</p><p> (gdb) help data 此命令查找data類(lèi)種的命令,并列出data類(lèi)種的所有命令。</p><p> (gdb) help call 此命令查找call命令。</p><p> 若用戶(hù)已知命令名,直接鍵入“help [comma
44、nd]”來(lái)查看命令。</p><p> 下面分別對(duì)這幾類(lèi)的命令進(jìn)行講解。</p><p> ?。?)工作環(huán)境相關(guān)命令</p><p> gdb中不僅可以調(diào)試所運(yùn)行的程序,而且還可以對(duì)程序相關(guān)的工作環(huán)境進(jìn)行相應(yīng)的設(shè)定,甚至還可以使用shell中的命令進(jìn)行相關(guān)的操作,其功能極其強(qiáng)大。表9.2所示列出了gdb常見(jiàn)工作環(huán)境相關(guān)命令。</p><p&g
45、t; 表9.2 gdb工作環(huán)境相關(guān)命令</p><p> (2) 設(shè)置斷點(diǎn)與恢復(fù)命令</p><p> gdb中設(shè)置斷點(diǎn)與恢復(fù)的常見(jiàn)命令如表9.3所示。</p><p> 表9.3 gdb設(shè)置斷點(diǎn)與恢復(fù)相關(guān)命令</
46、p><p> ?。?)gdb中源碼查看相關(guān)命令</p><p> 在gdb中可以查看源碼以方便其他操作,它的常見(jiàn)相關(guān)命令如表9.4所示:</p><p> 表9.4 gdb源碼查看相關(guān)相關(guān)命令</p><p> (4) gdb中查看運(yùn)行數(shù)據(jù)相關(guān)命令</p><p&
47、gt; gdb中查看運(yùn)行數(shù)據(jù)是指當(dāng)程序處于“運(yùn)行”或“暫?!睜顟B(tài)時(shí),可以查看的變量及表達(dá)式的信息,其常見(jiàn)命令如表9.5所示:</p><p> 表9.5 gdb查看運(yùn)行數(shù)據(jù)相關(guān)命令</p><p> ?。?)其他gdb命令</p><p> ● run命令:執(zhí)行當(dāng)前被
48、調(diào)試的程序。 </p><p> ● kill命令:停止正在調(diào)試的應(yīng)用程序。 </p><p> ● watch命令:設(shè)置監(jiān)視點(diǎn),監(jiān)視表達(dá)式的變化。 </p><p> ● awatch命令:設(shè)置讀寫(xiě)監(jiān)視點(diǎn)。當(dāng)要監(jiān)視的表達(dá)式被讀或?qū)憰r(shí)將應(yīng)用程序掛起。它的語(yǔ)法與watch命令相同。 </p><p> ● rwatch命令:設(shè)置讀監(jiān)視
49、點(diǎn),當(dāng)監(jiān)視表達(dá)式被讀時(shí)將程序掛起,等侍調(diào)試。此命令的語(yǔ)法與watch相同。 </p><p> ● info break命令:顯示當(dāng)前斷點(diǎn)列表,包括每個(gè)斷點(diǎn)到達(dá)的次數(shù)。 </p><p> ● info files命令:顯示調(diào)試文件的信息。 </p><p> ● info func命令:顯示所有的函數(shù)名。 </p><p> ●
50、info local命令:顯示當(dāng)前函數(shù)的所有局部變量的信息。 </p><p> ● info prog命令:顯示調(diào)試程序的執(zhí)行狀態(tài)。 </p><p> ● Shell命令:執(zhí)行Linux Shell命令。 </p><p> ● make命令:不退出gdb而重新編譯生成可執(zhí)行文件。 </p><p> ● Quit命令:退出gdb
51、。</p><p> (6) gdb中修改運(yùn)行參數(shù)相關(guān)命令</p><p> gdb還可以修改運(yùn)行時(shí)的參數(shù),并使該變量按照用戶(hù)當(dāng)前輸入的值繼續(xù)運(yùn)行。它的設(shè)置方法為:在單步執(zhí)行的過(guò)程中,鍵入命令“set 變量=設(shè)定值”。這樣,在此之后,程序就會(huì)按照該設(shè)定的值運(yùn)行了。 </p><p> 特別注意,在gcc編譯選項(xiàng)中一定要加入”-g”。只有在代碼處于“運(yùn)行”或“暫
52、停”狀態(tài)時(shí)才能查看變量值,設(shè)置斷點(diǎn)后程序在指定行之前停止。</p><p> 9.3 GNU make命令和makefile 文件</p><p> Makefile文件描述了目標(biāo)文件之間的依賴(lài)關(guān)系,以及指定編譯過(guò)程中使用的工具。Makefile里主要包含了五個(gè)方面:顯式規(guī)則、隱晦規(guī)則、變量定義、文件指示和注釋。</p><p> ● 顯式規(guī)則。顯式規(guī)則說(shuō)明
53、了如何生成一個(gè)或多個(gè)目標(biāo)文件。這是由Makefile的書(shū)寫(xiě)者明顯指出,要生成的文件、文件的依賴(lài)文件、生成的命令。</p><p> ● 隱晦規(guī)則。由于make有自動(dòng)推導(dǎo)的功能,所以隱晦的規(guī)則可以讓我們比較簡(jiǎn)略地書(shū)寫(xiě)Makefile,這是由make所支持的。</p><p> ● 變量的定義。在Makefile中可定義一系列的變量,變量一般是字符串,類(lèi)似C語(yǔ)言中的宏,當(dāng)Makefile被
54、執(zhí)行時(shí),其中的變量都會(huì)被擴(kuò)展到相應(yīng)的引用位置上。</p><p> ● 文件指示。其包括3個(gè)部分,一個(gè)是在一個(gè)Makefile中引用另一個(gè)Makefile,就像C語(yǔ)言中的include一樣;另一個(gè)是指根據(jù)某些情況指定Makefile中的有效部分,就像C語(yǔ)言中的預(yù)編譯#if一樣;還有就是定義一個(gè)多行的命令。</p><p> ● 注釋。Makefile中只有行注釋?zhuān)蚒NIX的Shell
55、腳本一樣,其注釋是用“#”字符,如果在Makefile中使用“#”字符,可以用反斜框進(jìn)行轉(zhuǎn)義,如:“\#”。</p><p> 最后,還值得一提的是,在Makefile中的命令,必須要以[Tab]鍵開(kāi)始。</p><p> Makefile定義了一系列的規(guī)則來(lái)指定哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進(jìn)行更復(fù)雜的功能操作。Makefile就像一個(gè)Shell
56、腳本一樣,其中也可以執(zhí)行操作系統(tǒng)的命令。Makefile帶來(lái)的好處就是“自動(dòng)化編譯”,一旦寫(xiě)好,只需要一個(gè)make命令,整個(gè)工程完全自動(dòng)編譯,極大地提高了軟件開(kāi)發(fā)的效率。GNU的make工作時(shí)的執(zhí)行步驟如下:</p><p> 讀入所有的Makefile。</p><p> 讀入被include的其它Makefile。</p><p> 初始化文件中的變量。&
57、lt;/p><p> 推導(dǎo)隱晦規(guī)則,并分析所有規(guī)則。</p><p> 為所有的目標(biāo)文件創(chuàng)建依賴(lài)關(guān)系鏈。</p><p> 根據(jù)依賴(lài)關(guān)系,決定哪些目標(biāo)要重新生成。</p><p><b> 執(zhí)行生成命令。</b></p><p> 1-5步為第一個(gè)階段,6-7為第二個(gè)階段。第一個(gè)階段中,如果
58、定義的變量被使用了,那么,make會(huì)把其展開(kāi)在使用的位置。但make并不會(huì)完全馬上展開(kāi)。make程序利用Makefile中的數(shù)據(jù)和每個(gè)文件的最后修改時(shí)間來(lái)確定那個(gè)文件需要更新,對(duì)于需要更新的文件,make程序執(zhí)行Makefile數(shù)據(jù)中定義的命令來(lái)更新。 </p><p> 9.3.1 Makefile文件的規(guī)則 </p><p> GNU make的主要功能是讀入一個(gè)文本文件make
59、file,并根據(jù)makefile的內(nèi)容執(zhí)行一系列的工作。Makefile的默認(rèn)文件名為GNU makefile、makefile或Makefile,也可以在make的命令行中指定別的文件名。如果不特別指定,make命令在執(zhí)行時(shí)將按順序查找默認(rèn)的Makefile文件。多數(shù)Linux程序員使用第三種文件名Makefile。因?yàn)榈谝粋€(gè)字母是大寫(xiě),通常被列在一個(gè)目錄的文件列表的最前面。 </p><p> Makefi
60、le文件包含一些規(guī)則。這些規(guī)則主要是描述哪些文件(稱(chēng)為target目標(biāo)文件,注意,不是指編譯時(shí)產(chǎn)生的目標(biāo)文件)是從哪些別的文件(稱(chēng)為dependency依賴(lài)文件)中產(chǎn)生的,以及用什么命令(command)來(lái)執(zhí)行這個(gè)過(guò)程。</p><p> 依靠這些信息,make會(huì)對(duì)磁盤(pán)上的文件進(jìn)行檢查,如果目標(biāo)文件的生成或被改動(dòng)時(shí)的時(shí)間(稱(chēng)為該文件時(shí)間戳)至少比它的一個(gè)依賴(lài)文件還舊的話(huà),make就執(zhí)行相應(yīng)的命令,以更新目標(biāo)文件
61、。目標(biāo)文件不一定是最后的可執(zhí)行文件,可以是任何一個(gè)中間文件并可以作為其他目標(biāo)文件的依賴(lài)文件。</p><p> 1.Makefile書(shū)寫(xiě)規(guī)則</p><p> 一個(gè)Makefile文件主要含有一系列的規(guī)則,每條規(guī)則包含以下內(nèi)容。</p><p> ● 一個(gè)目標(biāo)(target),即make最終需要?jiǎng)?chuàng)建的文件,如可執(zhí)行文件和目標(biāo)文件;目標(biāo)也可以是要執(zhí)行的動(dòng)作,如c
62、lean。</p><p> ● 一個(gè)或多個(gè)依賴(lài)文件(dependency)列表,通常是編譯目標(biāo)文件所需要的其他文件。</p><p> ● 一系列命今(command),是make執(zhí)行的動(dòng)作,通常是把指定的相關(guān)文件編譯成目標(biāo)文件的編譯命令,每個(gè)命令占一行,且每個(gè)命令行起始字符必須為T(mén)AB字符。 </p><p> 除非特別指定,否則make的工作目錄就是當(dāng)前
63、目錄。target是需要?jiǎng)?chuàng)建的二進(jìn)制文件或目標(biāo)文件,dependency是在創(chuàng)建target時(shí)需要用到的一個(gè)或多個(gè)文件的列表,命令序列是創(chuàng)建target文件所需要執(zhí)行的步驟,比如編譯命令。</p><p> Makefile規(guī)則的一般形式如下:</p><p> target:dependency dependency</p><p> (tab)<co
64、mmand> </p><p> 例如,有以下的Makefile文件:</p><p> # 一個(gè)簡(jiǎn)單的Makefile的例子</p><p> test:prog.o code.o</p><p> gcc –o test prog.o code.o</p><p> prog.o:prog.c pr
65、og.h code.h</p><p> gcc –c prog.c –o prog.o</p><p> code.o:code.c code.h</p><p> gcc –c code.c –o code.o</p><p><b> clean:</b></p><p> rm
66、–f *.o </p><p> 上面的Makefile文件中共定義了4個(gè)目標(biāo):test、prog.o、code.o和clean。目標(biāo)從每行的最左邊開(kāi)始寫(xiě),后面跟一個(gè)冒號(hào)(:),如果有與這個(gè)目標(biāo)有依賴(lài)性的其他目標(biāo)或文件,把它們列在冒號(hào)后面,并以空格隔開(kāi)。然后另起一行開(kāi)始寫(xiě)實(shí)現(xiàn)這個(gè)目標(biāo)的一組命令。在Makefile中,可使用續(xù)行號(hào)(\)將一個(gè)單獨(dú)的命令行延續(xù)成幾行。但要注意在續(xù)行號(hào)(\)后面不能跟任何字符(包括空
67、格和鍵)。</p><p> 一般情況下,調(diào)用make命令可輸入:</p><p> # make target</p><p> target是Makefile文件中定義的目標(biāo)之一,如果省略target,make就將生成Makefile文件中定義的第一個(gè)目標(biāo)。對(duì)于上面Makefile的例子,單獨(dú)的一個(gè)make命令等價(jià)于:</p><p&g
68、t; # make test</p><p> 因?yàn)閠est是Makefile文件中定義的第一個(gè)目標(biāo),make首先將其讀入,然后從第一行開(kāi)始執(zhí)行,把第一個(gè)目標(biāo)test作為它的最終目標(biāo),所有后面的目標(biāo)的更新都會(huì)影響到test的更新。第一條規(guī)則說(shuō)明只要文件test的時(shí)間戳比文件prog.o或code.o中的任何一個(gè)舊,下一行的編譯命令將會(huì)被執(zhí)行。 </p><p> 內(nèi)核源代碼中Make
69、file被分布在目錄樹(shù)中,與Makefile直接相關(guān)的文件有配置文件.config和規(guī)則文件Rules.make。頂層Makefile是整個(gè)內(nèi)核配置、編譯的總體控制文件。在頂層Makefile中的語(yǔ)句:include arch/$(ARCH)/Makefile,包含了特定CPU體系結(jié)構(gòu)下的Makefile,這個(gè)Makefile中包含了平臺(tái)相關(guān)的信息。配置文件.config包含由用戶(hù)選擇項(xiàng),用來(lái)存放內(nèi)核配置后的結(jié)果(如make confi
70、g)。位于各種CPU體系目錄下的Makefile,比如drivers/Makefile,負(fù)責(zé)所在子目錄下源代碼的管理。規(guī)則文件Rules.make,則被所有的Makefile使用。</p><p> 用戶(hù)通過(guò)make config配置后,產(chǎn)生了.config。頂層Makefile讀入.config中的配置選擇。頂層Makefile有兩個(gè)主要的任務(wù):產(chǎn)生壓縮的內(nèi)核鏡像vmlinux文件和內(nèi)核模塊module。為了
71、達(dá)到此目的,頂層Makefile遞歸的進(jìn)入到內(nèi)核的各個(gè)子目錄中,分別調(diào)用位于子目錄中的Makefile。至于到底進(jìn)入哪些子目錄,取決于內(nèi)核的配置。位于各個(gè)子目錄下的Makefile同樣也根據(jù).config給出的配置信息,構(gòu)造出當(dāng)前配置下需要的源文件列表,并在文件的最后有include $(TOPDIR)/ Rules.make。</p><p> 2. 在規(guī)則中使用通配符</p><p>
72、; 如果定義一系列比較類(lèi)似的文件,很自然地就想起使用通配符。make支持3種通配符:“*”,“?”和“[...]”。這是和Unix的B-Shell是相同的。</p><p> 波浪號(hào)(“~”)字符在文件名中有特殊的用途。如“~test”表示當(dāng)前用戶(hù)的$HOME目錄下的test目錄。而“~hchen/test”則表示用戶(hù)hchen的宿主目錄下的 test目錄。通配符 “*.c”表示所有以后綴為c的文件。例如:&
73、lt;/p><p> print: *.c</p><p><b> lpr -p $?</b></p><p> touch print</p><p> 該例說(shuō)明目標(biāo)print依賴(lài)于所有的[.c]文件。其中的“$?”是一個(gè)自動(dòng)化變量。</p><p><b> 3.偽目標(biāo)<
74、;/b></p><p> 偽目標(biāo)又稱(chēng)假想目標(biāo),如:</p><p><b> clean:</b></p><p> rm *.o temp</p><p> 這里并不生成“clean”這個(gè)文件?!皞文繕?biāo)”并不是一個(gè)文件,只是一個(gè)標(biāo)簽,由于“偽目標(biāo)”不是文件,所以make無(wú)法生成它的依賴(lài)關(guān)系和決定它是否要
75、執(zhí)行。</p><p> 可使用“make clean”來(lái)使用該目標(biāo)。</p><p> 如果你的Makefile需要生成若干個(gè)可執(zhí)行文件,可把所有的目標(biāo)文件都寫(xiě)在一個(gè)Makefile中,可聲明了一個(gè)“all”的偽目標(biāo),例如:</p><p> all : prog1 prog2 prog3</p><p> prog1 : prog
76、1.o utils.o</p><p> cc -o prog1 prog1.o utils.o</p><p> prog2 : prog2.o</p><p> cc -o prog2 prog2.o</p><p> prog3 : prog3.o sort.o utils.o</p><p> cc
77、-o prog3 prog3.o sort.o utils.o</p><p> 上面的Makefile中的第一個(gè)目標(biāo)“all”會(huì)被作為其默認(rèn)目標(biāo),其依賴(lài)于其它3個(gè)目標(biāo)。由于偽目標(biāo)總是被執(zhí)行的,其依賴(lài)的那3個(gè)目標(biāo)就總是不如“all”這個(gè)目標(biāo)新。所以,其它3個(gè)目標(biāo)的規(guī)則總是會(huì)被決議。也就達(dá)到了連續(xù)生成多個(gè)目標(biāo)的目的。從上面的例子可以看出,目標(biāo)也可以成為依賴(lài),偽目標(biāo)同樣也可成為依賴(lài)。</p><
78、p> 9.3.2 Makefile文件中隱含規(guī)則</p><p> “隱含規(guī)則”是指在Makefile中的“隱含的”,早先約定了的、不需要再寫(xiě)出來(lái)的規(guī)則。若要使用隱含規(guī)則生成需要的目標(biāo),make會(huì)試圖去自動(dòng)推導(dǎo)產(chǎn)生這個(gè)目標(biāo)的規(guī)則和命令,若make可以自動(dòng)推導(dǎo)生成這個(gè)目標(biāo)的規(guī)則和命令,那么這個(gè)行為就是隱含規(guī)則的自動(dòng)推導(dǎo)。</p><p><b> 1.常用的隱含規(guī)則&
79、lt;/b></p><p> ● 編譯C程序的隱含規(guī)則:<n>.o的目標(biāo)的依賴(lài)目標(biāo)會(huì)自動(dòng)推導(dǎo)為<n>.c,并且其生成命令是$(CC) –c $(CPPFLAGS) $(CFLAGS)。</p><p> ● 編譯C++程序的隱含規(guī)則:<n>.o的目標(biāo)的依賴(lài)目標(biāo)會(huì)自動(dòng)推導(dǎo)為<n>.cc或是<n>.C,并且其生成命令是$(
80、CXX) –c $(CPPFLAGS) $(CFLAGS)。(建議使用.cc作為C++源文件的后綴,而不是.C)</p><p> ● 匯編和匯編預(yù)處理的隱含規(guī)則:<n>.o的目標(biāo)的依賴(lài)目標(biāo)會(huì)自動(dòng)推導(dǎo)為<n>.s,默認(rèn)使用編譯器as,并且其生成命令是:$(AS) $(ASFLAGS)。<n>.s的目標(biāo)的依賴(lài)目標(biāo)會(huì)自動(dòng)推導(dǎo)為<n>.S,默認(rèn)使用C預(yù)編譯器cpp,并且
81、其生成命令是:$(AS) $(ASFLAGS)。</p><p> ● 鏈接Object文件的隱含規(guī)則——<n>目標(biāo)依賴(lài)于<n>.o,通過(guò)運(yùn)行C 的編譯器來(lái)運(yùn)行鏈接程序生成(一般是ld),其生成命令是:$(CC) $(LDFLAGS) <n>.o $(LOADLIBES) $(LDLIBS)。這個(gè)規(guī)則對(duì)于只有一個(gè)源文件的工程有效,同時(shí)也對(duì)多個(gè)Object文件(由不同的源文件生
82、成)也有效。</p><p> 2.隱含規(guī)則使用的變量</p><p> 在隱含規(guī)則的命令中,基本上都是使用了一些預(yù)先設(shè)置的變量??梢栽贛akefile中改變這些變量的值,或是在make的命令行中傳入這些值,或是在環(huán)境變量中設(shè)置這些值。當(dāng)然,也可以利用make的-R或--no–builtin-variables參數(shù)來(lái)取消所定義的變量對(duì)隱含規(guī)則的作用。下面是隱含規(guī)則中常用到的變量。<
83、;/p><p> ?。?)關(guān)于命令的變量。</p><p> ● AR :函數(shù)庫(kù)打包程序。默認(rèn)命令是ar。</p><p> ● AS :匯編語(yǔ)言編譯程序。默認(rèn)命令是as。</p><p> ● CC :C語(yǔ)言編譯程序。默認(rèn)命令是cc。</p><p> ● CXX :C++語(yǔ)言編譯程序。默認(rèn)命令是g++。<
84、/p><p> ● CPP :C程序的預(yù)處理器(輸出是標(biāo)準(zhǔn)輸出設(shè)備)。默認(rèn)命令是$(CC) –E。</p><p> ● RM :刪除文件命令。默認(rèn)命令是rm –f。</p><p> (2)關(guān)于命令參數(shù)的變量</p><p> 以下變量都是相關(guān)上面的命令的參數(shù)。若沒(méi)有指明其默認(rèn)值,則其默認(rèn)值都是空。</p><p&
85、gt; ● ARFLAGS :函數(shù)庫(kù)打包程序AR命令的參數(shù)。默認(rèn)值是rv。</p><p> ● ASFLAGS :匯編語(yǔ)言編譯器參數(shù)。(當(dāng)明顯地調(diào)用“.s”或“.S”文件時(shí))。</p><p> ● CFLAGS :C語(yǔ)言編譯器參數(shù)。</p><p> ● CXXFLAGS :C++語(yǔ)言編譯器參數(shù)。</p><p> ● CPPF
86、LAGS :C預(yù)處理器參數(shù)。( C 和 Fortran 編譯器也會(huì)用到)。</p><p> ● FFLAGS :Fortran語(yǔ)言編譯器參數(shù)。</p><p> ● GFLAGS :SCCS get程序參數(shù)。</p><p> ● LDFLAGS :鏈接器參數(shù)。(如:ld)</p><p><b> 3.自動(dòng)化變量<
87、;/b></p><p> 自動(dòng)化變量只出現(xiàn)在規(guī)則的命令中,這種變量會(huì)把模式中所定義的一系列的文件自動(dòng)地挨個(gè)取出,直至所有的符合模式的文件都取完了。常用的自動(dòng)化變量如下。</p><p> ● $@ :表示規(guī)則中的目標(biāo)文件集。在模式規(guī)則中,如果有多個(gè)目標(biāo),那么,"$@"就是匹配于目標(biāo)中模式定義的集合。</p><p> ● $% :僅
88、當(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]),那么,其值為空。</p><p> ● $< :依賴(lài)目標(biāo)中的第一個(gè)目標(biāo)名字。如果依賴(lài)目標(biāo)是以模式(即"%")定義的,那么"$<"將是符合模式的
89、一系列的文件集。注意,是一個(gè)一個(gè)取出來(lái)的。</p><p> ● $? :所有比目標(biāo)新的依賴(lài)目標(biāo)的集合,以空格分隔。</p><p> ● $^ :所有的依賴(lài)目標(biāo)的集合,以空格分隔。如果在依賴(lài)目標(biāo)中有多個(gè)重復(fù)的,那個(gè)這個(gè)變量會(huì)去除重復(fù)的依賴(lài)目標(biāo),只保留一份。</p><p> ● $+ :這個(gè)變量很像"$^",也是所有依賴(lài)目標(biāo)的集合。只是它
90、不去除重復(fù)的依賴(lài)目標(biāo)。</p><p> ● $* :這個(gè)變量表示不包含擴(kuò)展名的目標(biāo)文件名,即目標(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í)別的,那么$*就是除了后綴的那一部分
91、。例如:如果目標(biāo)是foo.c,因?yàn)?c是make所能識(shí)別的后綴名,所以,$*的值就是foo。這個(gè)特性是GNU make的,很有可能不兼容于其它版本的make,所以,你應(yīng)該盡量避免使用$*,除非是在隱含規(guī)則或是靜態(tài)模式中。</p><p> 對(duì)于上面的七個(gè)變量都可以分別加上D或是F,表示取文件的目錄部分和文件部分。下面以$@為例說(shuō)明其含義:</p><p> ● $(@D) :表示$@的
92、目錄部分(不以斜杠作為結(jié)尾),如果$@值是dir/foo.o,那么$(@D)就是dir,若$@中沒(méi)有包含斜杠的話(huà),其值就是“.”(當(dāng)前目錄)。</p><p> ● $(@F) :表示$@的文件部分,如果$@值是dir/foo.o,那么$(@F) 就是foo.o,$(@F)相當(dāng)于函數(shù)$(notdir $@)。</p><p> 9.3.3 Makefile文件的命令 </p&g
93、t;<p> 每條規(guī)則中的命令和操作系統(tǒng)Shell的命令行是一致的。make會(huì)一按順序一條一條的執(zhí)行命令,每條命令的開(kāi)頭必須以Tab鍵開(kāi)頭,除非命令是緊跟在依賴(lài)規(guī)則后面的分號(hào)后的。在命令行之間中的空格或是空行會(huì)被忽略,但是如果該空格或空行是以Tab鍵開(kāi)頭的,那么make會(huì)認(rèn)為其是一個(gè)空命令。</p><p><b> 1.顯示命令</b></p><p&
94、gt; 通常,make會(huì)把其要執(zhí)行的命令行在命令執(zhí)行前輸出到屏幕上。當(dāng)用“@”字符在命令行前,那么,這個(gè)命令將不被make顯示出來(lái),如:</p><p> @echo 正在編譯XXX模塊......</p><p> 當(dāng)make執(zhí)行時(shí),會(huì)輸出“正在編譯XXX模塊......”字符串,但不會(huì)輸出命令,如果沒(méi)有“@”,那么,make將輸出:</p><p> e
95、cho 正在編譯XXX模塊......</p><p> 正在編譯XXX模塊......</p><p> 如果make執(zhí)行時(shí),帶入make參數(shù)-n或--just-print,則只是顯示命令,而不會(huì)執(zhí)行命令,這個(gè)功能很有利于調(diào)試Makefile文件。</p><p> 而make參數(shù)-s或--slient則是全面禁止命令的顯示。</p><
96、p><b> 2.命令執(zhí)行</b></p><p> 當(dāng)依賴(lài)目標(biāo)新于目標(biāo)時(shí),也就是當(dāng)規(guī)則的目標(biāo)需要被更新時(shí),make會(huì)一條一條的執(zhí)行其后的命令。如果要讓上一條命令的結(jié)果應(yīng)用到下一條命令時(shí),應(yīng)該使用分號(hào)分隔這兩條命令。比如第一條命令是cd命令,希望第二條命令得在cd之后的基礎(chǔ)上運(yùn)行,那么就不能把這兩條命令寫(xiě)在兩行上,而應(yīng)該把這兩條命令寫(xiě)在一行上,用分號(hào)分隔。如:</p>
97、<p><b> exec:</b></p><p> cd /home/hchen; pwd</p><p> 當(dāng)執(zhí)行“make exec”時(shí),cd就起作用了,pwd會(huì)打印出“/home/hchen”。</p><p><b> 3.命令出錯(cuò)</b></p><p> 每當(dāng)命
98、令運(yùn)行完后,make會(huì)檢測(cè)每個(gè)命令的返回碼,如果命令返回成功,那么make會(huì)執(zhí)行下一條命令,當(dāng)規(guī)則中所有的命令成功返回后,這個(gè)規(guī)則就算是成功完成了。如果一個(gè)規(guī)則中的某個(gè)命令出錯(cuò)了(命令退出碼非零),那么make就會(huì)終止執(zhí)行當(dāng)前規(guī)則,這將有可能終止所有規(guī)則的執(zhí)行。</p><p> 有時(shí),命令的出錯(cuò)并不表示就是錯(cuò)誤的。例如mkdir命令,用戶(hù)一定需要建立一個(gè)目錄,如果目錄不存在,那么mkdir就成功執(zhí)行,如果目錄
99、存在,那么就出錯(cuò)了。若不希望mkdir出錯(cuò)而終止規(guī)則的運(yùn)行,可以在Makefile的命令行前加一個(gè)減號(hào)“-”(在Tab鍵之后),標(biāo)記為不管命令出不出錯(cuò)都認(rèn)為是成功的。例如:</p><p><b> clean:</b></p><p> -rm -f *.o</p><p> 若給make加上-i或是--ignore-errors參數(shù),
100、那么,Makefile中所有命令都會(huì)忽略錯(cuò)誤。而如果一個(gè)規(guī)則是以.IGNORE作為目標(biāo)的,那么這個(gè)規(guī)則中的所有命令將會(huì)忽略錯(cuò)誤。這些是不同級(jí)別的防止命令出錯(cuò)的方法,可以根據(jù)不同的愛(ài)好設(shè)置。</p><p> 若make的參數(shù)的是-k或是--keep-going,如果某規(guī)則中的命令出錯(cuò)了,那么就終目該規(guī)則的執(zhí)行,但繼續(xù)執(zhí)行其它規(guī)則。</p><p> 9.3.4 Makefile文件的
101、變量</p><p> 在Makefile中,變量可以使用在“目標(biāo)”,“依賴(lài)目標(biāo)”,“命令”或是Makefile的其它部分中。變量的命名字可以包含字符、數(shù)字,下劃線(可以是數(shù)字開(kāi)頭),但不應(yīng)該含有“:”、“#”、“=”或是空字符(空格、回車(chē)等)。變量是大小寫(xiě)敏感的,傳統(tǒng)的Makefile的變量名是全大寫(xiě)的命名方式,但推薦使用大小寫(xiě)搭配的變量名,例如:MakeFlags。</p><p>
102、 變量在聲明時(shí)需要給予初值,而在使用時(shí),需要給在變量名前加上“$”符號(hào),但最好用小括號(hào)“()”或是大括號(hào)“{}”把變量給包括起來(lái)。如果你要使用真實(shí)的“$”字符,那么需要用“$$”來(lái)表示。</p><p> 1.Makefile中的變量</p><p> 頂層Makefile定義并向環(huán)境中輸出了許多變量,并為各個(gè)子目錄下的Makefile傳遞一些信息。常用的變量有以下幾類(lèi):</p
103、><p><b> ?。?)版本信息</b></p><p> 版本信息有VERSION、PATCHLEVEL、SUBLEVEL、EXTRAVERSION和KERNELRE LEASE等變量,用來(lái)定義當(dāng)前內(nèi)核的版本。比如,VERSION = 2,PATCHLEVEL = 4,SUBLEVEL = 18,EXTRAVERSION = -rmk7,共同構(gòu)成內(nèi)核的發(fā)行版本KE
104、RNELRELEASE:2.4.18-rmk7。</p><p> (2)CPU體系結(jié)構(gòu)ARCH</p><p> 在頂層Makefile的開(kāi)頭,用ARCH定義目標(biāo)CPU的體系結(jié)構(gòu),比如,ARCH:=arm。許多子目錄的Makefile中,要根據(jù)ARCH的定義選擇編譯源文件的列表。</p><p> ?。?)路徑信息TOPDIR和SUBDIRS</p>
105、;<p> TOPDIR定義了Linux內(nèi)核源代碼所在的根目錄。例如,各個(gè)子目錄下的Makefile通過(guò)$(TOPDIR)/Rules.make就可以找到Rules.make的位置。</p><p> SUBDIRS定義了一個(gè)目錄列表,在編譯內(nèi)核或模塊時(shí),頂層Makefile根據(jù)SUBDIRS來(lái)決定進(jìn)入哪些子目錄。SUBDIRS的值取決于內(nèi)核的配置,在頂層Makefile中SUBDIRS賦值為k
106、ernel drivers mm fs net ipc lib;根據(jù)內(nèi)核的配置情況,在arch/*/Makefile中擴(kuò)充了SUBDIRS的值,可參考arch/arm/Makefile的例子。</p><p> (4)內(nèi)核組成信息HEAD,CORE_FILES,NETWORKS,DRIVERS,LIBS。 </p><p> Linux內(nèi)核文件vmlinux是由以下規(guī)則產(chǎn)生的:<
107、/p><p> vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs</p><p> $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o --start-group </p><p> $(CORE_FILES) \$(DRIVE
108、RS) $(NETWORKS) $(LIBS) --end-group -o vmlinux</p><p> 可以看出,vmlinux是由HEAD、main.o、version.o、CORE_FILES、DRIVERS、NETWORKS和LIBS組成的。這些變量(如HEAD)都是用來(lái)定義鏈接生成vmlinux所需的目標(biāo)文件和庫(kù)文件列表。其中,HEAD在arch/arm/Makefile中定義,用來(lái)確定最先鏈接
109、進(jìn)vmlinux的文件列表。比如,對(duì)于ARM系列HEAD的定義為:</p><p> HEAD := arch/arm/kernel/head-$(PROCESSOR).o \</p><p> arch/arm/kernel/init_task.o</p><p> 表明head-$(PROCESSOR).o和init_task.o需要最先被鏈接到vmlin
110、ux中。PROCESSOR為armv或armo,取決于目標(biāo)CPU。</p><p> ?。?)編譯信息CPP,CC,AS,LD,AR,CFLAGS,LINKFLAGS</p><p> 在Rules.make中定義的是編譯的通用規(guī)則,具體到特定的場(chǎng)合,需明確給出編譯環(huán)境,編譯環(huán)境是在以上的變量中定義的。針對(duì)交叉編譯的要求,定義了CROSS_COMPILE。比如:</p>&
111、lt;p> CROSS_COMPILE = arm-linux-</p><p> CC = $(CROSS_COMPILE)gcc</p><p> LD = $(CROSS_COMPILE)ld</p><p><b> ......</b></p><p>
112、 由于CROSS_COMPILE定義了交叉編譯器前綴arm-linux-,表明所有的交叉編譯工具都是以arm-linux-開(kāi)頭的,所以在各個(gè)交叉編譯器工具之前,都加入了$(CROSS_COMPILE),以組成一個(gè)完整的交叉編譯工具文件名,比如,arm-linux-gcc。</p><p> CFLAGS定義了傳遞給C編譯器的參數(shù)。</p><p> LINKFLAGS是鏈接生成vml
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫(kù)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 基于arm9的linux操作系統(tǒng)移植
- 基于arm9的linux操作系統(tǒng)的移植實(shí)習(xí)報(bào)告
- 基于arm9的linux操作系統(tǒng)移植設(shè)計(jì)說(shuō)明
- 基于arm9的linux操作系統(tǒng)移植設(shè)計(jì)說(shuō)明
- 【linux操作系統(tǒng)】第9章 動(dòng)態(tài)主機(jī)配置協(xié)議dhcp
- 基于arm9的嵌入式的linux操作系統(tǒng)的移植
- 基于ARM9和Linux操作系統(tǒng)的γ能譜采集系統(tǒng)研制.pdf
- 基于ARM9和Linux操作系統(tǒng)的嵌入式應(yīng)用開(kāi)發(fā).pdf
- 基于ARM的嵌入式Linux操作系統(tǒng)移植.pdf
- linux操作系統(tǒng)下c語(yǔ)言編程入門(mén)
- 基于ARM的嵌入式Linux操作系統(tǒng)的移植.pdf
- linux操作系統(tǒng)下的oracle數(shù)據(jù)庫(kù)編程
- 基于ARM的嵌入式Linux操作系統(tǒng)的移植研究.pdf
- linux操作系統(tǒng)下的多線程編程詳細(xì)解析
- linux操作系統(tǒng)
- 基于LINUX的安全操作系統(tǒng).pdf
- Linux操作系統(tǒng)在ARM硬件平臺(tái)上的移植.pdf
- 《操作系統(tǒng)》第2章
- 同濟(jì)《linux操作系統(tǒng)》課后習(xí)題4章
- 基于ARM的嵌入式Linux操作系統(tǒng)研究與移植.pdf
評(píng)論
0/150
提交評(píng)論