《嵌入式Linux開發(fā)實(shí)踐教程 第2版》 課件 項(xiàng)目4 使用嵌入式Linux常用開發(fā)工具_(dá)第1頁
《嵌入式Linux開發(fā)實(shí)踐教程 第2版》 課件 項(xiàng)目4 使用嵌入式Linux常用開發(fā)工具_(dá)第2頁
《嵌入式Linux開發(fā)實(shí)踐教程 第2版》 課件 項(xiàng)目4 使用嵌入式Linux常用開發(fā)工具_(dá)第3頁
《嵌入式Linux開發(fā)實(shí)踐教程 第2版》 課件 項(xiàng)目4 使用嵌入式Linux常用開發(fā)工具_(dá)第4頁
《嵌入式Linux開發(fā)實(shí)踐教程 第2版》 課件 項(xiàng)目4 使用嵌入式Linux常用開發(fā)工具_(dá)第5頁
已閱讀5頁,還剩172頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

編譯程序-GCC物聯(lián)網(wǎng)學(xué)院平震宇了解GCCGCC原名為GNUC語言編譯器(GNUCCompiler),GCC(GNUCompilerCollection,GNU編譯器套件)Fortran、Pascal、Objective-C、Java、Ada、Go

GCC版本1987年GCC發(fā)布首個(gè)公開發(fā)布版本。2012年為了慶祝25周年,GCC發(fā)布了GCC4.7.0版本,這是GCC一個(gè)全新的重要版本。

GCC8.2

released

[2018-07-26]GCC8.1

released

[2018-05-02]GCC7.3

released

[2018-01-25]GCC5.5

released

[2017-10-0]GCC7.2

released

[2017-08-14]GCC6.4

released

[2017-07-04]GNUBinutilsGNUBinutils,即GNUBinaryUtilities的簡寫,一般簡稱為Binutils。GNUBinutils,中文可以翻譯為GNU的二進(jìn)制工具集。GNUBinutils,是一組二進(jìn)制工具的集合。

GNUBinutils中包含的主要工具ld鏈接器

將多個(gè)目標(biāo)文件,鏈接成一個(gè)可執(zhí)行文件(或目標(biāo)庫文件)。as匯編器

將匯編源代碼,編譯為(目標(biāo))機(jī)器代碼

GNUBinutils中包含的其他次要工具addr2line

將地址轉(zhuǎn)換為(文件名和)行號的工具,以便于調(diào)試ar

用來操作(.a)文件,比如創(chuàng)建,修改,提取內(nèi)容等.c++filt

由于每一個(gè)重載的函數(shù)都使用與原函數(shù)相同的名稱,因此,支持函數(shù)重載的語言必須擁有一種機(jī)制,以區(qū)分同一個(gè)函數(shù)的許多重載版本。c++filt將每個(gè)輸入的名稱看成是改編后的名稱(mangledname),并設(shè)法確定用于生成該名稱的編譯器。dlltool

基于obj文件(基中函數(shù)標(biāo)記為__declspec(dllexport))或def文件生成exp和lib文件。前者(exp文件,其中包含了.edata段)是用于創(chuàng)建dll,后者(lib文件,包含.idata段)用于使用dll。

GNUBinutils中包含的其他次要工具gold

一個(gè)新的,速度更快的,只針對于ELF的鏈接器gprof

打印出程序運(yùn)行中各個(gè)函數(shù)消耗的時(shí)間,可以幫助程序員找出眾多函數(shù)中耗時(shí)最多的函數(shù)。nm

列舉目標(biāo)文件中的符號以及與符號有關(guān)的一些信息。Objcopy

把目標(biāo)文件的內(nèi)容從一種文件格式復(fù)制到另一種格式的目標(biāo)文件中。Objdump

顯示目標(biāo)文件信息,可以反編譯二進(jìn)制文件,也可以對對象文件進(jìn)行反匯編,并查看機(jī)器代碼。

GNUBinutils中包含的其他次要工具ranlib

生成索引以加快對歸檔文件的訪問,并將結(jié)果保存到這個(gè)歸檔文件中readelf

顯示符號、段信息、二進(jìn)制文件格式的信息等,這在分析編譯器如何工從源代碼創(chuàng)建二進(jìn)制文件時(shí)非常有用。size

可以列出目標(biāo)文件或者一個(gè)歸檔文件每一段的大小以及總體的大小strings

用于提取文件中的字符串內(nèi)容,使用該工具不會受到文件格式的限制。

strip

去除符號,比如用于debug的信息,在不影響程序功能的前提下,減少可執(zhí)行文件的大小,減少程序的占用空間

任務(wù)要求StepOne安裝GCC編譯器StepTwoGCC的編譯過程StepThreeGCC編譯實(shí)例StepOne安裝GCC通過GCC–v查看當(dāng)前的GCC版本gcc-v解壓gcc源碼包tarxzvfgcc-4.7.4.tar.gzStepOneinstallgmp./configure--prefix=/opt/gmp-4.3.2installmpfr./configure--prefix=/opt/mpfr-2.4.2--with-gmp=/opt/gmp-4.3.2installmpcStepOne配置../gcc-4.7.4/configure--prefix=/opt/gcc-4.7--with-gmp=/opt/gmp-4.3.2--with-mpfr=/opt/mpfr-2.4.2--with-mpc=/opt/mpc-1.0.1--enable-languages=c,c++,java編譯安裝makemakeinstallStep2程序的編譯過程

.C預(yù)處理.s.i編譯.o匯編hex鏈接預(yù)處理階段gcc–Ehello.c–ohello.iStep2程序的編譯過程

.C預(yù)處理.s.i編譯.o匯編.o鏈接編譯階段gcc–S

hello.i–ohello.sStep2程序的編譯過程

.C預(yù)處理.s.i編譯.o匯編.o鏈接匯編階段gcc–chello.s–ohello.oStep2程序的編譯過程

.C預(yù)處理.s.i編譯.o匯編.o鏈接鏈接階段gcchello.o–ohelloStep3

GCC編譯實(shí)例編譯簡單的C程序gcc-g-Wallhello.c–ohello選項(xiàng)""-g""表示在生成的目標(biāo)文件中帶調(diào)試信息選項(xiàng)-Wall開啟編譯器幾乎所有常用的警告warning:前面是懸崖,不要再往前走了。-w

:關(guān)閉所有警告-Wall:開啟所有錯(cuò)誤提示-Werror:把警告當(dāng)作錯(cuò)誤來處理警告選項(xiàng)-gformat:指定要生成的調(diào)試信息的格式以提供給其他平臺的其他調(diào)試器使用-g:以操作系統(tǒng)的本地格式(stabs,COFF,XCOFF,或DWARF)產(chǎn)生調(diào)試信息-pg:產(chǎn)生額外代碼用于輸出profile信息,供分析程序gprof使用調(diào)試選項(xiàng)

#include<head.h>#include“myhead.h”gcc-vhello.c-I/home/test-I

dir在頭文件的搜索路徑列表中添加dir目錄頭文件的處理鏈接庫的處理CompilerC源文件Olib目標(biāo)文件Linkerhex可執(zhí)行文件靜態(tài)庫動態(tài)庫libc.so#標(biāo)準(zhǔn)C庫,動態(tài)鏈接庫libpthread.a#線程庫,靜態(tài)鏈接庫一個(gè)特殊靜態(tài)鏈接庫方式,把庫完整名字加入gcc-ohellohello.olibmy.a-l參數(shù)用來鏈接庫標(biāo)準(zhǔn)表達(dá)式方式-lpthread表示鏈接libpthread.sogcchello.c-lpthread-ohello-L參數(shù)來指明從哪一個(gè)目錄加載庫在/home/test/lib/目錄下有鏈接時(shí)所需要的庫文件libmy.so

gcchello.c-L/home/test/lib-lmy–ohello新安裝一個(gè)庫之后如何讓系統(tǒng)能夠找到呢?1.編輯/etc/ld.so.conf文件,加入庫文件所在目錄的路徑2.運(yùn)行l(wèi)dconfig,該命令會重建/etc/ld.so.cache文件代碼優(yōu)化優(yōu)化級別1(-O1)優(yōu)化級別2(-O2)優(yōu)化級別3(-O3)StepThree編譯多個(gè)源文件gcc-Wallcalc.ccalc_fn.c-onewcalc

