G++(Linux)
-I(大寫i)挥唠,到指定目錄搜索頭文件
-L抵恋,到指定目錄搜索庫(kù)文件
-l(小寫L),到前面指定的目錄下添加庫(kù)文件進(jìn)行鏈接
-o宝磨,為生成文件重命名
???g++ -E xxx.cpp
???不加-o 生成xxx.i
???加-o xxx123 生成xxx123
-E弧关,將源代碼 .c/.cpp文件進(jìn)行預(yù)編譯
???將所有#define刪除
???并且展開(kāi)所有的宏定義處理所有的條件預(yù)編譯指令,如#if #ifdef #undef #ifndef #endif #elif處理#include
???將包含的文件插入到此處唤锉,這是一個(gè)遞歸的過(guò)程
???刪除所有注釋 // /* */添加行號(hào)和文件名標(biāo)識(shí)世囊,以便于編譯時(shí)產(chǎn)生的錯(cuò)誤警告能顯示行號(hào)
???保留#pragma編譯器指令
???g++ -E xxx.cpp 生成xxx.i
-S,將預(yù)處理完的.i文件進(jìn)行一系列的詞法分析窿祥、語(yǔ)法分析株憾、語(yǔ)義分析及優(yōu)化后生成響應(yīng)的匯編代碼文件
???g++ -S xxx.cpp/xxx.i 生成xxx.s
-c,生成目標(biāo)文件 以xxx.o結(jié)尾晒衩,可以用于生成庫(kù)文件
???g++ -c xxx.cpp/xxx.s 生成xxx.o
靜態(tài)庫(kù)
在g++ -c命令創(chuàng)建完.o結(jié)尾的目標(biāo)文件后嗤瞎,可以通過(guò)ar命令打包成靜態(tài)庫(kù)
實(shí)際上ar命令是用于創(chuàng)建備存文件的,將一些文件打包成一個(gè)文件听系,類似于壓縮文件贝奇,但不完全等于壓縮文件
實(shí)際上在調(diào)用g++ -l(小寫L)指令的時(shí)候?qū)浯嫖募械?o文件提取出來(lái)進(jìn)行鏈接操作
但是在鏈接中需要用到-L來(lái)指示庫(kù)文件所在目錄,用-l(小寫L)來(lái)指定庫(kù)文件
而-l(小寫L)時(shí)會(huì)補(bǔ)充xxx前后的lib與.a靠胜,所以在使用ar命令來(lái)打包靜態(tài)庫(kù)的時(shí)候需要直接命名為libxxx.a
在實(shí)際上以下兩種鏈接方法完全等效
$ g++ main.cpp -L./lib -lmath
$ g++ main.cpp math.o
一般對(duì).o結(jié)尾的目標(biāo)文件生成靜態(tài)庫(kù)的時(shí)候弃秆,使用以下參數(shù)
ar rcs [備存文件] [成員文件]
(靜態(tài)庫(kù)文件名) (目標(biāo)文件名)
例 ar rcs libmath.a math.o
更多ar命令届惋,請(qǐng)看以下
Linux ar命令
動(dòng)態(tài)庫(kù)
動(dòng)態(tài)庫(kù)編譯方式如同靜態(tài)庫(kù)一樣,先要編譯出目標(biāo)文件.o菠赚,然后組成.so庫(kù)—— g++ -c math.cpp -o math.o
但是這次編譯需要用到-fPIC指令來(lái)編譯脑豹,在g++ -fPIC -c math.cpp -o math.o
獲得了目標(biāo)文件.o后,需要用指令-shared聲明將.o文件鏈接成.so庫(kù)衡查,g++ -shared -o libmath.so math.o
實(shí)際上生成.so庫(kù)可以合成一個(gè)指令瘩欺,g++ -fPIC -shared math.cpp -o libmath.so
編譯main.cpp時(shí),需要和鏈接靜態(tài)庫(kù)一樣拌牲,要用到-L與-l(小寫L)俱饿,但是要添加-ldl,g++ math.cpp -L ./so/ -lmath -ldl
關(guān)于載入動(dòng)態(tài)庫(kù)的規(guī)則:
在Linux中塌忽,系統(tǒng)會(huì)按照一定方式搜索動(dòng)態(tài)庫(kù)文件
- (僅限ELF)如果調(diào)用程序的可執(zhí)行文件包含 DT_RPATH 標(biāo)記拍埠,并且不包含 DT_RUNPATH 標(biāo)記,則會(huì)搜索 DT_RPATH 標(biāo)記中列出的目錄土居。
- 如果在程序啟動(dòng)時(shí)枣购,環(huán)境變量 LD_LIBRARY_PATH 被定義為包含以冒號(hào)分隔的目錄列表,則會(huì)搜索這些目錄擦耀。 (作為安全措施棉圈,set-user-ID 和 set-group-ID程序?qū)⒑雎源俗兞俊#?/li>
- (僅限ELF)如果調(diào)用程序的可執(zhí)行文件包含?DT_RUNPATH?標(biāo)記眷蜓,則搜索該標(biāo)記中列出的目錄分瘾。
- 檢查緩存文件/etc/ld.so.cache(由ldconfig(8)維護(hù))以查看它是否包含filename的條目。
- 搜索目錄 /lib和 /usr/lib(按此順序)吁系。
例如創(chuàng)建環(huán)境變量 LD_LIBRARY_PATH 德召,在中間加入動(dòng)態(tài)庫(kù)的目錄,export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./so
在執(zhí)行調(diào)用動(dòng)態(tài)庫(kù)時(shí)汽纤,需要對(duì)以上規(guī)則內(nèi)的目錄進(jìn)行添加對(duì)應(yīng)動(dòng)態(tài)庫(kù)上岗,也可以用ldd命令查看可執(zhí)行文件中調(diào)用的動(dòng)態(tài)庫(kù)是否存在對(duì)應(yīng)的文件,ldd a.out
如何執(zhí)行動(dòng)態(tài)庫(kù)中的程序冒版?
一、隱式執(zhí)行
二逞姿、顯示執(zhí)行
一辞嗡、隱式執(zhí)行
庫(kù)文件中的可執(zhí)行函數(shù)都聲明為靜態(tài)(static),int main()中直接調(diào)用該靜態(tài)函數(shù)滞造,道理懂得都懂续室。
二、顯示執(zhí)行
使用<dlfcn.h>函數(shù)庫(kù)中各種庫(kù)函數(shù)谒养,加載動(dòng)態(tài)庫(kù)挺狰,執(zhí)行動(dòng)態(tài)庫(kù)中程序etc.
介紹幾個(gè)常用動(dòng)態(tài)庫(kù)函數(shù)
1.dlopen
??void* dlopen(const char* filename,int mode)
??filename 為動(dòng)態(tài)庫(kù)名明郭,mode為載入動(dòng)態(tài)庫(kù)的方式模式。
??mode:
??1丰泊、解析方式
??RTLD_LAZY:在dlopen返回前薯定,對(duì)于動(dòng)態(tài)庫(kù)中的未定義的符號(hào)不執(zhí)行解析(只對(duì)函數(shù)引用有效,對(duì)于變量引用總是立即解析)瞳购。
??RTLD_NOW: 需要在dlopen返回前话侄,解析出所有未定義符號(hào),如果解析不出來(lái)学赛,在dlopen會(huì)返回NULL年堆,錯(cuò)誤為:: undefined symbol: xxxx.......
??2、作用范圍盏浇,可與解析方式通過(guò)“|”組合使用变丧。
??RTLD_GLOBAL:動(dòng)態(tài)庫(kù)中定義的符號(hào)可被其后打開(kāi)的其它庫(kù)解析。
??RTLD_LOCAL: 與RTLD_GLOBAL作用相反绢掰,動(dòng)態(tài)庫(kù)中定義的符號(hào)不能被其后打開(kāi)的其它庫(kù)重定位痒蓬。如果沒(méi)有指明是RTLD_GLOBAL還是RTLD_LOCAL,則缺省為RTLD_LOCAL曼月。
??3谊却、作用方式
??RTLD_NODELETE: 在dlclose()期間不卸載庫(kù)胰舆,并且在以后使用dlopen()重新加載庫(kù)時(shí)不初始化庫(kù)中的靜態(tài)變量妹田。這個(gè)flag不是POSIX-2001標(biāo)準(zhǔn)酿秸。
??RTLD_NOLOAD: 不加載庫(kù)粤咪〔牌幔可用于測(cè)試庫(kù)是否已加載(dlopen()返回NULL說(shuō)明未加載哎垦,否則說(shuō)明已加載)柒昏,也可用于改變已加載庫(kù)的flag显蝌,如:先前加載庫(kù)的flag為RTLD_LOCAL末购,用dlopen(RTLD_NOLOAD|RTLD_GLOBAL)后flag將變成RTLD_GLOBAL破喻。這個(gè)flag不是POSIX-2001標(biāo)準(zhǔn)。
??RTLD_DEEPBIND:在搜索全局符號(hào)前先搜索庫(kù)內(nèi)的符號(hào)盟榴,避免同名符號(hào)的沖突曹质。這個(gè)flag不是POSIX-2001標(biāo)準(zhǔn)。
??dlopen執(zhí)行后返回一個(gè)handle
2.dlsym
??void* dlsym(void* handle,const char* symbol)
??執(zhí)行完后返回handle中的對(duì)應(yīng)symbol符號(hào)的地址
??其中handle就是dlopen執(zhí)行完后的handle擎场,symbol就是要求獲取的函數(shù)或全局變量的名稱
??關(guān)于symbol羽德,其中有說(shuō)法的是符號(hào)名
??因?yàn)樵赾++中為了保證多態(tài)性,函數(shù)都能進(jìn)行重載迅办,所以在c++中的符號(hào)名不是完全按照函數(shù)名來(lái)命名宅静,會(huì)按照不同編譯器的方式進(jìn)行改編
??而c中不需要保證多態(tài)性,所以符號(hào)名都為函數(shù)名站欺。
??所以在需要進(jìn)行c方式編譯的代碼段姨夹,用 extern "C" 來(lái)聲明這一段代碼用C語(yǔ)言來(lái)編譯纤垂,使用dlsym時(shí),便可以通過(guò)函數(shù)名來(lái)調(diào)用庫(kù)中的函數(shù)
3.dlclose
??int dlclose (void *handle)
??傳入handle磷账,卸載handle所指的動(dòng)態(tài)庫(kù)內(nèi)存區(qū)域
4.dlerror
??char *dlerror(void)
??返回錯(cuò)誤信息