亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

linux下有兩種庫(kù):動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)(共享庫(kù))

二者的不同點(diǎn)在于代碼被載入的時(shí)刻不同。

靜態(tài)庫(kù)的代碼在編譯過(guò)程中已經(jīng)被載入可執(zhí)行程序,因此體積比較大。

動(dòng)態(tài)庫(kù)(共享庫(kù))的代碼在可執(zhí)行程序運(yùn)行時(shí)才載入內(nèi)存,在編譯過(guò)程中僅簡(jiǎn)單的引用,因此代碼體積比較小。

不同的應(yīng)用程序如果調(diào)用相同的庫(kù),那么在內(nèi)存中只需要有一份該動(dòng)態(tài)庫(kù)(共享庫(kù))的實(shí)例。

靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)的最大區(qū)別,靜態(tài)情況下,把庫(kù)直接加載到程序中,而動(dòng)態(tài)庫(kù)鏈接的時(shí)候,它只是保留接口,將動(dòng)態(tài)庫(kù)與程序代碼獨(dú)立,這樣就可以提高代碼的可復(fù)用度,和降低程序的耦合度。

靜態(tài)庫(kù)在程序編譯時(shí)會(huì)被連接到目標(biāo)代碼中,程序運(yùn)行時(shí)將不再需要該靜態(tài)庫(kù)

動(dòng)態(tài)庫(kù)在程序編譯時(shí)并不會(huì)被連接到目標(biāo)代碼中,而是在程序運(yùn)行是才被載入,因此在程序運(yùn)行時(shí)還需要?jiǎng)討B(tài)庫(kù)存在

 

一 靜態(tài)庫(kù)

這類(lèi)庫(kù)的名字一般是libxxx.a;利用靜態(tài)函數(shù)庫(kù)編譯成的文件比較大,因?yàn)檎麄€(gè) 函數(shù)庫(kù)的所有數(shù)據(jù)都會(huì)被整合進(jìn)目標(biāo)代碼中,他的優(yōu)點(diǎn)就顯而易見(jiàn)了,即編譯后的執(zhí)行程序不需要外部的函數(shù)庫(kù)支持,因?yàn)樗惺褂玫暮瘮?shù)都已經(jīng)被編譯進(jìn)去了。當(dāng)然這也會(huì)成為他的缺點(diǎn),因?yàn)槿绻o態(tài)函數(shù)庫(kù)改變了,那么你的程序必須重新編譯。

靜態(tài)庫(kù)的代碼在編譯時(shí)鏈接到應(yīng)用程序中,因此編譯時(shí)庫(kù)文件必須存在,并且需要通過(guò)“-L”參數(shù)傳遞路徑給編譯器,應(yīng)用程序在開(kāi)始執(zhí)行時(shí),庫(kù)函數(shù)代碼將隨程序一起調(diào)入進(jìn)程內(nèi)存段直到進(jìn)程結(jié)束,其執(zhí)行過(guò)程不需要原靜態(tài)庫(kù)存在。

在UNIX中,使用ar命令創(chuàng)建或者操作靜態(tài)庫(kù)

ar archivefile objfile

archivefile:archivefile是靜態(tài)庫(kù)的名稱(chēng)

objfile:objfile是已.o為擴(kuò)展名的中間目標(biāo)文件名,可以多個(gè)并列

參數(shù) 意義

-r 將objfile文件插入靜態(tài)庫(kù)尾或者替換靜態(tài)庫(kù)中同名文件

-x 從靜態(tài)庫(kù)文件中抽取文件objfile

-t 打印靜態(tài)庫(kù)的成員文件列表

-d 從靜態(tài)庫(kù)中刪除文件objfile

-s 重置靜態(tài)庫(kù)文件索引

-v 創(chuàng)建文件冗余信息

-c 創(chuàng)建靜態(tài)庫(kù)文件

example:

/****************** hello.h **************/  
  void hello(void);  
/****************** hello.cpp **************/  
  #include<IOStream>  
#include"hello.h"  using namespace std;  void hello(void)  {            cout <<"Hello "<<endl;  
}  
/****************** main.cpp **************/  
  
#include"hello.h"  
  
int main(int argc,char *argv[])  
{          hello();          return 0;  }  

1.編譯成靜態(tài)庫(kù)