GCC編譯實(shí)例調(diào)試程序-GDB物聯(lián)網(wǎng)學(xué)院平震宇了解GDBGDB是一個(gè)強(qiáng)大的命令行調(diào)試工具。UNⅨ下的軟件全是命令行的,這給程序開發(fā)提代供了極大的便利,命令行軟件的優(yōu)勢在于,它們可以非常容易的集成在一起,使用幾個(gè)簡單的已有工具的命令,就可以做出一個(gè)非常強(qiáng)大的功能。

UNⅨ下的軟件比Windows下的軟件更能有機(jī)地結(jié)合,各自發(fā)揮各自的長處,組合成更為強(qiáng)勁的功能。Windows下的圖形軟件基本上是各自為營,互相不能調(diào)用,很不利于各種軟件的相互集成。“寸有所長,尺有所短”,圖形化工具還有時(shí)不如命令行的地方。

GDB功能啟動你的程序,可以按照你的自定義的要求隨心所欲的運(yùn)行程序??勺尡徽{(diào)試的程序在你所指定的調(diào)置的斷點(diǎn)處停住。(斷點(diǎn)可以是條件表達(dá)式)當(dāng)程序被停住時(shí),可以檢查此時(shí)你的程序中所發(fā)生的事。你可以改變你的程序,將一個(gè)BUG產(chǎn)生的影響修正從而測試其他BUG。

GNUDebuggerGNUDebugger最初是在1988年由理查德·馬修·斯托曼(RichardStallman,自由軟件的精神領(lǐng)袖)所撰寫,之后以GNU通用公共許可證的授權(quán)方式將軟件發(fā)布。

任務(wù)要求Step1熟悉使用GDB調(diào)試程序的流程Step2熟悉GDB常用命令Step3GDBServer遠(yuǎn)程調(diào)試GDB常用命令任務(wù)要求Step1查看源程序Step2暫停/恢復(fù)程序運(yùn)行Step3查看運(yùn)行時(shí)數(shù)據(jù)StepOne安裝GDB通過GDB–v查看當(dāng)前的GDB版本gdb-v解壓gcc源碼包tarxzvfgdb-7.4.tar.gzStepTwo如何單步執(zhí)行?如何打印變量的值?(printvar)

如何打印變量的地址?(print&var)

如何打印地址的數(shù)據(jù)值?(print*address)

如何查看當(dāng)前運(yùn)行的文件和行?(backtrace)

如何查看指定文件的代碼?(listfile:N)

如何立即執(zhí)行完當(dāng)前的函數(shù),但是并不是執(zhí)行完整個(gè)應(yīng)用程序?(finish)

如果程序是多文件的,怎樣定位到指定文件的指定行或者函數(shù)?(listfile:N)

如果循環(huán)次數(shù)很多,如何執(zhí)行完當(dāng)前的循環(huán)?(until)

GNUGCC開發(fā)教程gnugccturiolgnugcc簡介目前Linux下最常用的C語言編譯器是GCC(GNUCompilerCollection),它是GNU項(xiàng)目中符合ANSIC標(biāo)準(zhǔn)的編譯系統(tǒng).是Linux的基石,操作系統(tǒng)內(nèi)核和大部分程序都是gcc編譯的,是Linux下最重要開發(fā)工具之一gcc早期是c的編譯器,后來發(fā)展能支持c,c++和objectC,它可以通過不同的前端模塊來支持各種語言,如Java、Fortran、Pascal、Modula-3和Ada等。

gcc是一個(gè)交叉平臺的編譯器,目前支持幾乎所有主流CPU的處理器平臺.gcc支持的文件格式gcc支持源碼格式.c C源程序;.C,.cc,.cxx,.cpp C++源程序;.m Objective-C源程序;.i 預(yù)處理后的C文件;.ii 預(yù)處理后的C++文件;.s 匯編語言源程序;.S 匯編語言源程序;.h 預(yù)處理器文件;其它格式.o目標(biāo)文件(Objectfile).a歸檔庫文件(Archivefile)GCC組成gcc一般安裝在/usr/bingcc是一組編譯工具的總稱,包含如下工作C編譯器cc,cc1,cc1plus,gccC++編譯器c++,cc1plus,g++源碼預(yù)處理程序cpp,cpp0庫文件libgcc.a,libgcc_eh.a,libgcc_s.so,ibiberty.a,libstdc++,libsupc++.agcc的起步生成一個(gè)hello,world程序gcchello.c-ohello#把hello.c編譯成一個(gè)可執(zhí)行程序hellogcchello.c#不指定輸出名,生成一個(gè)a.outHello程序#include<stdio.h>#defineMY_NUMBER5intmain(void){printf("Hello%d,theWorld!\n",MY_NUMBER);return0;}編譯hello用GCC編譯程序可執(zhí)行程序的構(gòu)造任何一個(gè)可執(zhí)行程序從源代碼到可執(zhí)行的二進(jìn)制程序之中都要經(jīng)過固定的幾步預(yù)編譯(Pre-Processing)這一步完成對預(yù)編譯代碼的處理編譯(Compiling)將源代碼編譯成匯編代碼匯編(Assembling)將匯編代碼匯編成目標(biāo)文件鏈接(Linking)將目標(biāo)代碼和所需要庫的鏈成一個(gè)完整的應(yīng)用程序集成開發(fā)環(huán)境(IDE)自動協(xié)助開發(fā)完成這幾步,如VC++在Linux下,如果使用命令行開發(fā)工具(gcc,ld,ar)等,需要用戶手工調(diào)用這一些命令來完成這幾步驟.gcc在構(gòu)建程序的作用gcc在構(gòu)建應(yīng)用程序里,會調(diào)用不同的應(yīng)用程序完成每一步.因此在開發(fā)中,gcc處于一個(gè)核心地位.大部分開發(fā)只需要調(diào)用gcc即可gcc所做操作Gcc調(diào)用cpp進(jìn)行預(yù)處理Gcc調(diào)用cc1進(jìn)行編譯,會生成匯編代碼Gcc調(diào)用as對匯編代碼,生成擴(kuò)展名為.o的目標(biāo)文件Gcc調(diào)用ld來完成對所有目標(biāo)文件的鏈接.為什么要用gcc隨著Linux的GUI改進(jìn),也出現(xiàn)了越來越多的IDE開發(fā)環(huán)境.象VC++,自動完成各個(gè)開發(fā)流程但這一些IDE基本上是基于gcc編譯而且大部分項(xiàng)目,包括嵌入式開發(fā),都是提供gcc命令行開發(fā)模式.因此用gcc開發(fā)是Linux和嵌入式開發(fā)的必須使用的工具.也是基本功之一hello編譯過程分析以下將上述gcc編譯過程,分成幾個(gè)步驟單獨(dú)進(jìn)行,并生成每步運(yùn)行結(jié)果供觀察第一步是進(jìn)行預(yù)編譯,使用-E參數(shù)可以讓GCC在預(yù)處理結(jié)束后停止編譯過程:#

gcc-Ehello.c-ohello.i下一步是將hello.i編譯為目標(biāo)代碼,這可以通過使用-c參數(shù)來完成,。#

gcc-chello.i-ohello.o最后一步是將生成的目標(biāo)文件鏈接成可執(zhí)行文件#

gcchello.o-ohello注意:gcc編譯時(shí)是對輸入文件擴(kuò)展名是敏感的,即.c一定會當(dāng)做C代碼編譯,.cpp,.C…一定會當(dāng)成C++代碼編譯,這一點(diǎn)跟大部分Linux程序不一樣gcc的結(jié)果輸出是后綴名不相關(guān)的.只與輸出參數(shù)相關(guān).這跟一般Linux程序是一樣gcchello.c-ohello.o#雖然后綴名是.o,但實(shí)際是一個(gè)應(yīng)用程序gcc各個(gè)編譯步驟多文件gcc的處理在采用模塊化的設(shè)計(jì)思想進(jìn)行軟件開發(fā)時(shí),通常整個(gè)程序是由多個(gè)源文件組成的,相應(yīng)地也就形成了多個(gè)編譯單元,使用GCC能夠很好地管理這些編譯單元。假設(shè)有一個(gè)由foo1.c和foo2.c兩個(gè)源文件組成的程序,為了對它們進(jìn)行編譯,并最終生成可執(zhí)行程序foo,可以使用下面這條命令:gccfoo1.cfoo2.c-ofoo在編譯一個(gè)包含許多源文件的工程時(shí),若只用一條GCC命令來完成編譯是非常浪費(fèi)時(shí)間的。假設(shè)項(xiàng)目中有100個(gè)源文件需要編譯,并且每個(gè)源文件中都包含10000行代碼,如果像上面那樣僅用一條GCC命令來完成編譯工作,那么GCC需要將每個(gè)源文件都重新編譯一遍,然后再全部連接起來。很顯然,這樣浪費(fèi)的時(shí)間相當(dāng)多,尤其是當(dāng)用戶只是修改了其中某一個(gè)文件的時(shí)候,完全沒有必要將每個(gè)文件都重新編譯一遍,因?yàn)楹芏嘁呀?jīng)生成的目標(biāo)文件是不會改變的。要解決這個(gè)問題,關(guān)鍵是要靈活運(yùn)用GCC,同時(shí)還要借助像Make這樣的工具。用gcc構(gòu)造程序(1)在只有一個(gè)源代碼文件構(gòu)造出來的可執(zhí)行程序.只需要用到如下形式gcchello.c-ohello表示將hello.c一次做完四步,構(gòu)造出可執(zhí)行程序hello,gcchello.c將hello.c構(gòu)造一個(gè)可執(zhí)行程序,有缺省名a.out,但不建議這樣做.gcc-chello.c-ohello這一步驟是初學(xué)者常犯錯(cuò)誤.以為等于在一次性構(gòu)造應(yīng)用程序hello但實(shí)際上這只是在編譯c并生成一個(gè)目標(biāo)文件hello,即便是沒有.o的后綴.這個(gè)用file命令可以很容易查看,這個(gè)hello是無法執(zhí)行.用gcc構(gòu)造程序(2)使用多個(gè)源碼的項(xiàng)目,如項(xiàng)目中包含2個(gè)以上的源代碼,一般要先將源代碼編譯成目標(biāo)代碼.最后一次鏈接成可執(zhí)行程序以鏈表測試程序?yàn)槔?整個(gè)項(xiàng)目由兩個(gè)c代碼(test_link.c和link_list.c)和一個(gè)頭文件(link_list.h)組成.頭文件是包含在源代碼里,由預(yù)處理程序處理,不需要編譯首先各自己編譯成目標(biāo)文件gcc-clink_list.c#將link_list.c編譯成link_list.ogcc-ctest_link.c#將test_link.c編譯成test_link.o然后將各個(gè)目標(biāo)文件鏈接成一個(gè)文件gcclink_list.otest_link.o-otest_link#生成可執(zhí)行文件test_link也可以直接把兩個(gè)文件在一句里編譯,但強(qiáng)烈建議不要這樣做gcclink_list.ctest_link.c-otest_link編譯test_link實(shí)例用gcc構(gòu)造程序(3)gcc的對絕大部分參數(shù)順序一般沒有要求,但為可讀性強(qiáng),最好要按一定順序執(zhí)行g(shù)cclink_list.o-otest_link.otest_link等效于gcclink_list.otest_link.o-otest_link,但前者可讀性差很多.但多個(gè)-l(鏈接)參數(shù)的順序是有要求的對于有頭文件在多個(gè)目錄時(shí),需要在編譯時(shí)多次使用用-I參數(shù)加入頭文件所在目錄.例如test_link.c需要用到/usr/include,當(dāng)前目錄下,/home/hxy目錄下的頭文件.則如下編譯gcc-I.-I/usr/include-I/home/hxy-ctest_link.cgcc構(gòu)造復(fù)雜程序一個(gè)大型項(xiàng)目,一個(gè)可執(zhí)行程序可能擁有多個(gè)位于不同目錄的頭文件,多個(gè)源碼文件,還可能鏈接一些靜態(tài)庫或動態(tài)庫,這一些都需要用到gcc的一些擴(kuò)展選項(xiàng).gcc的參數(shù)參見下一節(jié)可能調(diào)用gcc很多次,如果完全手工編寫,將是一個(gè)浩大的工程需要寫一個(gè)類似Shell腳本的Makefile來調(diào)用gcc構(gòu)造GCC選項(xiàng)gcc完整使用格式gcc使用格式

gcc[option|filename]...g++[option|filename]...

其中option為gcc使用時(shí)的選項(xiàng)(后面會再詳),

而filename為欲以gcc處理的文件

總體選項(xiàng)(OverallOption)-c-S-E-ofile-pipe-v-xlanguagegcc選項(xiàng)(1)-xlanguage明確指出后面輸入文件的語言為language(而不是從文件名后綴得到的默認(rèn)選擇).這個(gè)選項(xiàng)應(yīng)用于后面所有的輸入文件,直到遇著下一個(gè)`-x'選項(xiàng).language的可選值有`c',`objective-c',`c-header',`c++',`cpp-output',`assembler',和`assembler-with-cpp'.gcc-xc++hello.c強(qiáng)制用c++來編譯-xnone關(guān)閉任何對語種的明確說明,因此依據(jù)文件名后綴處理后面的文件(就象是從未使用過`-x'選項(xiàng)).gcc選項(xiàng)(2)-c編譯或匯編源文件,但是不作連接.編譯器輸出對應(yīng)于源文件的目標(biāo)文件.缺省情況下,GCC通過用`.o'替換源文件名后綴`.c',`.i',`.s',等等,產(chǎn)生目標(biāo)文件名.可以使用-o選項(xiàng)選擇其他名字.GCC忽略-c選項(xiàng)后面任何無法識別的輸入文件(他們不需要編譯或匯編).gcc–chello.cgcc選項(xiàng)(3)-S編譯后即停止,不進(jìn)行匯編.對于每個(gè)輸入的非匯編語言文件,輸出文件是匯編語言文件.缺省情況下,GCC通過用`.o'替換源文件名后綴`.c',`.i',等等,產(chǎn)生目標(biāo)文件名.可以使用-o選項(xiàng)選擇其他名字.GCC忽略任何不需要編譯的輸入文件.相當(dāng)于編譯源碼,只生匯編代碼

gcc–Shello.c–ohello.sgcc選項(xiàng)(4)-E預(yù)處理后即停止,不進(jìn)行編譯.預(yù)處理后的代碼送往標(biāo)準(zhǔn)輸出.GCC忽略任何不需要預(yù)處理的輸入文件gcc–Ehello.c–ohello.i-v(在標(biāo)準(zhǔn)錯(cuò)誤)顯示執(zhí)行編譯階段的命令.同時(shí)顯示編譯器驅(qū)動程序,預(yù)處理器,編譯器的版本號.gcc-vgcc選項(xiàng)(5)-ofile指定輸出文件為file.該選項(xiàng)不在乎GCC產(chǎn)生什么輸出,無論是可執(zhí)行文件,目標(biāo)文件,匯編文件還是預(yù)處理后的C代碼.由編譯階段決定,輸入的格式gcc-Ehello.c-ohello.igcc-chello.i-ohello.ogcchello.c–ohello只能輸出一個(gè)文件gcc選項(xiàng)(6)-pipe在編譯過程的不同階段間使用管道而非臨時(shí)文件進(jìn)行通信.在將源代碼變成可執(zhí)行文件的過程中,需要經(jīng)過許多中間步驟,包含預(yù)處理、編譯、匯編和連接。這些過程實(shí)際上是由不同的程序負(fù)責(zé)完成的。大多數(shù)情況下GCC可以為Linux程序員完成所有的后臺工作,自動調(diào)用相應(yīng)程序進(jìn)行處理。是GCC在處理每一個(gè)源文件時(shí),最終都需要生成好幾個(gè)臨時(shí)文件才能完成相應(yīng)的工作,從而無形中導(dǎo)致處理速度變慢。例如,GCC在處理一個(gè)源文件時(shí),可能需要一個(gè)臨時(shí)文件來保存預(yù)處理的輸出、一個(gè)臨時(shí)文件來保存編譯器的輸出、一個(gè)臨時(shí)文件來保存匯編器的輸出,而讀寫這些臨時(shí)文件顯然需要耗費(fèi)一定的時(shí)間。當(dāng)軟件項(xiàng)目變得非常龐大的時(shí)候,花費(fèi)在這上面的代價(jià)可能會變得很沉重。解決的辦法是,使用Linux提供的一種更加高效的通信方式—管道。它可以用來同時(shí)連接兩個(gè)程序,其中一個(gè)程序的輸出將被直接作為另一個(gè)程序的輸入,這樣就可以避免使用臨時(shí)文件,但編譯時(shí)卻需要消耗更多的內(nèi)存。gcc-pipefoo.c-ofoo

關(guān)于宏(macro)的選項(xiàng)-Dmacro定義宏macro,宏的內(nèi)容定義為字符串`1'.gcctest_m.c–D__DEBUG–otest_m-Dmacro=defn定義宏macro的內(nèi)容為defn.命令行上所有的`-D'選項(xiàng)在`-U'選項(xiàng)之前處理.gcctest_m.c–D__DBG_NAME=hello–otest_m-Umacro取消宏macro.`-U'選項(xiàng)在所有的`-D'選項(xiàng)之后處理,但是優(yōu)先于任何`-include'gcc警告提示功能

GCC包含完整的出錯(cuò)檢查和警告提示功能,它們可以幫助Linux程序員寫出更加專業(yè)和優(yōu)美的代碼。編譯警告代碼-pedantic打開完全服從ANSIC標(biāo)準(zhǔn)所需的全部警告診斷,如里出現(xiàn)非標(biāo)準(zhǔn)擴(kuò)展,則拒絕編譯,所以叫書呆子pedant.-ansi支持符合ANSI標(biāo)準(zhǔn)的C程序.這樣就會關(guān)閉GNUC中某些不兼容ANSIC的特性,例如asm,inline和typeof關(guān)鍵字,以及諸如unix和vax這些表明當(dāng)前系統(tǒng)類型的預(yù)定義宏.同時(shí)開啟不受歡迎和極少使用的ANSItrigraph特性,以及禁止`$'成為標(biāo)識符的一部分.與pedantic區(qū)別在于,只是警告,如果需要停止編譯,仍然需要打開-pedanticgcc警告提示功能(2)-Wall打開所有編譯警告gcc-Wallillcode.c-oillcode-Werror視警告為錯(cuò)誤;出現(xiàn)任何警告即放棄編譯.gcc-Wall-Werrorillcode.c-oillcode-w禁止輸出警告信息調(diào)試分析選項(xiàng)-g以操作系統(tǒng)的本地格式(stabs,COFF,XCOFF,或DWARF).產(chǎn)生調(diào)試信息.GDB能夠使用這些調(diào)試信息,是進(jìn)行g(shù)db調(diào)試必備條件和大多數(shù)C編譯器不同,GNUCC允許結(jié)合使用`-g‘和`-O’選項(xiàng),但一般不建議一起使用gcchello.c-g-ohello-pg產(chǎn)生額外代碼,用于輸出profile信息,供分析程序gprof使用.所有調(diào)試選項(xiàng)會使用最終輸出文件尺寸急劇增加,在最后發(fā)布,需要使用strip命令把調(diào)試信息去掉,striphellogcc使用庫使用第三方庫在Linux下開發(fā)軟件時(shí),完全不使用第三方函數(shù)庫的情況是比較少見的,通常來講都需要借助一個(gè)或多個(gè)函數(shù)庫的支持才能夠完成相應(yīng)的功能。從程序員的角度看,函數(shù)庫實(shí)際上就是一些頭文件(.h)和庫文件(.so或者.a)的集合。雖然Linux下的大多數(shù)函數(shù)都默認(rèn)將頭文件放到/usr/include/目錄下,而庫文件則放到/usr/lib/目錄下,但并不是所有的情況都是這樣。正因如此,GCC在編譯時(shí)必須有自己的辦法來查找所需要的頭文件和庫文件。GCC采用搜索目錄的辦法來查找所需要的文件,-I選項(xiàng)可以向GCC的頭文件搜索路徑中添加新的目錄。例如,如果在/home/hxy/upgrade/include/目錄下有編譯時(shí)所需要的頭文件,為了讓GCC能夠順利地找到它們,就可以使用-I選項(xiàng):gccfoo.c-I/home/xiaowp/include-ofoo在一個(gè)gcc命令中可以用多個(gè)-I兩大類庫形式C/C++可以使用兩種庫.一種是靜態(tài)庫,另外一種是動態(tài)庫.靜態(tài)庫在鏈接時(shí)會把庫目標(biāo)代碼與最終的可執(zhí)行程序一起鏈接到一個(gè)文件,這樣相對尺寸較大.但處理簡單.而動態(tài)庫是可執(zhí)行程序在運(yùn)行,動態(tài)加載到進(jìn)程內(nèi)存中去.動態(tài)庫與可執(zhí)行程序是分離的兩部分文件.兩者在作用是完全等效,主要是使用方法不同.由開發(fā)者根據(jù)項(xiàng)目情況自行評估使用哪種形式.Windows下的靜態(tài)庫是以lib為后綴名的文件,而動態(tài)庫是以DLL為后綴名的文件.Linux下的動態(tài)鏈接庫是so為后綴,和靜態(tài)鏈接庫以.a為后綴名Linux的庫的命名Linux庫的命名有一個(gè)特殊的要求,即要是lib打頭,以.so或a結(jié)尾libc.so#標(biāo)準(zhǔn)C庫,動態(tài)鏈接庫libpthread.a#線程庫,的靜態(tài)鏈接庫版本.在一般使用時(shí),為防止不同版本庫互相覆蓋,一般還在系統(tǒng)庫名后加入版本號.libm.so.6#math庫ver6.0版本Libc-2.3.2.so#標(biāo)準(zhǔn)Cver2.3.2動態(tài)庫但為方便gcc使用,通常都對這一些帶版本名的庫作一個(gè)符號鏈接,鏈接名則是標(biāo)準(zhǔn)形式,如libc.so.Linux一般把系統(tǒng)庫放在/lib下.這是大部分庫命名的習(xí)慣,也可以不遵守,如果強(qiáng)行做一個(gè)叫mystd.a的庫,但使用起來很不方便,如不能使用-l參數(shù)等,所以建議不要這樣做.gcc鏈接庫gcc是在鏈接時(shí),把庫加入可以程序中.一個(gè)特殊靜態(tài)鏈接庫方式.把庫完整名字加入gcc-ohellohello.olibmy.a鏈接hello.o,和庫libmy.a到某一個(gè)程序hello中g(shù)cc-ohellohello.olibmy.so鏈接hello.o,和庫libmy.so到某一個(gè)程序hello中,注意這里沒有直接把libmy.so代碼加入hello中這一方法主要用于鏈接不標(biāo)準(zhǔn)庫名稱,或混和鏈接(即一部分庫用于靜態(tài)版本,一部分庫用動態(tài)版本).但不是正規(guī)用法,強(qiáng)烈建議不要使用這一方法gcc-l參數(shù)的使用gcc-l參數(shù)用來鏈接庫標(biāo)準(zhǔn)表達(dá)式方式.-l接的庫名,是去掉lib和后綴名(.so,.a)剩下的部分,gccfoo.c-lpthread-ofoo構(gòu)造foo,鏈接庫pthread.-lpthread表示鏈接libpthread.so由于去掉后綴名,gcc-l如何知道鏈接是動態(tài)庫還是靜態(tài)庫?,gcc有如下規(guī)則:如果gcc所能找到庫目錄同時(shí)有兩種版本,優(yōu)先鏈接動態(tài)鏈接庫版本如果gcc所能找到庫目錄只有靜態(tài)版本,則采用靜態(tài)版本如果加上-static參數(shù),gcc則強(qiáng)制鏈接靜態(tài)版本gccfoo.c-static-lpthread-ofoo-lpthread表示鏈接libpthread.a一個(gè)使用線程庫的例子gcc-L參數(shù)的使用gcc所編譯的目標(biāo)文件和庫通常不是在同一個(gè)目錄下.因此必須強(qiáng)制指明gcc要從哪一個(gè)目錄加載庫gcc在鏈接時(shí)采用-L參數(shù)來指明從哪一個(gè)目錄加載庫例如,如果在/home/hxy/lib/目錄下有鏈接時(shí)所需要的庫文件libfoo.sogccfoo.c-L/home/hxy/lib-lfoo-ofoo一個(gè)gcc語句可以包含多個(gè)-L參數(shù)在編譯時(shí)目標(biāo)文件時(shí)使用-L無效標(biāo)準(zhǔn)庫,gcc能自行找到,無需使用-L參數(shù)在一些應(yīng)用中,鏈接多個(gè)庫是有順序的,大部分無所謂如在系統(tǒng)中l(wèi)iba.a使用libpthread.a中的函數(shù),而可執(zhí)行程序同時(shí)使用兩個(gè)庫,則使用者liba.a的鏈接語句放在被使用者libpthread.a的前面,gccfoo.c-L/home/hxy/lib–la-lpthread-ofoo只是為了保險(xiǎn).在BerkeleyDB中就出現(xiàn)這種情況,pthread在前,則所有線程庫的函數(shù)找不到gcc-I參數(shù)的使用庫的頭文件通常也跟源文件不在同一個(gè)目錄之下,為了讓gcc找到頭文件,可以-I<頭文件目錄>來加入頭目錄.gcc是在編譯時(shí)使用-I,在鏈接時(shí)無效.這跟-L參數(shù)剛好相反一個(gè)gcc語句中可以使用多個(gè)-Igcc創(chuàng)建庫關(guān)于庫的演示代碼在隨后的演示中,將采用如下演示代碼.Strlen.c,Strnlen.c分別實(shí)現(xiàn)了兩個(gè)自定義示字符串長度函數(shù)這兩個(gè)函數(shù)的聲明在String.h中main.c分別用靜態(tài)鏈接,隱式動態(tài)鏈接來測試使用了Strlen.c,Strnlen.c的函數(shù),并使用.main_dl.c用顯示動態(tài)鏈接來調(diào)用庫代碼在隨后的例子里把Strlen.c,Strnlen.c分別編譯成靜態(tài)庫.libstr.a,隱式動態(tài)庫libstr.so,顯示動態(tài)庫libstrdl.so,庫名中最好不用出現(xiàn)大寫字母,gcc是按小寫字母來查找的關(guān)于靜態(tài)鏈接庫在LINUX下,靜態(tài)函數(shù)庫是以.a作后綴的,類似于Windows的lib在鏈接后,靜態(tài)庫的函數(shù)都會鏈接到最終的可執(zhí)行程序里.這樣可執(zhí)行程序的尺寸比動態(tài)鏈接要大.靜態(tài)鏈接的好處是不需要外部文件的支持,獨(dú)立運(yùn)行.在嵌入式環(huán)境下,如果尺寸影響不大,最好用靜態(tài)編譯.創(chuàng)建靜態(tài)鏈接庫gcc不能直接創(chuàng)建靜態(tài)庫.必須要用歸檔命令ar來創(chuàng)建ar用于建立、修改、提取檔案文件(archive)。archive是一個(gè)包含多個(gè)被包含文件的單一文件(也稱之為庫文件),其結(jié)構(gòu)保證了可以從中檢索并得到原始的被包含文件(稱之為archive中的member)。ar可以把任何文件歸在一起,但通常是用來把gcc編譯的目標(biāo)文件(.o),合在一個(gè)靜態(tài)庫中靜態(tài)庫創(chuàng)建$gcc-Wall-cfile1.cfile2.cfile3.c#一次性編譯三個(gè).o$arrvlibNAME.afile1.ofile2.ofile3.o#把三個(gè)o合在一起ar參數(shù){dmpqrtx}中的操作選項(xiàng)在命令中只能并且必須使用其中一個(gè),它們的含義如下:d:從庫中刪除模塊。按模塊原來的文件名指定要?jiǎng)h除的模塊。如果使用了任選項(xiàng)v則列出被刪除的每個(gè)模塊。m:該操作是在一個(gè)庫中移動成員。當(dāng)庫中如果有若干模塊有相同的符號定義(如函數(shù)定義),則成員的位置順序很重要。如果沒有指定任選項(xiàng),任何指定的成員將移到庫的最后。也可以使用'a','b',或'I'任選項(xiàng)移動到指定的位置。p:顯示庫中指定的成員到標(biāo)準(zhǔn)輸出。如果指定任選項(xiàng)v,則在輸出成員的內(nèi)容前,將顯示成員的名字。如果沒有指定成員的名字,所有庫中的文件將顯示出來。q:快速追加。增加新模塊到庫的結(jié)尾處。并不檢查是否需要替換。'a','b',或'I'任選項(xiàng)對此操作沒有影響,模塊總是追加的庫的結(jié)尾處。如果使用了任選項(xiàng)v則列出每個(gè)模塊。這時(shí),庫的符號表沒有更新,可以用'ars'或ranlib來更新庫的符號表索引。ar參數(shù)(2)r:在庫中插入模塊(替換)。當(dāng)插入的模塊名已經(jīng)在庫中存在,則替換同名的模塊。如果若干模塊中有一個(gè)模塊在庫中不存在,ar顯示一個(gè)錯(cuò)誤消息,并不替換其他同名模塊。默認(rèn)的情況下,新的成員增加在庫的結(jié)尾處,可以使用其他任選項(xiàng)來改變增加的位置。

