G++(Linux)
-I(大寫i),到指定目錄搜索頭文件
-L,到指定目錄搜索庫文件
-l(小寫L),到前面指定的目錄下添加庫文件進(jìn)行鏈接
-o,為生成文件重命名
???g++ -E xxx.cpp
???不加-o 生成xxx.i
???加-o xxx123 生成xxx123
-E,將源代碼 .c/.cpp文件進(jìn)行預(yù)編譯
???將所有#define刪除
???并且展開所有的宏定義處理所有的條件預(yù)編譯指令,如#if #ifdef #undef #ifndef #endif #elif處理#include
???將包含的文件插入到此處,這是一個(gè)遞歸的過程
???刪除所有注釋 // /* */添加行號(hào)和文件名標(biāo)識(shí),以便于編譯時(shí)產(chǎn)生的錯(cuò)誤警告能顯示行號(hào)
???保留#pragma編譯器指令
???g++ -E xxx.cpp 生成xxx.i
-S,將預(yù)處理完的.i文件進(jìn)行一系列的詞法分析、語法分析、語義分析及優(yōu)化后生成響應(yīng)的匯編代碼文件
???g++ -S xxx.cpp/xxx.i 生成xxx.s
-c,生成目標(biāo)文件 以xxx.o結(jié)尾,可以用于生成庫文件
???g++ -c xxx.cpp/xxx.s 生成xxx.o
靜態(tài)庫
在g++ -c命令創(chuàng)建完.o結(jié)尾的目標(biāo)文件后,可以通過ar命令打包成靜態(tài)庫
實(shí)際上ar命令是用于創(chuàng)建備存文件的,將一些文件打包成一個(gè)文件,類似于壓縮文件,但不完全等于壓縮文件
實(shí)際上在調(diào)用g++ -l(小寫L)指令的時(shí)候?qū)浯嫖募械?o文件提取出來進(jìn)行鏈接操作
但是在鏈接中需要用到-L來指示庫文件所在目錄,用-l(小寫L)來指定庫文件
而-l(小寫L)時(shí)會(huì)補(bǔ)充xxx前后的lib與.a,所以在使用ar命令來打包靜態(tài)庫的時(shí)候需要直接命名為libxxx.a
在實(shí)際上以下兩種鏈接方法完全等效
$ g++ main.cpp -L./lib -lmath
$ g++ main.cpp math.o
一般對(duì).o結(jié)尾的目標(biāo)文件生成靜態(tài)庫的時(shí)候,使用以下參數(shù)
ar rcs [備存文件] [成員文件]
(靜態(tài)庫文件名) (目標(biāo)文件名)
例 ar rcs libmath.a math.o
更多ar命令,請(qǐng)看以下
Linux ar命令
動(dòng)態(tài)庫
動(dòng)態(tài)庫編譯方式如同靜態(tài)庫一樣,先要編譯出目標(biāo)文件.o,然后組成.so庫—— g++ -c math.cpp -o math.o
但是這次編譯需要用到-fPIC指令來編譯,在g++ -fPIC -c math.cpp -o math.o
獲得了目標(biāo)文件.o后,需要用指令-shared聲明將.o文件鏈接成.so庫,g++ -shared -o libmath.so math.o
實(shí)際上生成.so庫可以合成一個(gè)指令,g++ -fPIC -shared math.cpp -o libmath.so
編譯main.cpp時(shí),需要和鏈接靜態(tài)庫一樣,要用到-L與-l(小寫L),但是要添加-ldl,g++ math.cpp -L ./so/ -lmath -ldl
關(guān)于載入動(dòng)態(tài)庫的規(guī)則:
在Linux中,系統(tǒng)會(huì)按照一定方式搜索動(dòng)態(tài)庫文件
- (僅限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)庫的目錄,export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./so
在執(zhí)行調(diào)用動(dòng)態(tài)庫時(shí),需要對(duì)以上規(guī)則內(nèi)的目錄進(jìn)行添加對(duì)應(yīng)動(dòng)態(tài)庫,也可以用ldd命令查看可執(zhí)行文件中調(diào)用的動(dòng)態(tài)庫是否存在對(duì)應(yīng)的文件,ldd a.out
如何執(zhí)行動(dòng)態(tài)庫中的程序?
一、隱式執(zhí)行
二、顯示執(zhí)行
一、隱式執(zhí)行
庫文件中的可執(zhí)行函數(shù)都聲明為靜態(tài)(static),int main()中直接調(diào)用該靜態(tài)函數(shù),道理懂得都懂。
二、顯示執(zhí)行
使用<dlfcn.h>函數(shù)庫中各種庫函數(shù),加載動(dòng)態(tài)庫,執(zhí)行動(dòng)態(tài)庫中程序etc.
介紹幾個(gè)常用動(dòng)態(tài)庫函數(shù)
1.dlopen
??void* dlopen(const char* filename,int mode)
??filename 為動(dòng)態(tài)庫名,mode為載入動(dòng)態(tài)庫的方式模式。
??mode:
??1、解析方式
??RTLD_LAZY:在dlopen返回前,對(duì)于動(dòng)態(tài)庫中的未定義的符號(hào)不執(zhí)行解析(只對(duì)函數(shù)引用有效,對(duì)于變量引用總是立即解析)。
??RTLD_NOW: 需要在dlopen返回前,解析出所有未定義符號(hào),如果解析不出來,在dlopen會(huì)返回NULL,錯(cuò)誤為:: undefined symbol: xxxx.......
??2、作用范圍,可與解析方式通過“|”組合使用。
??RTLD_GLOBAL:動(dòng)態(tài)庫中定義的符號(hào)可被其后打開的其它庫解析。
??RTLD_LOCAL: 與RTLD_GLOBAL作用相反,動(dòng)態(tài)庫中定義的符號(hào)不能被其后打開的其它庫重定位。如果沒有指明是RTLD_GLOBAL還是RTLD_LOCAL,則缺省為RTLD_LOCAL。
??3、作用方式
??RTLD_NODELETE: 在dlclose()期間不卸載庫,并且在以后使用dlopen()重新加載庫時(shí)不初始化庫中的靜態(tài)變量。這個(gè)flag不是POSIX-2001標(biāo)準(zhǔn)。
??RTLD_NOLOAD: 不加載庫??捎糜跍y(cè)試庫是否已加載(dlopen()返回NULL說明未加載,否則說明已加載),也可用于改變已加載庫的flag,如:先前加載庫的flag為RTLD_LOCAL,用dlopen(RTLD_NOLOAD|RTLD_GLOBAL)后flag將變成RTLD_GLOBAL。這個(gè)flag不是POSIX-2001標(biāo)準(zhǔn)。
??RTLD_DEEPBIND:在搜索全局符號(hào)前先搜索庫內(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,其中有說法的是符號(hào)名
??因?yàn)樵赾++中為了保證多態(tài)性,函數(shù)都能進(jìn)行重載,所以在c++中的符號(hào)名不是完全按照函數(shù)名來命名,會(huì)按照不同編譯器的方式進(jìn)行改編
??而c中不需要保證多態(tài)性,所以符號(hào)名都為函數(shù)名。
??所以在需要進(jìn)行c方式編譯的代碼段,用 extern "C" 來聲明這一段代碼用C語言來編譯,使用dlsym時(shí),便可以通過函數(shù)名來調(diào)用庫中的函數(shù)
3.dlclose
??int dlclose (void *handle)
??傳入handle,卸載handle所指的動(dòng)態(tài)庫內(nèi)存區(qū)域
4.dlerror
??char *dlerror(void)
??返回錯(cuò)誤信息