工程管理器make和調試工具gdb

Make

在實際的開發過程中,僅僅通過使用 gcc 命令對程序進行編譯是非常低效的。源文件的個數越多,那麼 gcc 的命令行就會越長。gcc 會把那些沒有被修改的源文件一起編譯,這樣

就會影響編譯的總體效率。所以引入工程管理器make。所有的編譯規則都保存在 Makefile 文件中。全自動化的工程管理器在編譯程序前會自動生成 Makefile 文件。

make的優點:

1)使用方便

 通過命令“make”就可以啓動 Make 工程管理器對程序進行編譯,所以不再需要每次都輸入 gcc 命令行。Make 啓動後會根據 Makefile 文件中的編譯規則命令自動對源文件進行編譯和鏈接,最終生成可執行文件。

 

2)調試效率高

 爲了提高編譯程序的效率,Make 會檢查每個源文件的修改時間(時間戳)。只有在上次編譯之後被修改的源文件纔會在接下來的編譯過程中被編譯和鏈接,這樣就能避免多餘的編譯工作量。

Make 工程管理器是完全根據 Makefile 文件中的編譯規則命令進行工作的。Makefile 文件由以下三項基本內容組成。

 

1)需要生成的目標文件(target file)。

 

2)生成目標文件所需要的依賴文件(dependency file)。

 

3)生成目標文件的編譯規則命令行(command)。

 

這三項內容按照如下格式進行組織:

 

target:dependency

<tab字符>command

Make 工程管理器編譯 test 程序的過程如下:

 

1)Make 工程管理器首先會在當前目錄下讀取 Makefile 文件。

 

2)查找 Makefile 文件中的第一個目標文件(在本例中爲 test),該文件也是 Make 工程管理器本次編譯任務的最終目標。

 

3)把目標文件 test 的依賴文件當作目標文件進行依賴規則檢查。這是一個遞歸的檢查過程。在本例中就是依次把 a.o 和 b.o 作爲目標文件來檢查各自的依賴規則。Make 會根據以下三種情況進行處理:

 

1) 如果當前目錄下沒有或缺少依賴文件,則執行其規則命令生成依賴文件(比如缺少 a.

 

文件,則執行命令“cc -c a.c”生成 a.o)。

 

2) 如果存在依賴文件,則把其作爲目標文件來檢查依賴規則(假設 a.c 比 a.o 新,則執行命令“cc -c a.c”更新 a.o)。

 

3) 如果目標文件比所有依賴文件新,則不做處理。

 

4)遞歸執行第三步後,就會得到目標文件 test 所有最新的依賴文件了。接着 Make 會根據以下三種情況進行處理:

 

1) 如果目標文件 test 不存在(比如第一次編譯),則執行規則命令生成 test。

 

2) 如果目標文件 test 存在,但存在比 test 要新的依賴文件,則執行規則命令更新 test。

 

3) 目標文件 test 存在,且比所有依賴文件新,則不做處理。



ep:

在makefile目錄下編寫makefile文件


CC=gcc

target = hello

object = hello.o print.o


$(target):$(object)

<tab>$(CC) $(object) -o $(target)

clean:

<tab>rm-rf helllo *.o


保存推出後輸入make


ep:make

gcc -c -o print.o print.c

gcc hello.o print.o -o hello


輸入ls

ep:ls

hello hello.c hello.o makefile print.c print.o


輸入make clean後ls

ep: make clean

ls


hello. c makefile print.c


在 Makefile 文件中,存在着大量的文件名,而且這些文件名都是重複出現的。所以在源文件比較多的情況下,很容易發生遺漏或寫錯文件名。而且一旦源文件的名稱發生了變

化,還容易造成與其他文件名不一致的錯誤。於是,Makefile 提供了變量來代替文件名。變量的使用方式爲:$(變量名)


Make 工程管理器提供了靈活的變量定義方式,具體有以下幾種實現方式。

1)通過“=”來實現

這種方式下前面的變量可以通過後面的變量來定義。但使用這種方式定義變量時,要防止出現死循環的情況。

2)通過“:=”來實現

這種方式下前面的變量不能通過後面的變量來定義。

3)通過“+=”來實現

這種方式下“+=”可以實現給變量追加值。

4)通過“?=”來實現

這種方式下如果變量 a1 已經在前面定義過了,那麼後面的定義就無效了。


僞目標

 

僞目標不是真正的目標文件,所以通過僞目標可以讓 Make 工程管理器只執行規則命令,而不用創建實際的目標文件。僞目標的使用方式爲:

 make (僞目標名)

 

由於僞目標不是真正的目標文件,只是一個符號。爲了不和真實的目標文件混淆,最好

 

使用“.PHONY”對僞目標進行標識。

1)all

 運行命令“make all”後,Make 會把 all 看成是最終的目標。由於僞目標和真實目標一樣都有依賴文件,所以 Make 會更新 all 的依賴文件 test、a.o 和 b.o。

2)clean

 運行命令“make clean”後,Make 會執行命令“rm -rf test $(obj)”。這樣 test、 a.o 和 b.o 文件就全被刪除了。