t:顯示庫的模塊表清單。一般只顯示模塊名。x:從庫中提取一個(gè)成員。如果不指定要提取的模塊,則提取庫中所有的模塊。但實(shí)際最多參數(shù)只有arrv....Replace+verbosearrcv....Replace+Create+verbose創(chuàng)建一個(gè)靜態(tài)庫的腳本gcc-cStrlen.cgcc-cStrnlen.c#把兩個(gè)目標(biāo)文件裝入靜態(tài)庫libstr.a中arrv

libstr.aStrlen.oStrnlen.ogcc-cmain.c-I.#鏈接main_a時(shí),一并鏈接libstr.a#gccmain.olibmy.a-omain_a#非標(biāo)準(zhǔn)用法,用全名gccmain.o-L.-lstr-omain_a#標(biāo)準(zhǔn)用法動態(tài)鏈接庫的創(chuàng)建動態(tài)鏈接庫的創(chuàng)建分為兩步:1.編譯目標(biāo)文件,必須帶上-fpic標(biāo)志,使輸出的對象模塊是按照可重定位地址方式生成的gcc-cStrlen.c-fpic

gcc-cStrnlen.c-fpic

2.將加入動態(tài)庫的目標(biāo)文件合并在一起,必須帶上-shared,明確表示是動態(tài)鏈接庫gcc-sharedStrlen.oStrnlen.o-olibstr.so兩步可以合并成一步,但一般不建議這樣做gcc-fpic

