1.編譯過程
1.1 預處理(Pre-Processing)
展開頭文件, 宏替換(變量宏、函數(shù)宏)、替換空格等
gcc -E hello.c -o hello.i // -E 預處理選項, -o 重命名
1.2 編譯(Compilation)
逐行檢查程序中出現(xiàn)的語法錯誤,簡單的邏輯錯誤
gcc -S hello.i -o hello.s
1.3 匯編(Assemble)
將 .s 匯編文件中所有的匯編指令翻譯成二進制機器碼(下面就是來了個截圖,二進制顯示了亂碼)
gcc -c hello.s -o hello.o
1.4 鏈接(Linking)
將 .o 的目標文件,鏈接庫文件、數(shù)據(jù)段合并,地址回填(把匯編里相對地址替換成程序運行后真正可以運行的地址)。生成可執(zhí)行文件 hello
gcc hello.o -o hello
1.5 gcc常用參數(shù)
-E // 展開頭文件 -s // 生成匯編文件 -c // 編譯生成2進制文件 -I // 指定頭文件路徑 大i -L // 指定庫文件路徑 -l // 指定庫名 小L -g // 包含調試信息 -On // n取 0-3, n 越大優(yōu)化級別越高 -Wall //warning all 顯示所有警告 -D // 編譯時動態(tài)注入一個宏, 編譯的時候控制#define的具體數(shù)值
2.動態(tài)庫和靜態(tài)庫
2.1 函數(shù)庫
本質:把具有相同功能的一組函數(shù)放到同一份文件中(源碼或二進制的形式)
2.2 靜態(tài)庫
對執(zhí)行速度有要求
- 機制:把引入的庫文件通過編譯直接復制到 .out 文件中
- 優(yōu)點:將函數(shù)庫中的函數(shù)本地化,尋址方便,速度快(函數(shù)庫執(zhí)行效率 = 自定義函數(shù)的執(zhí)行效率)
- 缺點:每個程序都需要復制一份,會浪費內存
制作靜態(tài)庫:?
gcc -c add.c sub.c mul.c // 制作 .o 文件 ar rs libmymath.a add.o sub.o mul.o // 制作靜態(tài)庫 gcc hello.c -L ./ -lmymath -o app // 指定頭文件路徑, 指定庫名, 設置文件輸出名app
2.3 動態(tài)庫
對執(zhí)行速度不敏感,對系統(tǒng)資源敏感;更新比較頻繁(可以避免完全重新編譯)
- 機制:代碼共享
- 優(yōu)點:節(jié)省內存(共享)、易于更新(動態(tài)鏈接)
- 缺點:相較于靜態(tài)庫函數(shù)調用速度慢,函數(shù)地址是延時綁定機制
gcc -c -fPIC add.c sub.c mul.c // -fPIC生成與位置無關的目標文件 gcc -shared -o libmymath.so sub.o mul.o add.o // 生成一個動態(tài)庫 gcc hello.c -o app -L ./lib -l mymath -I ./inc // 生成文件
啟動 ./app 報錯,錯誤原因:”動態(tài)鏈接器“ ld-linux-x86-64.so.2 搜索動態(tài)庫的路徑?jīng)]有指定
鏈接器:工作于 gcc 編譯過程中的鏈接階段。工作結束后生成可執(zhí)行文件
動態(tài)鏈接器:工作于可執(zhí)行程序運行之后,輔助加載器負責將動態(tài)庫加載到內存
解決辦法:
環(huán)境變量法:export LD_LIBRARY_PATH=./lib 將當前動態(tài)庫所在的目錄加入到環(huán)境變量,終端退出后環(huán)境變量就會失效
配置文件法:vi .bashrc 加入一行 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib,重啟終端,每次啟動終端自動生效
拷貝法:把自己的動態(tài)庫直接拷貝到 /lib 或 /usr/lib 中
緩存文件法(推薦):修改配置文件,修改緩存文件,生成動態(tài)鏈接器需要搜索的新目錄位置
sudo vim /etc/ld.so.conf // 修改動態(tài)鏈接庫的路徑 // 將絕對路徑增加到文件中 sudo ldconfig -v // 更新 ld.so.cache 該文件影響動態(tài)鏈接庫搜索的位置
3.makefile
3.1 語法
目標:依賴條件
tab縮進,指令
hello:hello.o add.o sub.o mul.o gcc hello.o add.o sub.o mul.o -o hello hello.o:hello.c gcc -c hello.c -o hello.o sub.o:sub.c gcc -c sub.c -o sub.o add.o:add.c gcc -c add.c -o add.o mul.o:mul.c gcc -c mul.c -o mul.o
模式規(guī)則:在makefile中,具有有嚴格統(tǒng)一的規(guī)則,使用模式規(guī)則代替,模式規(guī)則中只能使用 $< 符號
%.o:%.c
gcc -c $< -o $@
靜態(tài)模式規(guī)則:將模式規(guī)則指定給某一個變量使用
$(obj):%.o:%.c
gcc -c $< -o $@
偽目標:針對殘缺的規(guī)則,使之生成目標(比如有一個clean.o文件已經(jīng)是最新的,就不會執(zhí)行clean清除命令
.PHONY:clean ALL
3.2 函數(shù)介紹
3.2.1 wildcard 函數(shù)
// 匹配當前工作目錄下的所有 .c 文件,將文件名組成列表,賦值給 src 變量 // src = add.c sub.c mul.c hello.o src = $(wildcard ./*.c)
3.2.2 patsubst 函數(shù)
// 用來替換參數(shù), 將 參數(shù)3 中包含 參數(shù)1 的部分替換為 參數(shù)2 // obj = add.o sub.o mul.o hello.o obj = $(patsubst %.c, %.o, $(src))
3.3 普通變量和自動變量
普通變量
- 定義變量語法:變量名 = 變量值? ? ?(foo = abc)
- 取變量值語法:$(變量)? ? ? ? ? ?(bar = $abc ---> bar = abc)
自動變量
- $@: 在規(guī)則的命令中,表示規(guī)則中的目標
- $^ : 在規(guī)則的命令中,表示所有依賴條件
- $< : 在規(guī)則的命令中,表示第一個依賴條件。如果該變量應用在”模式規(guī)則“中,它可以將依賴條件列表中的每一個依賴,依次取出,套用模式規(guī)則
3.4 關鍵字
ALL: 默認情況下第一組生成文件的目標就是終極目標,或者顯示的寫ALL:hello表示終極目標,完成后結束makefile
clean: 借助makefile清除項目中的指定文件,例如(clean: -rm -rf $(obj) hello
指令 make -n 模擬執(zhí)行命令,不真正執(zhí)行,可以先看一次避免出問題
3.5 修改后的 makefile
src = $(wildcard *.c) obj = $(patsubst %.c, %.o, $(src)) CC = gcc target = app ALL:$(target) $(target):$(obj) $(CC) $^ -o $@ $(obj):%.o %.c $(CC) -c $< -o $@ clean: -rm -rf $(obj) $(target) .PHONY:clean ALL
4. gdb調試
4.1 基礎指令
基礎的斷點設置和繼續(xù)運行等指令文章來源:http://www.zghlxwxcb.cn/news/detail-711064.html
- -g:使用該指令編譯可執(zhí)行文件,否則沒有調試表
- gdb ./a.out
- list:list 1 列出源碼,根據(jù)源碼指定行號設置斷點,1表示從第一行開始顯示源碼
- b:b 55 在第55行添加斷點
- run/r:運行程序,啟動調試(可以直接找到停止位置就是出錯位置)
- next/n:下一條指令(越過函數(shù))
- step/s:下一條執(zhí)行(進入函數(shù)內部)
- print/p:打印變量值,如p var 查看 var 變量的值
- continue:執(zhí)行到下一個斷點
- finish:結束當前函數(shù)調用
- quit:退出調試
- start:不使用斷點,直接開始單步調試
設置一些條件和查看棧幀及變量文章來源地址http://www.zghlxwxcb.cn/news/detail-711064.html
- set args:啟動gdb調試后,通過該指令可以設置main函數(shù)的參數(shù),需要在start和run指令之前設置
- info b:查看當前斷點信息表
- b 23 if i=5:設置斷點在23行,如果 i=5 時斷點才生效
- ptybe:查看變量類型
- display:設置跟蹤變量,display i,跟蹤變量 i
- undisplay:取消跟蹤變量
- bt:列出當前程序存活的棧幀
- frame:如果有多層調用,在內層想查看外層棧幀里的參數(shù),使用 frame n (n 是棧幀編號)切換棧幀,再使用 p var 打印變量
到了這里,關于Linux下gcc編譯,動態(tài)庫和靜態(tài)庫,makefile,gdb調試的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!