在實(shí)際軟件開(kāi)發(fā)中,軟件由許多文件組成,。不同操作系統(tǒng)下這些組成文件也不一樣,,本文總結(jié)在幾種操作系統(tǒng)(Windows,、linux、macOS)下軟件的庫(kù)文件,,也包含在實(shí)際項(xiàng)目開(kāi)發(fā)中,,所使用的庫(kù)文件。 一,、Windows下的庫(kù)在操作系統(tǒng)下,,一個(gè)庫(kù)從源代碼經(jīng)編譯套件編譯構(gòu)建后,會(huì)生成對(duì)應(yīng)的庫(kù),。這個(gè)庫(kù)由:bin,、include、lib等目錄中的文件來(lái)描述,。當(dāng)然不同的編譯構(gòu)建套件所生成的庫(kù)的組成有所不同,。 在Windows操作系統(tǒng)下,主要有以下兩種: (1)*.lib 可由MSVC編譯構(gòu)建套件編譯生成,。 (2)lib*.a 可由MinGW編譯套件(Gcc系的編譯套件)構(gòu)建生成,。 在生成Windows下的可執(zhí)行程序(exe)時(shí)有兩種鏈接方式: (1)動(dòng)態(tài)鏈接:允許可執(zhí)行模塊(.dll文件或.exe文件)僅包含在運(yùn)行時(shí)定位dll函數(shù)的可執(zhí)行代碼所需的信息。 (2)靜態(tài)鏈接:鏈接器從靜態(tài)鏈接庫(kù)lib獲取所有被引用的函數(shù),,并將庫(kù)同代碼一起放到可執(zhí)行文件中,。 (1-1)、lib和dll的區(qū)別(1)lib是在我們編譯的時(shí)候用到的,,dll是程序運(yùn)行的時(shí)候用到的,。如果要完成源代碼的編譯,只需要lib,;如果要使動(dòng)態(tài)鏈接的程序運(yùn)行起來(lái),,只需要dll,不必需要lib,。 (2)如果有dll文件,,那么lib一般包含一些索引信息,記錄dll中函數(shù)的入口和位置,,dll中是函數(shù)的具體內(nèi)容,;如果只有l(wèi)ib文件,那么這個(gè)lib文件是靜態(tài)編譯出來(lái)的,,索引和實(shí)現(xiàn)都在對(duì)應(yīng)文件中,。使用靜態(tài)編譯的lib文件,在運(yùn)行程序時(shí)不需要?jiǎng)討B(tài)庫(kù)了,,缺點(diǎn)是導(dǎo)致應(yīng)用程序本體比較大,,而且失去了動(dòng)態(tài)庫(kù)的靈活性,在我們需要重新發(fā)布新版本時(shí)要發(fā)布新的應(yīng)用程序才行。 (3)在動(dòng)態(tài)鏈接的情況下,,有兩種文件:一個(gè)是lib文件,,一個(gè)是dll文件。lib包含被dll導(dǎo)出的函數(shù)名稱和位置,,dll包含實(shí)際的函數(shù)和數(shù)據(jù),,應(yīng)用程序使用lib文件鏈接到dll文件。在應(yīng)用程序的可執(zhí)行文件中,,存放的不是被調(diào)用的函數(shù)代碼,,而是dll中相應(yīng)函數(shù)代碼的對(duì)應(yīng)地址,從而節(jié)省了內(nèi)存資源,。dll和lib文件必須隨應(yīng)用程序一起發(fā)行,,否則應(yīng)用程序運(yùn)行時(shí)會(huì)產(chǎn)生錯(cuò)誤,如下圖所示,。 如果不想用lib文件或者沒(méi)有l(wèi)ib文件,,可以用WIN32 API函數(shù)LoadLibrary、GetProcAddress進(jìn)行裝載,。 (1-2),、如何使用已經(jīng)存在的庫(kù)?應(yīng)該在我們的項(xiàng)目中包含我們需要使用的庫(kù)的頭文件(.h),,并指定我們所需要鏈接的庫(kù)文件(.lib),。如果是動(dòng)態(tài)鏈接,還需要將生成的可執(zhí)行軟件(exe)放到我們所使用的庫(kù)的動(dòng)態(tài)鏈接庫(kù)(dll)目錄下,。 例如,,我們?cè)赒tCreator中進(jìn)行開(kāi)發(fā)時(shí),可以使用: DESTDIR:指明鏈接生成的可執(zhí)行文件的目錄,。(這個(gè)目錄最好是一個(gè)包含完整的dll的目錄路徑) INCLUDEPATH:指定庫(kù)的頭文件包含路徑,。 LIBS:指定在鏈接中,所使用的庫(kù),。如果沒(méi)有指定,,一般會(huì)報(bào)類似如下的錯(cuò)誤: (1-3)、應(yīng)用程序的可執(zhí)行文件是如何找到dll文件的呢,?在許多軟件開(kāi)發(fā)工具中,,例如Qt,可以指定dll文件的完整搜索路徑,;如果不指定路徑,,或者在鏈接可執(zhí)行文件時(shí)進(jìn)行了隱式鏈接,Windows將遵循下面的搜索順序來(lái)定位dll: (1)包含exe文件的目錄,。 (2)工程目錄。 (3)Windows操作系統(tǒng)的系統(tǒng)目錄。 (4)列在Path環(huán)境變量中的目錄,。 (1-4)查看依賴推薦兩種方式: (1)使用dumpbinVS命令行工具查看依賴,。 (2)使用Depends.exe查看程序依賴庫(kù)。 二,、linux下的庫(kù)在linux平臺(tái)下,,庫(kù)主要有以下兩種: (1)lib*.so :動(dòng)態(tài)庫(kù) (2)lib*.a : 靜態(tài)庫(kù) 在linux系統(tǒng)下,為了理解擴(kuò)展名為.a,、.so和.la的文件庫(kù)的實(shí)際含義,,我們首先必須了解Linux中的庫(kù)的概念。簡(jiǎn)單地說(shuō),,Linux是一組預(yù)編譯的代碼片段的集合,,這些代碼片段被稱為函數(shù)。庫(kù)非常有用,,它們提供了可重用的函數(shù),、類和數(shù)據(jù)結(jié)構(gòu)。Linux中的一些庫(kù)示例有g(shù)libc(標(biāo)準(zhǔn)C庫(kù)的GNU版本)和libc (C標(biāo)準(zhǔn)庫(kù))等,。 總的來(lái)說(shuō),,可以將Linux中的庫(kù)分為兩類: (2-1)靜態(tài)庫(kù)在編譯時(shí)鏈接到程序中的庫(kù)稱為靜態(tài)庫(kù)。它們也被稱為靜態(tài)鏈接庫(kù),,由一組例程,、外部函數(shù)和變量組成。在編譯時(shí)鏈接到一個(gè)程序之后,,它被鏈接器,、綁定器或編譯器復(fù)制到目標(biāo)應(yīng)用程序,然后生成一個(gè)目標(biāo)文件和一個(gè)獨(dú)立的可執(zhí)行文件,。 靜態(tài)庫(kù)有一個(gè)擴(kuò)展名.a,,其中的.a代表“存檔”。 靜態(tài)庫(kù)的缺點(diǎn)是:比動(dòng)態(tài)庫(kù)更快,,因?yàn)橥ǔJ褂玫囊唤M目標(biāo)文件被放在一個(gè)可執(zhí)行文件中,。 靜態(tài)庫(kù)的優(yōu)點(diǎn)是:用于構(gòu)建它的代碼被鎖定在最終的可執(zhí)行文件中,并且在不重新編譯庫(kù)的情況下無(wú)法修改它,。 (2-2)動(dòng)態(tài)庫(kù)作為獨(dú)立文件存在于可執(zhí)行文件之外的庫(kù)被稱為動(dòng)態(tài)庫(kù),。在編譯時(shí),程序生成庫(kù)文件的一個(gè)副本,。 擴(kuò)展名為.so的文件代表動(dòng)態(tài)庫(kù),。 動(dòng)態(tài)庫(kù)的優(yōu)點(diǎn)是:?jiǎn)蝹€(gè)庫(kù)可以被多個(gè)應(yīng)用程序使用,而不需要每個(gè)應(yīng)用程序都像使用靜態(tài)庫(kù)那樣擁有自己的庫(kù)副本,。 動(dòng)態(tài)庫(kù)的缺點(diǎn)是:與靜態(tài)庫(kù)相比,,庫(kù)被破壞的可能性要高得多。一個(gè)非常簡(jiǎn)單情況就是:如果一個(gè)動(dòng)態(tài)庫(kù)文件損壞,可執(zhí)行文件可能會(huì)無(wú)法啟動(dòng)運(yùn)行,。 (2-3).la 文件擴(kuò)展名為.la的文件不是庫(kù),,但實(shí)際上它們是包含庫(kù)描述的文本文件。它們由GNU“l(fā)ibtools”包生成,,用于描述組成相應(yīng)庫(kù)的文件,。 (2-4)運(yùn)行時(shí)加載庫(kù)文件
由于靜態(tài)庫(kù)在程序編譯時(shí)會(huì)被鏈接到目標(biāo)代碼中,程序運(yùn)行時(shí)將不再需要該靜態(tài)庫(kù),。
(1)將so文件拷貝安裝到/lib或/usr/lib目錄下, 并執(zhí)行l(wèi)dconfig命令,。 (2)如果將庫(kù)文件安裝到非/lib或/usr/lib目錄下, 那么在執(zhí)行l(wèi)dconfig命令前, 還要把新共享庫(kù)目錄加入到共享庫(kù)配置文件/etc/ld.so.conf中。 (3)如果將庫(kù)文件安裝到非/lib或/usr/lib目錄下, 并且我們不想在/etc/ld.so.conf中加路徑(或者是沒(méi)有權(quán)限加路徑),。這時(shí)候,,我們那可以export一個(gè)全局變量LD_LIBRARY_PATH,并指定完整的庫(kù)路徑,。在運(yùn)行程序的時(shí)候就會(huì)去這個(gè)目錄中找共享庫(kù),,可以設(shè)置多個(gè)搜索目錄, 這些目錄之間使用冒號(hào)分隔開(kāi)。 export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH (注意)在linux系統(tǒng)下,,有一點(diǎn)與Windows不同:動(dòng)態(tài)庫(kù)與可執(zhí)行文件放在同一目錄下是找不到動(dòng)態(tài)庫(kù)的,。 ldconfig命令的作用主要是:在默認(rèn)搜尋目錄/lib和/usr/lib以及動(dòng)態(tài)庫(kù)配置文件/etc/ld.so.conf內(nèi)所列的目錄下,搜索出可共享的動(dòng)態(tài)鏈接庫(kù),進(jìn)而創(chuàng)建出動(dòng)態(tài)裝入程序(ld.so)所需的鏈接和緩存文件,。 緩存文件默認(rèn)為/etc/ld.so.cache,,此文件保存已排好序的動(dòng)態(tài)鏈接庫(kù)名字列表,為了讓動(dòng)態(tài)鏈接庫(kù)為系統(tǒng)所共享,,需運(yùn)行動(dòng)態(tài)鏈接庫(kù)的管理命令ldconfig,,此執(zhí)行程序存放在/sbin目錄下。 ldconfig通常在系統(tǒng)啟動(dòng)時(shí)運(yùn)行,,當(dāng)我們安裝了一個(gè)新的動(dòng)態(tài)鏈接庫(kù)時(shí),,就需要手動(dòng)運(yùn)行這個(gè)命令。 (2-5)依賴查看使用ldd命令查看可執(zhí)行文件依賴的庫(kù)文件,。例如下圖: 三,、macOS下的庫(kù)在macOS平臺(tái)下,庫(kù)主要有以下三種: (1)*dylib 在macOS系操作系統(tǒng)中,,*dylib為動(dòng)態(tài)庫(kù)的存在形式,。 (2)*.a *a是靜態(tài)庫(kù)的存在形式。 (3)*.framework 對(duì)于*.framework文件來(lái)說(shuō),,可以是靜態(tài)的,,也可以是動(dòng)態(tài)的。 (3-1)macOS下靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)的區(qū)別.a 文件肯定是靜態(tài)庫(kù), .dylib 肯定是動(dòng)態(tài)庫(kù), .framework 可能是靜態(tài)庫(kù)也可能是動(dòng)態(tài)庫(kù),。 靜態(tài)庫(kù)在鏈接時(shí), 會(huì)被完整的鏈接到可執(zhí)行文件中, 如果多個(gè)APP都使用了同一個(gè)靜態(tài)庫(kù), 那么每個(gè)APP都會(huì)拷貝一份, 這樣做,,缺點(diǎn)就是占用很多的內(nèi)存空間,。 動(dòng)態(tài)庫(kù)不會(huì)復(fù)制,只有一份, 程序運(yùn)行時(shí)會(huì)被動(dòng)態(tài)加載到內(nèi)存中, 且系統(tǒng)只會(huì)加載一次, 多個(gè)程序公用一份, 因此節(jié)約了內(nèi)存空間,。但是如果在項(xiàng)目中使用了自己定義的動(dòng)態(tài)庫(kù), 蘋果是不允許上架的, 在 iOS8 后 蘋果開(kāi)放了動(dòng)態(tài)加載 .dylib 的接口, 可用于掛載 .dylib 動(dòng)態(tài)庫(kù),。 |
|