-sharedStrlen.cStrnlen.c-olibstr.soso是SharedObject的縮寫動態(tài)鏈接庫的創(chuàng)建#gcc-fpic-sharedStrlen.cStrnlen.c-olibstr.sogcc-c-fpicStrlen.cgcc-c-fpicStrnlen.c#生成動態(tài)鏈接庫gcc-sharedStrlen.oStrnlen.o-olibstr.so#編譯測試程序gcc-cmain.c-I.#鏈接主程序和動態(tài)庫#gccmain.olibstr.so-omain_so#非標(biāo)準(zhǔn)鏈接方式gccmain.o-L.-lstr-omain_so運(yùn)行中使用動態(tài)鏈接庫一個(gè)使用動態(tài)鏈接庫的程序運(yùn)行時(shí),要做一下設(shè)置.否則應(yīng)用程序會報(bào)找不到動態(tài)庫的錯(cuò)誤隱式調(diào)用和顯式調(diào)用兩種調(diào)用方法.隱式調(diào)用是不采用特殊系統(tǒng)調(diào)用,只是在gcc鏈接采用-l,-L鏈接.這樣代碼影響不大顯式調(diào)用是在運(yùn)行時(shí),使用動態(tài)庫的文件名來加載,具有靈活的特點(diǎn),缺點(diǎn)就是必須使用特定的,不可移植的系統(tǒng)調(diào)用來編寫.過程比較復(fù)雜一個(gè)程序運(yùn)行后,可以用命令ldd來檢查它使用了哪一些動態(tài)庫ldd./hello隱式調(diào)用動態(tài)方法必須要能讓程序運(yùn)行能找動態(tài)鏈接庫,Linux有如下幾種方法.把庫所在路徑加入/etc/ld.so.conf,程序加載是會首先到這里路徑查找設(shè)置環(huán)境變量LD_LIBRARY_PATH,把庫所在路徑加入這個(gè)變量中,這是最常用的方法演示代碼將采用這一方法運(yùn)行,寫一個(gè)腳本run_so.sh將exportLD_LIBRARY_PATH和執(zhí)行語句寫在一行命令中,并用;隔開exportLD_LIBRARY_PATH=$PWD;./mani_so#!/bin/shexportLD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH./main_soldd./main_so#用ldd查看用了哪些動態(tài)庫隱式動態(tài)庫的執(zhí)行結(jié)果動態(tài)庫的顯示調(diào)用顯示調(diào)用,Linux提供4個(gè)庫函數(shù)(dlopen,dlerror,dlsym和dlclose),一個(gè)include文件(dlfcn.h)以支持動態(tài)鏈接裝入器dlopen

