目錄
一、工具準備
gcc是GNU的C編譯器(GNU C Compiler)
g++是GNU的C++編譯器(GNU C++ Compiler)
gdb是Linux下常用的調試工具,主要功能如下
- 啓動你的程序,可以按照你的自定義的要求隨心所欲的運行程序。
- 可讓被調試的程序在你所指定的調置的斷點處停住(斷點可以是條件表達式)。
- 當程序被停住時,可以檢查此時你的程序中所發生的事。
- 你可以改變你的程序,將一個BUG產生的影響修正從而測試其他BUG。
Makefile文件:Makefile是程序編譯的規則,makefile記錄着整個工程的編譯規則(如源文件的編譯順序、依賴關係等),通過make工具進行編譯。make根據makefile定義的規則將源代碼編譯成二進行文件。在跨平臺(特別是類Unix系統中)的程序中,一般都會通過makefile來進行編譯。
二、程序的編譯及調試
1、程序的編譯及常用命令
$ g++ main.cpp #編譯程序,在當前目錄自動生成一個a.out
的可執行文件
$ ./a.out # 執行可執行文件,即運行程序
$ g++ main.cpp -o test # 指定自己想要生成的可執行程序的別名 (test)
$ g++ -c main.cpp # 將源代碼編譯成目標文件(main.o),不進行鏈接
$ g++ main.o -o test1($ g++ -o test1 main.o) #g++接編譯後的(*.o)文件進行鏈接,生成可執行程序 (test1)
$ ldd test1 #該命令可以看到可執行程序 (test1)所鏈接的庫
$ g++ -o test1 main.cpp -L /usr/Lib -l /usr/include #將依賴的函數庫和庫路徑加入
-
-L 指定連接的動態庫或者靜態庫路徑 ;
-
-I(大寫i) 指定頭文件路徑 ,即include文件(也就是包含的*.h頭文件)所在的目錄;
-
-l(小寫L) 指定需要鏈接的庫的名稱
$ gcc -g main.c -o test #使用gdp調試C/C++程序, 在編譯時,必須要把調試信息加到可執行文件中
$ g++ -g main.cpp -o test
注: 編譯過程包括預處理、編譯,鏈接 ;linux系統上的編譯生成.o文件,windows系統上的編譯生成.obj文件 ;linux系統上生成沒有後綴的可執行文件,windows系統中生成.exe文件 ; linux系統下的靜態函數庫的後綴是.a,動態庫是.so ; windows系統下的靜態函數庫的後綴是.lib,動態庫是.dll。
2、gdb調試
GDB是一個由GNU開源組織發佈的、UNIX/LINUX操作系統下的、基於命令行的、功能強大的程序調試工具。可以用來調試C,C++程序。
gdp功能及其常用命令
命令形式 | 功能解釋 |
---|---|
gdb -g main.cpp -o test | 編譯代碼時的命令,要把調試信息加到可執行文件中 |
gdb | 進入gdb調試命令 |
help | 顯示幫助信息,例:help quit,顯示quit命令的信息 |
q/quit | 退出GDB調試 |
file test | 加載被調試的可執行程序文件test;或者直接使用gdb ./test進行debug調試命令 |
l/list | 列出文件的內容 |
b/break <line number> | 在某一行設置普通斷點,運行到該行即停止,例:b 7 |
b/break <line number> if condition | 在某一行設置條件斷點,運行到該行滿足條件即停止,例:b 7 if index=2 |
b/break <function name> | 在某一個函數調用處設置斷點,運行到函數調用出即停止,例:b getSum |
r/run | 運行調試的程序(如果程序中沒有設置斷點,則程序會一直運行到結束或者出現異常結束,如果設置斷點,則會在斷點處停止) |
d/delete <break number> | 刪除斷點編號對應的斷點,例:d 1 |
clear | 清空所有的斷點信息 |
start | 開始調試 |
c/continue | 繼續執行程序直到下一個斷點或者程序結束 |
n/next | 逐行調試 |
s/step | 遇到函數時進到函數內部調試 |
p/print <value> | 顯示變量的值,即查看變量數據,例:p index |
三、Makefile文件基礎
1、Makefile介紹
Makefile文件關係到了整個工程的編譯規則,它定義了一系列的規則來指定哪些文件需要先編譯,哪些文件需要後編譯,哪些文件需要重新編譯,甚至於進行更復雜的功能操作,因爲 makefile就像一個Shell腳本一樣,其中也可以執行操作系統的命令。
Makefile帶來的好處就是“自動化編譯”,一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發的效率。
make是一個命令工具,是一個解釋makefile中指令的命令工具, 在終端中輸入make命令,會自動搜索當前路徑下的makefile或者是Makefile文件 。
2、Makefile編寫
(1)Makefile示例1及分析
edit:main.o test.o #需要生成的目標:生成目標的依賴項
g++ main.o test.o -o test #以Tab鍵開始,具體要執行的命令
test.o:
g++ -c test.cpp
main.o:
g++ -c main.cpp
clean:
rm main.o test.o
- makefile書寫規則包含兩個部分,一個是依賴關係,一個是生成目標的方法。
- 我們可以把這個內容保存在文件爲“Makefile”或“makefile”的文件中(最好使用 “Makefile”這個文件名),然後在該目錄下直接輸入命令“make”就可以生成執行文件edit。
- 如果要刪除執行文件和所有的中間目標文件,那麼,只要簡單地執行一下“make clean”就可以。
- 在Makefile中使用“#”字符,表示註釋。
通過示例1看make的工作過程:
- 首先,輸入make命令,make會在當前目錄下找名字叫“Makefile”或“makefile”的文件;
- 如果找到,它會找文件中的第一個目標文件,即“edit”文件,並把這個文件作爲最終的目標文件;
- 如果edit文件不存在,或是edit所依賴的後面的 .o 文件的文件修改時間要比edit這個文件新,那麼,他就會執行後面所定義的命令來生成edit這個文件;
- 如果edit所依賴的.o文件也不存在,那麼make會在當前文件中找目標爲.o文件的依賴性,如果找到則再根據那一個規則生成.o文件。(這有點像一個堆棧的過程);
- 然後再用 .o 文件生成make的終極任務,也就是執行文件edit。
這就是整個make的依賴性,make會一層又一層地去找文件的依賴關係,直到最終編譯出第一個目標文件。在尋找的過程中,如果出現錯誤,比如最後被依賴的文件找不到,那麼make 就會直接退出,並報錯,而對於所定義的命令的錯誤或是編譯不成功,make根本不理。make 只管文件的依賴性。
(2)Makefile示例2及分析
#################################################
# Example for call LTP libraries under UNIX #
#################################################
cc=g++
ccflags=-O2
all: cws \
pos
cws: cws.cpp
${cc} ${ccflags} -o cws cws.cpp -I./ \
-I../include/ \
-I../thirdparty/boost/include \
-L../lib/ -lsegmentor -lboost_regex
pos: pos.cpp
${cc} ${ccflags} -o pos pos.cpp -I./ \
-I../include/ \
-L../lib/ -lpostagger
.PHONY: clean
clean:
rm cws
rm pos
- 反斜槓(\)是換行符的意思。這樣比較便於Makefile的閱讀;
- -I../include/表示依賴的頭文件路徑,-L../lib/表示依賴的庫路徑;
- -O2:表示編譯時使用二級優化
- makefile中使用變量,比如:cc=g++,makefile中以“$(cc)”的方式來使用這個變量;變量的命名字可以包含字符、數字,下劃線(可以是數字開頭),但不應該含有“:”、“#”、“=”或是空字符(空格、回車等)。變量是大小寫敏感的,“foo”、“Foo”和“FOO”是三個不同的變量名。
- 清空目標文件的規則:爲了避免和文件重名的這種情況,我們可以使用一個特殊的標記“.PHONY”來顯示地指明一個目標是“僞目標”,向make說明,不管是否有這個文件,這個目標就是“僞目標”。只要有“.PHONY : clean ”這個聲明,不管是否有“clean”文件,要運行“clean”這個目標,只需“make clean” 即可。
(3)Makefile編寫規則
- 顯式規則。顯式規則說明了,如何生成一個或多的的目標文件。這是由Makefile的書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令。
- 隱晦規則。由於make有自動推導的功能,所以隱晦的規則可以讓我們比較粗糙地簡略地書寫Makefile,這是由make所支持的。
- 變量的定義。在Makefile中我們要定義一系列的變量,變量一般都是字符串,當Makefile被執行時,其中的變量都會被擴展到相應的引用位置上。
- 文件指示。其包括了三個部分,一個是在一個Makefile中引用另一個Makefile,就像C語言中的include一樣;另一個是指根據某些情況指定Makefile中的有效部分,就像C語言中的預編譯#if一樣;還有就是定義一個多行的命令。
- 註釋。Makefile中只有行註釋,和UNIX的Shell腳本一樣,其註釋是用“#”字符,這個就像C/C++中的“//”一樣。如果你要在你的Makefile中使用“#”字符,可以用反斜框進行轉義,如:“#”。
注:在Makefile中的命令,必須要以[Tab]鍵開始。
(4)make工作時執行過程
- 讀入所有的Makefile;
- 讀入被include的其它Makefile;
- 初始化文件中的變量;
- 推導隱晦規則,並分析所有規則;
- 爲所有的目標文件創建依賴關係鏈;
- 根據依賴關係,決定哪些目標要重新生成;
- 執行生成命令。
(5)makefile文件中使用通配符
我們想定義一系列比較類似的文件,可以使用通配符。make支持三種通配符:“*”,“?”和“[...]”;通配符可以代替一系列的文件,如“*.cpp”表示所有後綴爲cpp的文件。一個需要我們注意的是,如果我們的文件名中有通配符,如:“*”,那麼可以用轉義字符“\”,如“\*”來表示真實的“*”字符。
(6)Makefile中的-Wall -O2 -Os -g等選項介紹
- -Wall:選項可以打印出編譯時所有的錯誤或者警告信息。這個選項很容易被遺忘,編譯的時候,沒有錯誤或者警告提示,以爲自己的程序很完美,其實,裏面有可能隱藏着許多陷阱。變量沒有初始化,類型不匹配,或者類型轉換錯誤等警告提示需要重點注意,錯誤就隱藏在這些代碼裏面。沒有使用的變量也需要注意,去掉無用的代碼,讓整個程序顯得乾淨一點。下次寫Makefile的時候,一定加-Wall編譯選項。
- -O0: 表示編譯時沒有優化。
- -O1: 表示編譯時使用默認優化。
- -O2: 表示編譯時使用二級優化。
- -O3: 表示編譯時使用最高級優化。
- -Os:相當於-O2.5優化。
3、make的運行和退出
(1)make的運行
直接在命令行下輸入make命令,make命令會找當前目錄的makefile來執行,一切都是自動的。
(2)make的退出
make命令執行後有三個退出碼:
- 0 —— 表示成功執行。
- 1 —— 如果make運行時出現任何錯誤,其返回1。
- 2 —— 如果你使用了make的“-q”選項,並且make使得一些目標不需要更新,那麼返回2。