1. 程式人生 > >跟著iMX28x開發套件學linux-03

跟著iMX28x開發套件學linux-03

二、linux應用程式設計之一編譯基礎知識

VS這類整合IDE的編譯過程已經被簡化成ctrl+f5,底層一點的編譯過程已經被淡化。而linux應用開發或者驅動開發又要對編譯過程有一定的瞭解,所以學習編譯基礎知識還是很有必要的。

gcc編譯流程

gcc編譯流程分為四步,分別是:預處理,編譯,彙編,連結。

1) gcc -E test.c -o test.i : 預處理,各種預處理命令進行處理,包括標頭檔案包含、巨集定義的擴充套件、條件編譯的選擇等。

2) gcc -S test.i -o test.s : 編譯,將預處理得到的原始碼檔案,進行“翻譯轉換”,產生出機器語言的目標程式,得到機器語言的彙編檔案。

3) gcc -c test.s -o test.o : 彙編,將彙編程式碼翻譯成了機器碼,但是還不可以執行。

4) gcc    test.o -o test   : 連結,處理可重定位檔案,把各種符號引用和符號定義轉換成為可執行檔案中的合適資訊,通常是虛擬地址。

常用的gcc選項

1) -g : 新增除錯內容,用於GDB除錯,是在彙編過程就要加上了。

2) -O  優化編譯,可選優化等級,01,02,03O3優化等級最高。

3) -w/-W : 關閉/開啟編譯警告。

4) -v : 顯示編譯詳細資訊。

5) -I  編譯時包含標頭檔案的目錄,後面要跟上標頭檔案目錄的路徑。

6) -static : 編譯採用靜態連結,即將庫檔案包含到程式中,程式會變得非常大,gcc預設是動態編譯。

庫檔案是一些資料型別,函式和變數等的集合。庫的詳細內容是不可見的,只可以在標頭檔案中看到函式原型。例如標準輸入輸出庫,只要包含了stdio.h就可以自動地連結到標準輸入輸出庫。庫分為靜態庫(.a)以及動態庫(.so)。

靜態庫(.a)是.o檔案的集合,在編譯的連結階段使用,編譯器將程式用到的函式從靜態庫裡面提取出來,整合到程式中去。因為程式中用到的庫函式都被整合到了程式中,所以編譯出來的程式會比較大。建立使用者靜態庫的步驟如下:

1) 編寫庫的.c檔案 : 按照要求,可以編寫多個.c檔案,注意.c檔案內要include一個.h檔案。

2) 編寫庫的.h檔案 : 在.h檔案中宣告所有庫函式的函式原型。

3) 將所有的.c檔案進行編譯不連結(-c) : 正確進行編譯後產生若干個.o檔案。

4) ar -r 庫名.a *.o(所有的.o檔案,空格間隔) : 將.o檔案連結成庫。

5) 使用庫 編寫.c檔案時include庫的.h檔案,編譯的時候引用生成的庫.a以及標頭檔案.h。

在編譯時引用庫的方式一般有以下幾種方式:

1) gcc test.c test.a -o test : 直接在編譯列表中加入庫檔案(.c檔案後),可以包含路徑。

2) gcc test.c -L ./libtest -lFOO: 用-L引入庫檔案所在的目錄,再用-lFOO引用名字為libFOO的庫(所以庫的檔名就要寫成lib**了),這樣可以避免每個庫都要寫帶路徑的全名。

動態庫以.so(share object)結尾,在Windows中以.dll結尾。動態庫建立與使用都與靜態庫類似,但是用動態庫編譯的檔案在執行時,要在系統中能找到動態庫檔案才能正確執行。建立動態庫的步驟如下:

1) 前三步與靜態庫一樣,都是生成.o檔案和.h檔案。

2) gcc -shared -fPIC -o 庫名.so *.o(所有的.o檔案,空格間隔)  : 將.o檔案連結成庫。

引用動態庫的方法跟靜態庫差不多,但是生成的可執行檔案在執行之前要把動態庫放到系統庫檔案目錄下,比如/usr/lib 。

其實靜態或者動態庫平時接觸也很多,就是沒有留意到。例如在keil中新增一個.c檔案,再新增一個.h檔案,編譯完成之後就可以在其他檔案中引用這個.c檔案中的函數了,這裡用到的應該是使用者建立庫,只是建立及引用過程被keil封裝成了一個編譯按鈕。

Makefile

每次編譯都要寫一大串gcc指令,太繁瑣了,用Makefile可以簡化這個過程。Makefile可以看成是一個編譯指令碼,執行這個Makefile指令碼就可以完成想要完成的編譯動作。有些版本的Ubuntu沒有安裝make工具,要先安裝make工具。

Makefile的格式比較簡單,暫時用到的初級通用Makefile程式碼如下:

   

 

.PHONY:clean 表示偽目標,意思是clean不是目標,但是可以make clean呼叫這個“目標”下的指令,主要用來刪除編譯產生的檔案。

EXE, OBJ, SRC, CC, CFLAGS, TEMP 這些都是變數,用$(變數名)就可以引用這些變數。其中EXE代表生成可執行程式名,OBJ表示生成過程檔名(.o檔案), SRC表示.c程式名, CC表示編譯器型別,可以用gcc編譯生成可執行檔案在Ubuntu上執行,也可以用arm-linux-交叉編譯器生成可執行檔案在開發板上面執行。CFLAGS表示編譯選項,可以加上類似-g-v-O這類的選項。TEMP表示臨時檔案,如果程式中用了creat()之類的函式建立了新的檔案,可以把生成的檔名新增到這裡,執行make clean可以刪除掉。

注意一點:“目標:依賴檔案”的下一行是指令行,這裡有一個縮排,這個縮排必須要用一個tab實現,不管文字編輯器的tab是幾個空格都行,但是不能用幾個空格代替。

GDB

GDB是一個程式碼除錯工具,功能很強大,可是沒有圖形介面用起來不是很習慣,所以安裝了GDB的圖形介面DDD。用命令 ddd 可執行檔案可以開啟ddd介面,前提是在彙編的時候一定要加上-g選項,不然開啟的ddd介面沒有顯示程式碼,也除錯不了。ddd中可以輸入GDB的指令,常用的指令如下:

1) break 行號 : 在第幾行設定斷點。

2) clear 行號 : 取消在第幾行設定的斷點。

3) watch 變數名 : 觀察一個變數的值。

其他指令暫時還沒用過,在ddd的視覺化介面上的按鈕可以快速實現這些命令。

個人選擇

個人比較喜歡視覺化程式設計,所以在Ubuntu上我是用notepad+ddd來完成程式設計的,vi只是用來修改一些系統配置檔案或者寫一些簡單一點的測試程式。本來還想折騰eclipse,裝了cdt外掛後發現編譯出錯,而且偶爾開啟報錯,一直都搞不定。想了想,Makefile也要自己寫,不如用notepad算了,省事一點。暫時先用著吧,後面有別的需求再考慮換。