將共享目標(biāo)文件打開并且映射到內(nèi)存中,并且返回句柄dlsym返回一個(gè)指向被請求入口點(diǎn)的指針dlerror

返回NULL或者一個(gè)指向描述最近錯(cuò)誤的ASCII字符串的指針dlclose關(guān)閉句柄并且取消共享目標(biāo)文件的映射這四個(gè)函數(shù)被包含在libdl.a/libdl.so之中,所以使用動態(tài)顯示調(diào)用,必須要鏈接-ldl這一機(jī)制是后來加入,模仿Windows下的LoadLibrary/FreeLibrary機(jī)制不同調(diào)用方式對動態(tài)庫本身沒有任何影響,需要調(diào)整是調(diào)用庫函數(shù)的應(yīng)用程序,要做較大調(diào)整.dlopen()的說明void*dlopen(constchar*filename,intflag);將共享目標(biāo)文件打開并且映射到內(nèi)存中,并且返回句柄聲明在頭文件dlfcn.h之中第一個(gè)參數(shù):指定共享庫的名稱,將會在下面位置查找指定的共享庫。dlopencall中的絕對文件路徑在LD_LIBRARY_PATH環(huán)境變量中指定的目錄中在/etc/ld.so.cache中指定的庫列表之中先在/usr/lib之中,然后在/lib之中第二個(gè)參數(shù):指定如何打開共享庫。RTLD_NOW:將共享庫中的所有函數(shù)加載到內(nèi)存RTLD_LAZY:會推后共享庫中的函數(shù)的加載操作,直到調(diào)用dlsym()時(shí)方加載某函數(shù)

