LINUX下編譯與調試 LINUX下編譯與調試... 1 1. gcc/g++編譯器... 1 2. makefile使用... 2 2.1. 基本過程處理... 2 2.2. 特殊處理與偽目標... 3 2.3. 變數、函數與規則... 5 3. 程式調試... 8 3.1. gdb常用命令... 8 3.2. gdb 應用舉例... 9 3.3. assert斷言宏... 12 3.4. 錯誤處理函數和進程退出函數... 13 3.5. 系統日誌... 15
1. gcc/g++編譯器
對於.c格式的C檔案,可以採用gcc或g++編譯 對於 .cc、.cpp格式的C++檔案,應該採用g++進行編譯 常用的選項兩種 -c 表示編譯源檔案 -o 表示輸出目標檔案 -g 在目標檔案中產生調試資訊,用於gdb調試 -D <宏定義> 編譯時間將宏定義傳入進去 -Wall 選項可以開啟所有類型的文法警告,以便協助我們確定代碼是正確的,並且儘可能實現可移植性。 例如有兩個檔案main.cpp,func.cpp 其中 main.cpp 內容為: #include <stdio.h> #include <stdlib.h> int MyFunc(); int main() { #ifdef _DEBUG printf("Debug MyFunc is:%d/n",MyFunc()); #else printf("NDEBUG MyFunc is:%d/n",MyFunc()); #endif } func.cpp 內容為: int MyFunc() { return 123; } 編譯和串連的方式有如下一些 : 1、 g++ -c func.cpp 將編譯func.cpp,並且產生同名的但副檔名為.o的二進位目標檔案 func.o 同樣道理 g++ -c main.cpp 將編譯main.cpp,並且產生同名的但副檔名為.o的二進位目標檔案 main.o 2、g++ -c func.cpp -o func.o 功能同(1)一樣,但是顯式地指定了輸出檔案名為main.o 同樣道理 g++ -c main.cpp –o main.o 編譯main.cpp,並輸出目標檔案main.o 3、 (1)、(2)的基礎上 l g++ main.o func.o l g++ -o a.out main.o func.o l g++ -o a.out *.o 都將串連目標檔案main.o和func.o最後形成可執行檔a.out 對於第一種,如果沒有顯式指定可執行檔名,g++預設為a.out 4、 也可以將編譯和連結的過程合為一塊處理: g++ *.cpp g++ func.cpp main.cpp g++ -o a.out func.cpp main.cpp 都將先編譯指定的源檔案,如果成功的話,再連結成可執行檔a.out 採用第4種方式,在其中第某個源檔案中必須有main函數,否則連結通不過。 5、 如果希望在編譯時間傳入宏定義,可使用-D參數,例如 g++ -D _DEBUG *.cpp
2. makefile使用
2.1. 基本過程處理
makefile的工作過程為:先將需要編譯串連的c/c++源檔案組織到檔案makefile中, 接著運行make程式,make程式讀取當前檔案夾下面的makefile檔案資訊,並根據makefile 裡面的組織資訊,調用相應的gcc/g++/shell等程式,完成對源檔案的批量編譯和串連。 要寫makefile檔案,首頁必須清楚makefile中的目標檔案和依賴檔案的概念。 通常情況下,目標檔案和依賴檔案都是指實際的檔案。 例如,有makefile檔案,內容如下:
| main.exe:main.o func.o g++ -o main.exe main.o func.o main.o:main.cpp g++ -c main.cpp func.o:func.cpp g++ -c func.cpp |
檔案第一行中的檔案main.exe稱為目標檔案,冒號後面以空格分隔的兩個檔案 稱為main.exe的依賴檔案。意思是檔案main.exe的產生依賴於檔案main.o和 func.o 同樣道理: 第3行的main.o為目標檔案,main.cpp為main.o的依賴檔案 第5行的func.o為目標檔案,func.cpp為func.o的依賴檔案. 檔案第2行(以tab開頭)表示要產生第1行的目標檔案需要執行的命令。 對於該makefile檔案,程式make處理過程如下: 1、 make 程式首先讀到第1行的目標檔案main.exe和它的兩個依賴檔案main.o和func.o;然後比較檔案main.exe和main.o/func.o的產生時間,如果main.exe比main.o/func.o舊的話,則執行第2條命令,以產生目標檔案main.exe,否則make立即返回,表示目標檔案不必依賴檔案舊,不需要更新。 2、 在執行第2行的命令前,它首先會查看makefile中的其他定義,看有沒有以第1行main.o和func.o為目標檔案的依賴檔案,如果有的話,繼續按照(1)、(2)的方式匹配下去。 3、 根據(2)的匹配過程,make程式發現第3行有目標檔案main.o依賴於main.cpp,則比較目main.o與它的依賴檔案main.cpp的檔案新舊,如果main.o比main.cpp舊,則執行第4行的命令以產生目標檔案main.o.在執行第4條命令時,main.cpp在檔案makefile不再有依賴檔案第定義,make程式不再繼續往下匹配,而是執行第4條命令,產生目標檔案main.o 4、 目標檔案func.o按照上面的同樣方式判斷產生. 執行(3)、(4)產生完main.o和func.o以後,則第2行的命令可以順利地執行了,最終產生了第1行的目標檔案main.exe。
2.2. 特殊處理與偽目標
先看一些makefile的特殊情況: makefile檔案內容為
執行make時 如果檔案a存在,echo ‘a’將不會被調用,可以理解為檔案a沒有依賴檔案,則認為檔案a總是最新的,不需要執行; 如果檔案a不存在,echo ‘a’將會被調用。
如果檔案b不存在,不管a是否存在,make時都將會報錯 如果檔案b存在,檔案a不存在,則echo ‘a’會被調用 如果檔案a、b都存在,則按照正常的方式先比較檔案新舊,決定是否調用echo
makefile裡面有2組定義:
make時,如果檔案a不存在,echo ‘a’將會被調用,但是echo’b’ 不會被調用,說明make執行的進入點只有一個,就是第一個目標檔案的定義,其它的調用都是由於有與第一條定義直接或間接依賴關係而被調用的; make b時,表示指定進入點為b,則echo ‘b’被調用,echo ‘a’不被調用,也說明進入點只有一個
make b時,調用順序為echo ‘a’然後是echo ‘b’,說明依賴體的匹配過程是全檔案匹配,並不是順序往下的。 偽目標:再回到(2)中的第一種情況,如果希望指定進入點為b,並且不管檔案b是否都存在,都調用echo ‘b’,則可以定義b為偽目標:
| a: echo 'a' .PHONY: b b: echo ‘b’ |
.PHONY是makefile檔案的關鍵字,表示它後面列表中的目標均為偽目標,這樣,不論檔案b是否存在,執行make b時,echo ‘b’都將被調用。 偽目標通常用在清理檔案、強制重新編譯等情況下,例如:
| main.exe:main.o func.o g++ -o main.exe main.o func.o main.o:main.cpp g++ -c main.cpp func.o:func.cpp g++ -c func.cpp .PHONY:rebuild clean rebuild:clean main.exe clean: rm *.o *.exe |
執行make clean將清除掉檔案夾中的二進位可執行檔 執行make rebuild則先執行清除,再重新編譯串連。
2.3. 變數、函數與規則
隨著軟體項目的變大、變複雜,源檔案也越來越多,如果採用前面的方式寫makefile檔案,將會使makefile也變得複雜而難於維護。通過make支援的變數定義、使用、內建函數和規則,可以寫出通用性較強的makefile檔案,使得同一個makefile檔案能夠適應不能的項目。 變數:為一文本串定義一個名字,名字即為變數的名稱,文本串即為變數的值。 定義變數的一般方法: 變數名=變數值 遞規變數展開(幾個變數共用一個值) 或者 變數名:=變數值 簡單變數展開(類似於C++的賦值) 使用變數的一般方法: $(變數名)=??? 賦值 ???=$(變數名) 引用 例:
| OBJS= main.o func.o main.exe:$(OBJS) g++ -o main.exe main.o func.o main.o:main.cpp g++ -c main.cpp func.o:func.cpp g++ -c func.cpp |
make內部事先定義好了一些變數,他們分為兩種類型,自動變數和預定義變數: 自動變數: 指在使用的時候,自動用特定的值替換。 常用的有:
| 變數 |
說明 |
| $@ |
當前規則的目標檔案 |
| $< |
當前規則的第一個依賴檔案 |
| $^ |
當前規則的所有依賴檔案,以逗號分隔 |
| $? |
規則中日期新於目標檔案的所有相關檔案清單,逗號分隔 |
| $(@D) |
目標檔案的目錄名部分 |
| $(@F) |
目標檔案的檔案名稱部分 |
預定義變數:也是make內部事先定義好的變數,但是它的值是固定的,並且有些的值是為空白的。 常用的有:
| 變數 |
說明 |
| $(CC) |
C編譯器,預設值:cc |
| $(CPP) |
C預先處理程式,預設值:cpp |
| $(RM) |