3)install

 運行命令“make clean”後,Make 會順序執行命令“mkdir $(test_dir)”和“cp test $(test_dir)”,把 test 文件複製到 test_dir 變量指定的目錄中去。

4)uninstall

運行命令“make clean”後,Make 會執行命令“rm -rf $(test_dir)”。這樣就可以把變量 test_dir 指定的目錄以及目錄中的文件全部刪除。



 文件查找

 

爲了便於管理和組織,程序的源文件都根據功能的不同放置在不同的子目錄中。但是源文件被分散存儲之後,Makefile 又如何才能找到這些源文件呢?Makefile 提供了以下兩種方法。

 

1)VPATH

 

VPATH 是一個特殊變量。Make 在當前路徑找不到源文件的情況下就會自動到 VPATH 中指定的路徑中去尋找。VPATH 的使用方法爲:

 

 VPATH = 目錄 : 目錄 „

 

 

2)vpath

 

VPATH 不同的是,vpath 並不是變量而是關鍵字。其作用和 VPATH 類似,但使用方式更加靈活。vpath 的使用方法爲:

 

 vpath 模式目錄: 目錄 „



嵌套執行

 

如果把所有源文件的編譯規則命令都寫在一個 Makefile 中,會造成 Makefile 過於臃腫,爲編寫和修改帶來了很大的不便。解決這個問題的辦法是把 Makefile 分解成多個子Makefile,並放置到程序的每個子目錄中,每個子 Makefile 文件負責所在目錄下源文件的編譯工作。

 Make 工程管理器會首先讀取程序根目錄下的 Makefile 文件(總控 Makefile),然後再去讀取各個目錄中的子 Makefile 文件。這個過程就稱爲 Make 的嵌套執行。




gdb

程序的調試工作在整個程序的開發過程中佔據了相當大的比例。使用 gcc 調試 C 程序時,只能依靠 gcc 發出的警告或錯誤信息來進行,所以調試的效率非常低。爲此,GNU 開發了 GDB 調試器(GNU Debugger)。GDB 的調試功能非常強大,甚至可以 Visual C++、Visual Basic、Jbuilder 等開發工具的調試器相媲美。但 GDB 的缺點是沒有圖形調試界面。儘管如此,對於從事嵌入式 Linux 應用開發的人員還是有必要知道 GDB的使用方法的。

假設寫個程序名爲 add.c

1. 輸入gcc -g add.c -o add 進行編譯

2.使用命令 gdb add進行調試(若需參數,則gdb -- args add arg1 arg2 )

[root@localhost home]# gdb test

GNU gdb Everest Linux (6.4-1)

Copyright 2005 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

下面對一些常用命令進行介紹

1)查看源文件

 在調試程序時,gcc 會給出產生警告或錯誤的代碼行數。但在普通的文本環境中是無法直接獲得語句行數的。在 GDB 中通過命令 l(list 的縮寫)可以查看所有的代碼行數。GDB 以 10 行爲單位進行顯示。再運行一次命令 l 就會顯示下 10 行代碼。這樣設計方便了源代碼的閱讀。


2)設置斷點

 斷點是調試程序的重要方法,通過斷點可以知道程序每一步的執行狀況(比如當前變量的值、函數是否調用、堆棧使用情況等)。在 GDB 中通過命令 b(breakpoint 的縮寫)進行斷點設置。如下所示:

 (gdb) b 7

 Breakpoint 1 at 0x8048389: file add.c, line 7.

可以看到,命令 b 在程序的第 7 行處設置了第一個斷點,並顯示了該斷點在內存中的物理地址。


3)查看斷點情況

由於使用命令 b 可以設置多個斷點,所以用戶需要能夠隨時查看各個斷點的情況。在GDB 中通過命令“info b”查看所有的斷點情況。


4)運行程序

  GDB 中通過命令 r(run 的縮寫)運行程序。GDB 默認從代碼的首行開始運行(也可以通過“r 行數”的方式讓程序從指定行數開始運行)。如果程序中有斷點,則程序會在斷點行數的前一行暫停運行。



5)查看變量值

 程序暫停運行後就可以查看當前的狀態了。在 GDB 中通過命令“p 變量名”print 的縮寫)查看當前變量 n 的值。


6)繼續運行程序

 查看完當前程序的情況後,就可以讓程序繼續往下運行了。在 GDB 中通過命令 c 讓程序繼續往下運行。在 test.c 中,由於函數 cal 是遞歸調用運行,所以程序會再次在斷點處暫停。


7)單步運行

 在程序邏輯比較複雜的時候往往需要程序能一步一步的往下運行,但如果每行都設置一個斷點的話又會很麻煩。在 GDB 中可以通過命令 s(step 的縮寫)和 n(next 的縮寫)讓程序一步一步的往下運行。其中 s 可以在發生函數調用時進入函數內部運行,而 n 不會進入函數內部運行。在 test.c 中。由於函數 cal 是遞歸調用運行,所以只能選擇 s 才能看到變量n的值。


















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章