用C編譯器編譯源文件:gcc 源文件 -o 可執行文件名
詳細步驟:
gcc -E a.c -o a.i
預處理器將頭文件展開,宏替換,去掉注釋gcc -S a.i -o a.s
編譯器將C文件變成匯編文件gcc -c a.s -o a.o
匯編器將會變文件變成二進制文件gcc a.o -o a
鏈接器進行鏈接
ESc+鏈接
如果不使用參數-o
則自動生成a.out
制定頭文件的路徑gcc a.c -I 頭文件的目錄 -o 生成可執行文件的名字
在比較舊的版本上-I和頭文件目錄之間不能有空格,現版本無所謂
指定宏-D 宏名
優化-O1/O2/O3
O3優化速度最高
輸出警告信息-Wall
生成調試信息-g
靜態庫
- 命名規則
lib+庫的名字+.a
- 制作步驟
生成對應的.o
文件,直接使用參數-c
得到.o
文件,記得不要使用-o
參數,否則將會直接生成可執行文件
將生成的.o
文件進行打包,需要使用軟件ar
將.o
打包為.a
ar rcs 靜態庫名稱 所有的.o
- 發布和使用靜態庫
打包靜態庫和頭文件,將所有的靜態庫放到lib文件夾中,將所有的頭文件放到include文件夾中,制作好靜態庫以后可以發送這兩個文件夾。
用戶通過頭文件知道有哪些函數接口。通過直接和源文件編譯靜態庫使用。
gcc 源文件 靜態庫 -o 可執行文件 -Iinclude
gcc 源文件 -Iinclude -L lib -l 靜態庫文件名(去掉頭部lib和尾部.a) -o 可執行文件
- 靜態庫的優缺點
nm 靜態庫文件 //查看靜態庫
打包的最小單元為.o
優點:
- 庫已經打包在程序中,不需要再提供
- 庫的加載速度比較快
缺點: - 可執行文件會比較大
- 如果庫發生了改變需要重新編譯
動態庫/共享庫
- 命名規則
lib+名字+.so - 制作步驟
(1) 生成與位置無關的代碼(.o)
gcc -fPIC -c *.c -Iinlcude
(2) 將.o打包成共享庫
Linux每一個運行的程序操作系統都會為其分配一個0-4G的地址空間。Linux下可執行文件格式:ELF
gcc -shared -o libname.so *.o -Iinclude
再講lib中的.so文件和include中的頭文件發送給用戶
- 用戶使用
gcc main.c lib/libname.so -o main -Iinclude
gcc main.c -Iinclude -L lib -l name -o main//需要注意的是這里的name是不包含lib和后綴.so的
使用ldd
查看可執行文件所依賴的所有的共享庫的名字
動態庫的使用需要動態鏈接器幫助。我們需要讓動態鏈接器找到我們自己的動態鏈接庫
正常情況下使用會出現動態庫無法找到的問題。然后就需要我們去解決。
可是我自己嘗試的時候沒有遇到這個情況。。。我也不清楚為什么,可能是現在版本的gcc已經智能地解決這個問題了。
(1)將動態庫放到系統的lib文件夾中
(2) 配置環境變量LD_LIBRARY_PATH
(如果你的動態庫沒有在默認的環境變量中,會先在這個環境變量中查找)
用于臨時測試
echo $LD_LIBRARY_PATH //$從環境變量中取值 查看環境變量
export LD_LIBRARY_PATH=./lib //將當前目錄下的lib文件夾導入到環境變量中
關掉終端后失效
(3)
ls -a
vi .bashrc
在里面加上export LD_LIBRARY_PATH=動態庫目錄
重啟終端
永久
(4)工作中更加常用的方法
-
找到動態鏈接器的配置文件
/etc/ld.so.conf
需要使用管理員權限 -
將動態庫的路徑寫到配置文件中
-
更新
sudo ldconfig -v
-v是提示信息
動態庫沒有加載到源文件中,而是在需要使用的位置加上了一個標記,在使用的時候才進行訪問。
優點:
- 執行程序很小
- 動態庫更新方便
缺點: - 需要將動態庫發布給用戶
- 加載庫的時候速度較慢
gdb 調試
l
默認展示包含main()的文件l 文件名:行號
展示以行號為中心上下文件的內容l 文件名:函數名
展示文件中的函數,輸入l
繼續展示后面的內容,然后后面再直接按回車,會繼續向下展示文件,一次展示10行break 行號
在某一行打斷點b 行號
b 行號 if 條件
條件斷點,條件斷點只能設置在循環內部,如果設置在邊界不會停止b filename:行號
在某個文件的某一行設置斷點info break
i b
查看斷點信息start
gdb開始運行程序,每次運行一行,n
單步調試,c
繼續執行到斷點s
下一步,會進入函數體內部(step)n
下一步,不會進入函數內部run
直接運行到斷點,如果沒有斷點直接運行結束p 變量
展示某個變量的值ptype 變量
展示變量的類型display 變量
追蹤某個變量的值undisplay 變量編號
取消追蹤某個變量info display
打印所有追蹤變量的信息u
將循環運行結束,結束循環finish
跳出當前函數,需要將函數中的斷點消除d 斷點編號
刪除斷點(del)set var 變量=x
直接運行到變量為x的時候quit
退出gdb
makefile
makefile
項目管理工具,用于管理源代碼
簡單makefile文件
-
命名規則
(1)makefile
(2)Makefile
-
編寫規則
makefile 一般情況下要和.c
文件在一個文件夾中,如果不在需要絕對路徑
三要素:
目標:依賴 //目標就是想要生成文件的名字 依賴:`.c`文件命令(必須要有Tab縮進):gcc a.c b.c c.c -o 目標
- 使用
make
進階makefile文件
當一些文件修改以后需要重新編譯,為了解決這個問題:
例如:
app:main.o add.o sub.o mul.o //終極目標,默認第一條語句是終極目標gcc main.o add.o sub.o mul.o -o app
//如果依賴中的文件沒有發現,就去下面的子目標中查找有沒有相關的規則用于生成文件
main.o:main.c gcc main.c -c
add.o:add.cgcc add.c -c
sub.o:sub.cgcc sub.c -c
mul.o:mul.cgcc mul.c -c
上面的寫法會自動查找文件是否修改,如果沒有修改就不會編譯,從而提高效率
工作原理:通過比較修改時間,目標應該比依賴的修改時間遲,如果發現目標比依賴的修改時間早則重新生成目標。
進進階makefile文件
上面的寫法有些冗余,通過變量來將寫法變得簡潔
obj=main.o add.o sub.o mul.o
target=app
$(target):$(obj) //$取obj變量中的值gcc $^ -o $@
//模式規則
%.o:%.cgcc -c $< -o &@
makefile中的自動變量:
$<
規則中的第一個依賴$@
規則中的目標$^
規則中的所有依賴- 只能夠在規則中的命令來使用
makefile自己維護的變量: - 都是大寫,例如
CC,CPPFLAGS,CFLAGS,LDFLAGS
進進進階makefile文件
在makefile中的函數都是有返回值的
- 獲取指定目錄下所有的
.c
文件
src=$(wildcard 所需要查找的目錄/*.c)
- 獲取指定目錄下所有的
.o
文件
obj=$(patsubst ./%.c , ./%.o , $(src)) #模式匹配
- 自動刪除以前生成的目標文件
clean:rm $(target) -f #如果不存在也會強制刪除,不會彈出提示信息
生成文件 時候:
make clean #會刪除目標文件,只會執行生成clean的語句
如果目錄中真的存在clean
目標,則會提示目標是最新的而不會運行。
.PHONY:clean #聲明clean為偽目標,不會與目錄中的目標進行比較
在命令前面加上-
,則命令執行失敗以后也不會停下來,繼續向后執行