其它dl函數(shù)聲明constchar*dlerror(void);如果上一步的dl函數(shù)出錯(cuò),則返回非空字符串,指明錯(cuò)誤原因

void*dlsym(void*handle,char*symbol);用庫函數(shù)名字symbol在dlopen打開的handle查找一個(gè)函數(shù)指針,如果找到,則放入返回值中,應(yīng)用程序可以直接用函數(shù)指針來操作.intdlclose(void*handle);關(guān)閉dlopen打開的句柄關(guān)于使用顯示動態(tài)庫的步驟必須包含頭文件#include<dlfcn.h>聲明使用的到庫函數(shù)的函數(shù)指針用dlopen打開共享庫用dlsym取得對應(yīng)庫函數(shù)的函數(shù)指針如果成功,使用直接調(diào)用這個(gè)指針.相當(dāng)于使用庫函數(shù)用完共享庫后,用dlclose釋放共享庫使用顯示調(diào)用實(shí)例(1)#include<stdio.h>#include<dlfcn.h>/*

加入頭文件支持*/intmain(intargc,char*argv[]){//definefunctionpointorint(*pStrlenFun)(char*pStr);//聲明對應(yīng)的函數(shù)的函數(shù)指針

int(*pStrnlenFun)(char*pStr,intulMaxLen);charstr[]={"helloworld"};unsignedlongulLength=0;void*pdlHandle;char*pszErr;

pdlHandle=dlopen(“./libstrdl.so”,RTLD_LAZY);//加載動態(tài)鏈接庫/libstrdl.soif(!pdlHandle){printf("Failedloadlibrary\n");}使用顯示調(diào)用實(shí)例(2)/*接上一段代碼*//*判斷dlopen是否打開出錯(cuò),如是,打印錯(cuò)誤后退出*/pszErr=dlerror();

if(pszErr!=NULL){printf("%s\n",pszErr);return0;}//從庫中查找?guī)旌瘮?shù)Strlen的函數(shù)指針

pStrlenFun=dlsym(pdlHandle,"Strlen");//獲取函數(shù)的地址

pszErr=dlerror();if(pszErr!=NULL){printf("%s\n",pszErr);return0;}使用顯示調(diào)用實(shí)例(3)/*接上一段代碼*//*從庫中查找?guī)旌瘮?shù)Strnlen的函數(shù)指針*/pStrnlenFun=dlsym(pdlHandle,"StrNlen");pszErr=dlerror();if(pszErr!=NULL){printf("%s\n",pszErr);return0;}printf("Thestringis:%s\n",str);ulLength=pStrlenFun(str);//直接使用函數(shù)指針,相當(dāng)于調(diào)用庫函數(shù)

printf("Thestringlengthis:%d(useStrlen)\n",ulLength);ulLength=pStrnlenFun(str,10);printf("Thestringlengthis:%d(useStrNlen)\n",ulLength);

dlclose(pdlHandle);//關(guān)閉共享庫

return0;}創(chuàng)建顯示調(diào)用動態(tài)庫rm-flibstrdl.sorm-f*.omain#gcc-fpic-sharedStrlen.cStrnlen.c-olibstr.sogcc-c-fpicStrlen.cgcc-c-fpicStrnlen.c#創(chuàng)建動態(tài)鏈接庫gcc-sharedStrlen.oStrnlen.o-olibstrdl.sogcc-cmain_dl.c-I.#必須同時(shí)加入strdl和dl庫支持gccmain_dl.o-L.-lstrdl

-ldl-omain_dl運(yùn)行顯示調(diào)用實(shí)例代碼優(yōu)化Gcc代碼優(yōu)化(1)代碼優(yōu)化指的是編譯器通過分析源代碼,找出其中尚未達(dá)到最優(yōu)的部分,然后對其重新進(jìn)行組合,目的是改善程序的執(zhí)行性能。GCC提供的代碼優(yōu)化功能非常強(qiáng)大,它通過編譯選項(xiàng)-On來控制優(yōu)化代碼的生成,其中n是一個(gè)代表優(yōu)化級別的整數(shù)。對于不同版本的GCC來講,n的取值范圍及其對應(yīng)的優(yōu)化效果可能并不完全相同,比較典型的范圍是從0變化到2或3。編譯時(shí)使用選項(xiàng)-O可以告訴GCC同時(shí)減小代碼的長度和執(zhí)行時(shí)間,其效果等價(jià)于-O1。在這一級別上能夠進(jìn)行的優(yōu)化類型雖然取決于目標(biāo)處理器,但一般都會包括線程跳轉(zhuǎn)(ThreadJump)和延遲退棧(DeferredStackPops)兩種優(yōu)化。選項(xiàng)-O2告訴GCC除了完成所有-O1級別的優(yōu)化之外,同時(shí)還要進(jìn)行一些額外的調(diào)整工作,如處理器指令調(diào)度等。選項(xiàng)-O3則除了完成所有-O2級別的優(yōu)化之外,還包括循環(huán)展開和其它一些與處理器特性相關(guān)的優(yōu)化工作。通常來說,數(shù)字越大優(yōu)化的等級越高,同時(shí)也就意味著程序的運(yùn)行速度越快。許多Linux程序員都喜歡使用-O2選項(xiàng),因?yàn)樗趦?yōu)化長度、編譯時(shí)間和代碼大小之間,取得了一個(gè)比較理想的平衡點(diǎn)。