無(wú)論靜態(tài)庫(kù),還是動(dòng)態(tài)庫(kù),都是由.o文件創(chuàng)建的。因此,我們必須將源程序hello.c通過(guò)gcc先編譯成.o文件。

hc@linux-v07j:~/weiming/tt> g++ -o hello.o -c hello.cpp

hc@linux-v07j:~/weiming/tt> ar cqs libHello.a hello.o

hc@linux-v07j:~/weiming/tt> ls
hello.cpp hello.h hello.o libHello.a main.cpp

2.鏈接

hc@linux-v07j:~/weiming/tt> g++ main.cpp libHello.a -o Out1 (g++ -o aOut main.cpp ./libHello.a 或者 g++ -o aOut main.cpp -L./ -lHello)

注意:如果hello() 里面還使用了其他的庫(kù)函數(shù)比如pthread_create,則最后生成Out1 時(shí)還需 -lpthread,但ar 時(shí)可以不用,只需要在 include 的頭文件中找到函數(shù)符號(hào)聲明即可,但最終生成可執(zhí)行文件時(shí)需要找到所有的符號(hào)定義。

hc@linux-v07j:~/weiming/tt> ls
hello.cpp hello.h hello.o libHello.a main.cpp Out1

 

hc@linux-v07j:~/weiming/tt> ldd Out1
linux-gate.so.1 => (0xffffe000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e36000)
libm.so.6 => /lib/libm.so.6 (0xb7e11000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7e06000)
libc.so.6 => /lib/libc.so.6 (0xb7ce3000)
/lib/ld-linux.so.2 (0xb7f1b000)

 

二: 動(dòng)態(tài)庫(kù)

這類(lèi)庫(kù)的名字一般是libxxx.so;相對(duì)于靜態(tài)函數(shù)庫(kù),動(dòng)態(tài)函數(shù)庫(kù)在編譯的時(shí)候 并沒(méi)有被編譯進(jìn)目標(biāo)代碼中,你的程序執(zhí)行到相關(guān)函數(shù)時(shí)才調(diào)用該函數(shù)庫(kù)里的相應(yīng)函數(shù),因此動(dòng)態(tài)函數(shù)庫(kù)所產(chǎn)生的可執(zhí)行文件比較小。由于函數(shù)庫(kù)沒(méi)有被整合進(jìn)你的程序,而是程序運(yùn)行時(shí)動(dòng)態(tài)的申請(qǐng)并調(diào)用,所以程序的運(yùn)行環(huán)境中必須提供相應(yīng)的庫(kù)。動(dòng)態(tài)函數(shù)庫(kù)的改變并不影響你的程序,所以動(dòng)態(tài)函數(shù)庫(kù)的升級(jí)比較方便

不同的UNIX系統(tǒng),鏈接動(dòng)態(tài)庫(kù)方法,實(shí)現(xiàn)細(xì)節(jié)不一樣

 

編譯PIC型.o中間文件的方法一般是采用C語(yǔ)言編譯器的-KPIC或者-fpic選項(xiàng),有的UNIX版本C語(yǔ)言編譯器默認(rèn)帶上了PIC標(biāo)準(zhǔn).創(chuàng)建最終動(dòng)態(tài)庫(kù)的方法一般采用C語(yǔ)言編譯器的-G或者-shared選項(xiàng),或者直接使用工具ld創(chuàng)建。

最主要的是GCC命令行的一個(gè)選項(xiàng):
-shared 該選項(xiàng)指定生成動(dòng)態(tài)連接庫(kù)(讓連接器生成T類(lèi)型的導(dǎo)出符號(hào)表,有時(shí)候也生成弱連接W類(lèi)型的導(dǎo)出符號(hào)),不用該標(biāo)志外部程序無(wú)法連接。相當(dāng)于一個(gè)可執(zhí)行文件
-fPIC:表示編譯為位置獨(dú)立的代碼,不用此選項(xiàng)的話編譯后的代碼是位置相關(guān)的所以動(dòng)態(tài)載入時(shí)是通過(guò)代碼拷貝的方式來(lái)滿足不同進(jìn)程的需要,而不能達(dá)到真正代碼段共享的目的。(轉(zhuǎn)者注:共享庫(kù)各段的加載地址并沒(méi)有定死,可以加載到任意位置,因?yàn)橹噶钪袥](méi)有使用絕對(duì)地址(相對(duì)于鏈接后的可執(zhí)行文件各segment來(lái)說(shuō)),因此稱(chēng)為位置無(wú)關(guān)代碼)
-L.:表示要連接的庫(kù)在當(dāng)前目錄中
-ltest:編譯器查找動(dòng)態(tài)連接庫(kù)時(shí)有隱含的命名規(guī)則,即在給出的名字前面加上lib,后面加上.so來(lái)確定庫(kù)的名稱(chēng)

