1. 動態(tài)庫和靜態(tài)庫介紹
1. 靜態(tài)庫(.a):程序在編譯鏈接的時候把庫的代碼鏈接到可執(zhí)行文件中。程序運行的時候?qū)⒉辉傩枰o態(tài)庫。
2. 動態(tài)庫(.so):程序在運行的時候才去鏈接動態(tài)庫的代碼,多個程序共享使用庫的代碼。
3. 一個與動態(tài)庫鏈接的可執(zhí)行文件僅僅包含它用到的函數(shù)入口地址的一個表,而不是外部函數(shù)所在目標(biāo)文件的整個機(jī)器碼。
4. 在可執(zhí)行文件開始運行以前,外部函數(shù)的機(jī)器碼由操作系統(tǒng)從磁盤上的該動態(tài)庫中復(fù)制到內(nèi)存中,這個過程稱為動態(tài)鏈接。
5. 動態(tài)庫可以在多個程序間共享,所以動態(tài)鏈接使得可執(zhí)行文件更小,節(jié)省了磁盤空間。操作系統(tǒng)采用虛擬內(nèi)存機(jī)制允許物理內(nèi)存中的一份動態(tài)庫被要用到該庫的所有進(jìn)程共用,節(jié)省了內(nèi)存和磁盤空間。
2. 創(chuàng)建一個靜態(tài)庫
首先,一個靜態(tài)庫里面不能有main函數(shù),原因是與我們自己的沖突。
我們這里寫了兩個函數(shù)方法,一個是累加計算,一個是查看時間戳。
如果我們只把所有的.o文件放在一起,就可以鏈接使用嗎?
我們可以來測試一下:
只要把所有.o文件放在一起就可以鏈接使用。既然只需要.o文件就可以了,那么如果.o文件多的時候,我們打個包就可以了。
那么該如何打包呢?
ar是gnu歸檔工具,rc表示(replace and create)。這樣就完成了打包。
如果我們想查看靜態(tài)庫中的目錄列表,我們可以這樣:
t:列出靜態(tài)庫中的文件。v:verbose 詳細(xì)信息。
我們也可以把這些過程寫入makefile里面:
我們知道:當(dāng)我們用庫的時候,我們需要頭文件和庫文件。那我們怎么在makefile里面寫呢?
3. 創(chuàng)建一個動態(tài)庫
動態(tài)庫和靜態(tài)庫的思路大致類似:
shared: 表示生成共享庫格式。fPIC:產(chǎn)生位置無關(guān)碼。庫名規(guī)則:libxxx.so。
那么我們可以把這兩個庫放在makefile里一起生成:
我們來運行一下:
但是這樣會發(fā)生錯誤。原因是:動態(tài)庫生成的.o文件是和位置無關(guān)的,而靜態(tài)庫是和位置有關(guān)的。所以當(dāng)靜態(tài)庫gcc時就會發(fā)生沖突,我們可以改一下名字。
運行一下:
4. 如何使用動靜態(tài)庫
4.1 使用靜態(tài)庫
看下面的例子:
我們可以來編譯一下:
你會發(fā)現(xiàn)找不到這個頭文件。原因是:頭文件的搜索有兩種路徑。一種是在當(dāng)前路徑下查找頭文件。一種是系統(tǒng)頭文件路徑下查找。
所以,我們可以把頭文件和庫文件拷貝到系統(tǒng)路徑下。
然后我們在去運行:
還是不行。原因是:我們以前是用的C/C++庫編譯器是認(rèn)識的,它會自動鏈接庫。而我們自己的庫編譯器不認(rèn)識,需要我們指定鏈接的第三方庫的名稱(gcc -l(指定鏈接的第三方庫的名稱))。
庫的名稱是去掉lib和后綴。
但是我們不建議這樣做,因為這樣會污染我們的系統(tǒng)的庫文件和頭文件。
我們可以自己指定路徑:
-I(大寫)的意思是:頭文件查找路徑
-L的意思是:庫文件搜索路徑
-l(小寫)的意思是:在-L指定的路徑下你要鏈接的是哪一個庫
4.2 使用動態(tài)庫
第一種方法也是一樣就是把這些拷貝到系統(tǒng)路徑下。
我們來看第二種方法:
為什么這里就不行了呢?原因是:這里的-I和-L的選項是作用于gcc的。這個gcc編譯器知道這個庫在哪里。但是當(dāng)我們可執(zhí)行程序運行的時候,它不知道庫在哪里。所以會報錯。
解決辦法:
第一種:通過導(dǎo)入環(huán)境變量的方式。當(dāng)程序運行時,會在環(huán)境變量中(LD_LIBRARY_PATH)查找自己需要的動態(tài)庫路徑。
具體步驟:
這是我們動態(tài)庫的絕對路徑。我們要把這個路徑倒進(jìn)環(huán)境變量中。
可以看到這個路徑已經(jīng)成功導(dǎo)入進(jìn)去了。此時,我們再去運行就是可以的。
但是這里也會有一個問題:就是當(dāng)我們把shell關(guān)閉重新打開,這個環(huán)境變量就會消失。我們需要在系統(tǒng)配置文件來做。
這些就是配置文件。當(dāng)系統(tǒng)讀我們自定義的動態(tài)庫時,除了會在lib64下去找,還會在這些配置文件里找。這里面的配置文件很簡單,就是我們的路徑。
我們在這里先創(chuàng)建一個測試文件,在這里需要提升一下權(quán)限。然后在這個文件中把我們路徑寫進(jìn)去。
但是此時你會發(fā)現(xiàn)我們的可執(zhí)行程序還是找不到動態(tài)庫:
這里的原因是:配置文件還沒有生效。我們需要激活一下。也就是讓系統(tǒng)把文件加載到內(nèi)存里。
這樣當(dāng)我們的shell關(guān)閉再打開也不會消失。
第二種:通過軟鏈接的方式。
此時,我們再去編譯就會方便許多:
我們就不需要去指定庫文件的路徑了。
此時我們找的就是軟鏈接。
那么為什么動態(tài)庫會出現(xiàn)這樣的問題呢?
這是進(jìn)程虛擬地址空間,棧是向下增長,堆是向上增長。但是棧和堆兩者之間是什么呢?
當(dāng)我們的可執(zhí)行程序加載到內(nèi)存運行時,有些代碼是需要跳轉(zhuǎn)到庫里運行。既然需要到庫里運行,那么我們就要將庫加載到內(nèi)存中。
既然我們的程序要去執(zhí)行庫的代碼,系統(tǒng)就會將庫通過頁表映射到堆棧之間。
這個區(qū)域就叫做:共享區(qū)。我們的進(jìn)程是先執(zhí)行自己的代碼,然后遇到庫的代碼就會去共享區(qū)里,運行完成后再回到代碼區(qū)。文章來源:http://www.zghlxwxcb.cn/news/detail-703413.html
所以,動態(tài)庫會出現(xiàn)這個情況。原因是:進(jìn)程運行時,如果要動態(tài)加載它所需要的庫。前提是需要先找到這個庫在哪里?而我們進(jìn)程在運行時它不知道。文章來源地址http://www.zghlxwxcb.cn/news/detail-703413.html
到了這里,關(guān)于動態(tài)庫和靜態(tài)庫的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!