Gcc代碼優(yōu)化(2)不帶優(yōu)化

gcc-Walloptimize.c-ooptimize做了優(yōu)化gcc-Wall-Ooptimize.c-ooptimizetime借助Linux提供的time命令,可以大致統(tǒng)計(jì)出該程序在運(yùn)行時(shí)所需要的時(shí)間,比較兩次時(shí)間#time./optimize代碼優(yōu)化實(shí)例一個(gè)做了大量浮點(diǎn)數(shù)除法的程序.#include<stdio.h>intmain(void){doublecounter;doubleresult;doubletemp;for(counter=0;counter<2000.0*2000.0*2000.0/20.0+2020;counter+=(5-1)/4){temp=counter/1979;result=counter;}

printf("Resultis%lf\n",result);

return0;}代碼優(yōu)化的結(jié)果比較Gcc代碼優(yōu)化(3)-O-O1-O2多優(yōu)化一些.除了涉及空間和速度交換的優(yōu)化選項(xiàng),執(zhí)行幾乎所有的優(yōu)化工作.例如不進(jìn)行循環(huán)展開(loopunrolling)和函數(shù)內(nèi)嵌(inlining).和-O選項(xiàng)比較,這個(gè)選項(xiàng)既增加了編譯時(shí)間,也提高了生成代碼的運(yùn)行效果.-O3優(yōu)化的更多.除了打開-O2所做的一切,它還打開了-finline-functions選項(xiàng).-O0不優(yōu)化.如果指定了多個(gè)-O選項(xiàng),不管帶不帶數(shù)字,最后一個(gè)選項(xiàng)才是生效的選項(xiàng).Gcc代碼優(yōu)化(4)避免優(yōu)化代碼場合:程序開發(fā)的時(shí)候優(yōu)化等級越高,消耗在編譯上的時(shí)間就越長,因此在開發(fā)的時(shí)候最好不要使用優(yōu)化選項(xiàng),只有到軟件發(fā)行或開發(fā)結(jié)束的時(shí)候,才考慮對最終生成的代碼進(jìn)行優(yōu)化。資源受限的時(shí)候一些優(yōu)化選項(xiàng)會增加可執(zhí)行代碼的體積,如果程序在運(yùn)行時(shí)能夠申請到的內(nèi)存資源非常緊張(如一些實(shí)時(shí)嵌入式設(shè)備),那就不要對代碼進(jìn)行優(yōu)化,因?yàn)橛蛇@帶來的負(fù)面影響可能會產(chǎn)生非常嚴(yán)重的后果。跟蹤調(diào)試的時(shí)候在對代碼進(jìn)行優(yōu)化的時(shí)候,某些代碼可能會被刪除或改寫,或者為了取得更佳的性能而進(jìn)行重組,從而使跟蹤和調(diào)試變得異常困難。