這里分別將源文件d1.c和d2.c編譯為動(dòng)態(tài)庫(kù)d1.so和d2.so.

/************ d1.h***************/  
void print();  
/***************  d1.cpp *******************/  
  #include <iostream>  
#include "d1.h"  using namespace std  int p = 1;  void print()    {        cout<< p <<endl;  
  
}  
/************ d2.h***************/  
void print();  
/***************  d2.cpp *******************/  
#include <iostream>  
#include "d2.h"  using namespace std;    int p = 2;  void print()  {      cout<< p <<endl;  
}  

LINUX和其他gcc編譯器

g++ -fpic -c d1.cpp d2.cpp /* 編譯為.o為擴(kuò)展名的中間目標(biāo)文件d1.o,d2.o*/

g++ -shared -o libd1.so d1.o /*根據(jù)中間目標(biāo)文件d1.o創(chuàng)建動(dòng)態(tài)庫(kù)文件d1.so*/

g++ -shared -o libd2.so d2.o /*根據(jù)中間目標(biāo)文件d2.o創(chuàng)建動(dòng)態(tài)庫(kù)文件d2.so*/

或者直接一步到位

g++ -O -fpic -shared -o libd1.so d1.cpp

g++ -O -fpic -shared -o libd2.so d2.cpp

某些版本的gcc上也可以使用-G替換-shared選項(xiàng)

 

調(diào)用動(dòng)態(tài)庫(kù)

隱式調(diào)用動(dòng)態(tài)庫(kù)

/**************  main.cpp *********************/  
  
void print(); //或者用#include"d1.h"(#include"d2.h")替換  
int main(int argc,char *argv[])  
{      print();  }  

#cp ./libd1.so libd.so (cp ./libd2.so libd.so )

# g++ -o dOut main.cpp ./libd.so (或者g++ -o dOut main.cpp -L./ -ld)

hc@linux-v07j:~/weiming/tt/dd> ldd dOut
linux-gate.so.1 => (0xffffe000)
libd.so => ./libd.so (0xb7f0f000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e2b000)
libm.so.6 => /lib/libm.so.6 (0xb7e06000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7dfa000)
libc.so.6 => /lib/libc.so.6 (0xb7cd8000)
/lib/ld-linux.so.2 (0xb7f12000)

 

ldd模擬運(yùn)行一遍main,在運(yùn)行過(guò)程中做動(dòng)態(tài)鏈接,從而得知這個(gè)可執(zhí)行文件依賴(lài)于哪些共享庫(kù),每個(gè)共享庫(kù)都在什么路徑下,加載到進(jìn)程地址空間的什么地址。

 

總之,共享庫(kù)的搜索路徑由動(dòng)態(tài)鏈接器決定,從ld.so(8)的Man Page可以查到共享庫(kù)路徑的搜索順序:

1. 首先在環(huán)境變量LD_LIBRARY_PATH所記錄的路徑中查找。

2. 在程序鏈接時(shí)指定的 rpath 中查找,可以 readelf binfile | grep RPATH 。

3. 然后從緩存文件/etc/ld.so.cache中查找。這個(gè)緩存文件由/sbin/ldconfig命令讀取配置文件/etc/ld.so.conf 之后生成。

(也可以在 ld.so.conf.d 目錄下增加 *.conf 文件,里面寫(xiě)入庫(kù)路徑,在 ld.so.conf 中 include ld.so.conf.d/*.conf )

Linux下動(dòng)態(tài)庫(kù)(.so)和靜態(tài)庫(kù)(.a) 的區(qū)別

 

4. 如果上述步驟都找不到,則到默認(rèn)的系統(tǒng)路徑中查找,先是/usr/lib然后是/lib。

不同的UNIX所依賴(lài)的動(dòng)態(tài)庫(kù)查找路徑環(huán)境變量名稱(chēng)各不相同

UNIX版本 動(dòng)態(tài)庫(kù)查找路徑環(huán)境變量

AIX LIB_PATH

LINUX LD_LIBRARY_PATH

HP_UNIX PAHT

SCO UNIX LD_LIBRARY_PATH

 

動(dòng)態(tài)鏈接庫(kù)取代靜態(tài)庫(kù)的好處之一就是可以隨時(shí)升級(jí)庫(kù)的內(nèi)容。

當(dāng)動(dòng)態(tài)庫(kù)被接口完全相同的庫(kù)文件取代后,可執(zhí)行程序能迅速的切換到新動(dòng)態(tài)庫(kù)中代碼,省去了編譯的麻煩。

 

顯式調(diào)用動(dòng)態(tài)庫(kù)

顯式調(diào)用動(dòng)態(tài)庫(kù),編譯時(shí)無(wú)需庫(kù)文件,執(zhí)行時(shí)動(dòng)態(tài)可存儲(chǔ)于任意位置,庫(kù)里共享對(duì)象必須先申請(qǐng)后使用,不同動(dòng)態(tài)庫(kù)版本,只要其共享對(duì)象接口相同,就可以直接動(dòng)態(tài)加載。注意添加 "-ldl" 編譯參數(shù)。

//打開(kāi)動(dòng)態(tài)庫(kù)  
#include<dlfcn.h>  
void *dlopen(const char * pathname,int mode);    //獲取動(dòng)態(tài)庫(kù)對(duì)象地址  include<dlfcn.h>  
void *dlsym(void *handle,const char *name);    //錯(cuò)誤檢測(cè)  include<dlfcn.h>  
char *dlerror(vid);    //關(guān)閉動(dòng)態(tài)庫(kù)  include<dlfcn.h>  
int dlclose(void * handle);  

動(dòng)態(tài)庫(kù)的加載或多或少會(huì)占用一定的系統(tǒng)資源,比如內(nèi)存等。因此當(dāng)不需要或者一段時(shí)間內(nèi)不需要共享動(dòng)態(tài)庫(kù)時(shí)就要卸載之。函數(shù)dlclose關(guān)閉參數(shù)handle所指向的動(dòng)態(tài)庫(kù),卸載其所占的內(nèi)存等資源,此調(diào)用后參數(shù)handle無(wú)效。

實(shí)際上,由于動(dòng)態(tài)庫(kù)可能同時(shí)被多個(gè)進(jìn)程共享,當(dāng)一個(gè)進(jìn)程指向dlclose時(shí),資源并不馬上被卸載,只有當(dāng)全部進(jìn)程都宣布關(guān)閉動(dòng)態(tài)庫(kù)后,操作系統(tǒng)才開(kāi)始回收動(dòng)態(tài)庫(kù)資源。

 

總結(jié):

編譯靜態(tài)庫(kù)時(shí)先使用-c選項(xiàng),再利用ar工具產(chǎn)生.編譯動(dòng)態(tài)庫(kù)的方式依不同版本的UNXI而定。隱式調(diào)用動(dòng)態(tài)庫(kù)與靜態(tài)庫(kù)的用法相一致,而顯示調(diào)用動(dòng)態(tài)庫(kù)則需要借助動(dòng)態(tài)加載共享庫(kù)函數(shù)族。

隱式調(diào)用動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)使用方法一致,使用靜態(tài)庫(kù)和使用動(dòng)態(tài)庫(kù)編譯成目標(biāo)程序使用的gcc命令完全一樣,那當(dāng)靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)同名時(shí),gcc命令會(huì)使用哪個(gè)庫(kù)文件呢?

通過(guò)測(cè)試可以發(fā)現(xiàn),當(dāng)靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)同名時(shí), gcc命令將優(yōu)先使用動(dòng)態(tài)庫(kù).為了確保使用的是靜態(tài)庫(kù), 編譯時(shí)可以加上 -static 選項(xiàng),因此多第三方程序?yàn)榱舜_保在沒(méi)有相應(yīng)動(dòng)態(tài)庫(kù)時(shí)運(yùn)行正常,喜歡在編譯最后應(yīng)用程序時(shí)加入-static

分享到:
標(biāo)簽:動(dòng)態(tài) Linux
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定