交叉開發(fā)GCC在其它平臺的gccgcc是一個(gè)強(qiáng)大,開源的編譯器,因此被人移植多種CPU,多個(gè)操作系統(tǒng)下.如移植Windows下的mingW,Cygwingcc.exe幾乎在每種CPU,如ARM,MIPS,PowerPC等都有相應(yīng)版本,而且在很多時(shí)候是唯一的編譯器,如龍芯.gcc還有一個(gè)強(qiáng)大的功能,即交叉編譯.即在A的操作系統(tǒng)下,編譯B操作系統(tǒng)下的程序.如嵌入式操作下x86的redhat9.0下去編譯ARM下的Arm-Linux的程序用于交叉開發(fā)的gcc在arm下開發(fā)的gcc通常叫arm-linux-gcc將arm-linux-gcc解壓后安裝將arm-linux-gcc其路徑加入系統(tǒng)PATH中將所有需要gcc的地方改成arm-linux-gcc重新編譯,即可完成簡單的移植在嵌入式中,通常需要-static靜態(tài)編譯.編譯后的可執(zhí)行程序可用U盤或FTP上傳到ARM開發(fā)板上課內(nèi)練習(xí),將上一次課堂練習(xí)結(jié)果移植到開發(fā)板上注意,首先修改開發(fā)HOST的對應(yīng)用戶的.bash_profile,假設(shè)是用戶hxy,則在/home/hxy/.bash_profile的PATH改成如下定義PATH=/usr/local/arm/2.95.3/bin:$PATH這樣才可以直接用arm-linux-gcc常見錯(cuò)誤或警告dl_list.h:42:7:warning:nonewlineatendoffile這個(gè)通常是由于源碼里最后一行不是UNIX文本字符要求的空行,造成,這不影響最終編譯結(jié)果,如果想去掉,直接在源碼中加入一個(gè)空行即可test_link.o(.text+0x308):Infunction`test2'::undefinedreferenceto`dl_save_to_file‘表示在最終鏈接時(shí),沒有找到dl_save_to_file這個(gè)函數(shù)的目標(biāo)代碼,原因有多種,如沒有把這個(gè)源碼包含進(jìn)來,系統(tǒng)函數(shù)的筆誤.找不到對應(yīng)鏈接庫main.c:8:47:String.h:Nosuchfileordirectory某個(gè)頭文件找不到,很大可能性是沒有用-I參數(shù)把String.h所有在目錄加入進(jìn)來../main:errorwhileloadingsharedlibraries:libstr.so:cannotopensharedobjectfile:Nosuchfileordirectory應(yīng)用程序找不到自己鏈接的動態(tài)庫libstr.so,需要把libstr.so加入到環(huán)境變量LD_LIBRARY_PATH中程序運(yùn)行常見錯(cuò)誤1在busybox下運(yùn)行程序,/usr/bin/boa:/usr/bin/boa:1:Syntaxerror:"("unexpected最大可以是這個(gè)程序是用x86gcc編譯的程序,然后在Arm-Linux運(yùn)行時(shí),被不匹配的strip課堂作業(yè)請開發(fā)一個(gè)程序,使用結(jié)構(gòu)定義structstudent{intno;/*學(xué)號*/charname[64];/*名稱*/floatheight;/*身高*/};要求創(chuàng)建3個(gè)學(xué)生定義,并給三個(gè)學(xué)生的三個(gè)成員都賦上值,用一個(gè)printf把一個(gè)學(xué)生的三個(gè)值打印出來,依次把所有學(xué)生信息顯示要求用vi編輯,并用gcc在Linux下編譯,測試通過課堂練習(xí)開發(fā)一個(gè)庫函數(shù),要求能對字符串的進(jìn)行轉(zhuǎn)大寫轉(zhuǎn)換.要求把庫函數(shù),編譯成靜態(tài)和動態(tài)鏈接庫各一個(gè),取名libtu.a,libtu.so編寫一個(gè)測試程序,要求能測試libtu測試庫函數(shù)把上述過程寫成一個(gè)Shell腳本,一次性執(zhí)行謝謝,請?zhí)釂栐诏偪竦臅r(shí)代把握未來課程目標(biāo)學(xué)習(xí)使用字符界面gdb來調(diào)試Linux程序gdb高級應(yīng)用圖形gdb界面-dddGdb簡介GDB是一個(gè)強(qiáng)大的命令行調(diào)試工具。大家知道命令行的強(qiáng)大就是在于,其可以形成執(zhí)行序列,形成腳本。UNIX下的軟件全是命令行的,這給程序開發(fā)提代供了極大的便利,命令行軟件的優(yōu)勢在于,它們可以非常容易的集成在一起,使用幾個(gè)簡單的已有工具的命令,就可以做出一個(gè)非常強(qiáng)大的功能。GDB相對圖形界面的VC++等,命令比較難記,這是命令行界面一大缺點(diǎn)Linux也有基于GDB圖形界面的調(diào)試器,如gdbinsight,DDD.GDB功能啟動你的程序,可以按照你的自定義的要求隨心所欲的運(yùn)行程序??勺尡徽{(diào)試的程序在你所指定的調(diào)置的斷點(diǎn)處停住。(斷點(diǎn)可以是條件表達(dá)式)當(dāng)程序被停住時(shí),可以檢查此時(shí)你的程序中所發(fā)生的事。動態(tài)的改變你程序的執(zhí)行環(huán)境GDB與VC++調(diào)試命令的對比GDB幫助象大多部復(fù)雜Linux程序一樣,GDB是通過內(nèi)部命令來完成調(diào)試工作gdb的命令很多,gdb把之分成許多個(gè)種類.help命令只是例出gdb的命令種類,如果要看種類中的命令,可以使用help<class>命令,如:helpbreakpoints,查看設(shè)置斷點(diǎn)的所有命令。也可以直接help<command>來查看命令的幫助。gdb中,輸入命令時(shí),可以不用打全命令,只用打命令的前幾個(gè)字符就可以了,當(dāng)然,命令的前幾個(gè)字符應(yīng)該要標(biāo)志著一個(gè)唯一的命令在gdb下,你可以敲擊兩次TAB鍵來補(bǔ)齊命令的全稱,如果有重復(fù)的,那么gdb會把其例出來。GDB測試樣例編譯測試程序,一定要加上-g參數(shù),為可執(zhí)行文件加上調(diào)試信息gcc-gtst.c-otst啟動GDB的方式gdb<program>

program也就是你的執(zhí)行文件,一般在當(dāng)前目錄下gdb<program>core用gdb同時(shí)調(diào)試一個(gè)運(yùn)行程序和core文件,core是程序非法執(zhí)行后coredump后產(chǎn)生的文件gdb<program><PID>如果你的程序是一個(gè)服務(wù)程序,那么你可以指定這個(gè)服務(wù)程序運(yùn)行時(shí)的進(jìn)程ID。gdb會自動attach上去,并調(diào)試他。program應(yīng)該在PATH環(huán)境變量中搜索得到。操作GDB常見命令GDB的啟動選項(xiàng)GDB啟動時(shí),可以加上一些GDB的啟動選項(xiàng)--symbols<file>-s<file>

從指定文件中讀取符號表。-sefile

從指定文件中讀取符號表信息,并把他用在可執(zhí)行文件中。--core<file>

-c<file>

調(diào)試時(shí)coredump的core文件。--directory<directory>

-d<directory>

加入一個(gè)源文件的搜索路徑。默認(rèn)搜索路徑是環(huán)境變量中PATH所定義的路徑。fileprogram詳細(xì)的開關(guān)可以用gdb--helpgdb的基本調(diào)試調(diào)試器的基本功能任何一種調(diào)試器,都必須具備如下基本功能建立可執(zhí)行程序與源碼的聯(lián)系(查看源碼)設(shè)置斷點(diǎn)執(zhí)行行基本的調(diào)試命令程序暫停后,查看各種信息查看源程序

GDB可以打印出所調(diào)試程序的源代碼,當(dāng)然,在程序編譯時(shí)一定要加上-g的參數(shù),把源程序信息編譯到執(zhí)行文件中。當(dāng)程序停下來以后,GDB會報(bào)告程序停在了那個(gè)文件的第幾行上。你可以用list命令來打印程序的源代碼。可以縮寫為llist<linenum>

顯示程序第linenum行的周圍的源程序。list<function>

顯示函數(shù)名為function的函數(shù)的源程序。list

顯示當(dāng)前行后面的源程序。list-

顯示當(dāng)前行前面的源程序。一般是打印當(dāng)前行的上5行和下5行,如果顯示函數(shù)是是上2行下8行,默認(rèn)是10行,當(dāng)然,你也可以定制顯示的范圍,使用下面命令可以設(shè)置一次顯示源程序的行數(shù)。setlistsize<count>

設(shè)置一次顯示源代碼的行數(shù)。setlistsize20設(shè)置顯示一次20行showlistsize

查看當(dāng)前l(fā)istsize的設(shè)置。

查看源程序(2)list命令還有下面的用法list<first>,<last>

顯示從first行到last行之間的源代碼。list,<last>

顯示從當(dāng)前行到last行之間的源代碼。list+

往后顯示源代碼。

一般來說在list后面可以跟以下這們的參數(shù):<linenum>行號。

<+offset>當(dāng)前行號的正偏移量。

<-offset>當(dāng)前行號的負(fù)偏移量。

<filename:linenum>哪個(gè)文件的哪一行。lgdb_tst.c:20<function>函數(shù)名。

<filename:function>

哪個(gè)文件中的哪個(gè)函數(shù)lgdb_tst.c:main<*address>程序運(yùn)行時(shí)的語句在內(nèi)存中的地址。l*0x0804835a調(diào)試程序執(zhí)行g(shù)dbgdbgdb_tst設(shè)置斷點(diǎn)通常至少要設(shè)一個(gè)斷點(diǎn),要不然gdb會直接運(yùn)行到程序結(jié)束.bmain#在主函數(shù)入口設(shè)斷點(diǎn)設(shè)置命令行參數(shù)如果程序需要用到命令行參數(shù),直接在gdb命令是無法輸入setargs

可指定運(yùn)行時(shí)參數(shù)。如:gdb>setargs1020304050開始調(diào)試進(jìn)入gdb提示符后,gdb并沒有進(jìn)調(diào)試狀態(tài)需要用r,即run進(jìn)行調(diào)試在GDB中運(yùn)行程序

當(dāng)以gdb<program>方式啟動gdb后,gdb會在PATH路徑和當(dāng)前目錄中搜索<program>的源文件。如要確認(rèn)gdb是否讀到源文件,可使用l或list命令,看看gdb是否能列出源代碼。在gdb中,運(yùn)行程序使用r或是run命令。程序的運(yùn)行,你有可能需要設(shè)置下面四方面的事。程序運(yùn)行參數(shù)。setargs可指定運(yùn)行時(shí)參數(shù)。如:setargs1020304050運(yùn)行環(huán)境path<dir>可設(shè)定程序的運(yùn)行路徑。showpaths查看程序的運(yùn)行路徑。setenvironmentvarname[=value]設(shè)置環(huán)境變量。如:setenvUSER=hchenshowenvironment[varname]查看環(huán)境變量。工作目錄。cd<dir>

相當(dāng)于shell的cd命令。pwd顯示當(dāng)前的所在目錄。程序的輸入輸出infoterminal顯示你程序用到的終端的模式。使用重定向控制程序輸出。如:run>outfiletty命令可以指寫輸入輸出的終端設(shè)備。如:tty/dev/ttyb常用調(diào)試命令

當(dāng)程序被停住了,你可以用continue命令恢復(fù)程序的運(yùn)行直到程序結(jié)束,或下一個(gè)斷點(diǎn)到來。也可以使用step或next命令單步跟蹤程序。continue[ignore-count]

c[ignore-count]

fg[ignore-count]

恢復(fù)程序運(yùn)行,直到程序結(jié)束,或是下一個(gè)斷點(diǎn)到來。ignore-count表示忽略其后的斷點(diǎn)次數(shù)。continue,c,fg三個(gè)命令都是一樣的意思。step<count>

單步跟蹤,如果有函數(shù)調(diào)用,他會進(jìn)入該函數(shù)。進(jìn)入函數(shù)的前提是,此函數(shù)被編譯有debug信息。很像VC等工具中的stepin。后面可以加count也可以不加,不加表示一條條地執(zhí)行,加表示執(zhí)行后面的count條指令,然后再停住。next<count>

同樣單步跟蹤,如果有函數(shù)調(diào)用,他不會進(jìn)入該函數(shù)。很像VC等工具中的stepsetstep-mode

setstep-modeon

打開step-mode模式,于是,在進(jìn)行單步跟蹤時(shí),程序不會因?yàn)闆]有debug信息而不停住。這個(gè)參數(shù)有很利于查看機(jī)器碼。常用調(diào)試命令(2)setstep-modoff

關(guān)閉step-mode模式。finish

運(yùn)行程序,直到當(dāng)前函數(shù)完成返回。并打印函

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論