靜態(tài)庫與動(dòng)態(tài)庫的思考

前言

在上文《編譯與鏈接過程的思考》評(píng)論中暴走大牙提到了靜態(tài)庫和動(dòng)態(tài)庫依賴的問題抱环,還在群里提了幾個(gè)測試樣例和測試工程范抓。
大致介紹下測試工程和如何進(jìn)行測試:
工程P為主工程腔彰,其中有4個(gè)子工程A沿癞、B等缀、C、D臣嚣,子工程打包的庫為動(dòng)態(tài)庫或靜態(tài)庫净刮,子工程之間存在依賴關(guān)系。
通過修改主工程的依賴庫硅则,以及子工程的依賴關(guān)系以及打包類型淹父,測試動(dòng)態(tài)庫依賴靜態(tài)庫靜態(tài)庫依賴動(dòng)態(tài)庫怎虫、靜態(tài)庫依賴靜態(tài)庫的情況暑认。

正文

在測試之前,先簡單說明下靜態(tài)庫和動(dòng)態(tài)庫的打包方式

  • Cocoa Touch Framework
  • Mach-O Type 為 Static
    打包的.framework文件為靜態(tài)庫
  • Mach-O Type 為 Dynamic
    打包的.framework文件為動(dòng)態(tài)庫
  • Cocoa Touch Static Library
    打包的.a文件為靜態(tài)庫

靜態(tài)庫依賴靜態(tài)庫

測試環(huán)境
靜態(tài)庫A大审、B蘸际、C均采用Cocoa Touch Framework的打包方式。

  • 靜態(tài)庫A:提供函數(shù)foo();
  • 靜態(tài)庫B:提供函數(shù)call_foo_b(); 依賴靜態(tài)庫A徒扶,在call_foo_b中調(diào)用foo();
  • 靜態(tài)庫C:提供函數(shù)foo()粮彤;


測試代碼

#include "BLib.h"
#include "CLib.h"

- (void)testLib {
    NSLog(@"Test A.");
    call_foo_b();
    
    NSLog(@"Test B.");
    foo();
}

測試結(jié)果

2016-12-20 09:54:12.931731 testLib[7671:4787567] Test A.
call_foo in BLib.
foo in ALib.
2016-12-20 09:54:12.931925 testLib[7671:4787567] Test B.
foo in ALib.

  • 對于TestA,我們調(diào)用B的call_foo_b,然后在call_foo_b中又調(diào)用A的foo导坟,打印的調(diào)用順序?yàn)锽->A屿良,正常;
  • 對于TestB惫周,我們引入C的頭文件尘惧,然后調(diào)用C的foo,打印的調(diào)用順序是A闯两,異常褥伴;

結(jié)果思考??
靜態(tài)庫的生成只有編譯,沒有鏈接漾狼;
當(dāng)工程同時(shí)存在庫A和C時(shí)重慢,兩個(gè)foo的函數(shù)符號(hào)在鏈接的時(shí)候,先引入者優(yōu)先逊躁;

驗(yàn)證:把工程依賴順序從ABC改成CBA之后似踱,結(jié)果輸出變?yōu)?br> 2016-12-20 10:19:28.613791 testLib[7691:4795943] Test A.
call_foo in BLib.
foo in CLib.
2016-12-20 10:19:28.613871 testLib[7691:4795943] Test B.
foo in CLib.

靜態(tài)庫依賴動(dòng)態(tài)庫

測試環(huán)境
庫A、B稽煤、C核芽、D均采用Cocoa Touch Framework的打包方式。

  • 動(dòng)態(tài)庫A:提供函數(shù)foo();
  • 靜態(tài)庫B:提供函數(shù)call_foo_b(); 依賴動(dòng)態(tài)庫A酵熙,在call_foo_b中調(diào)用foo();
  • 動(dòng)態(tài)庫C:提供函數(shù)foo()轧简;
  • 靜態(tài)庫D:提供函數(shù)call_foo_d(); 依賴動(dòng)態(tài)庫C,在call_foo_d中調(diào)用foo();


測試代碼

#include "BLib.h"
#include "DLib.h"

- (void)testLib {
    NSLog(@"Test lib.");
    call_foo_b();
    call_foo_d();
}

測試結(jié)果

2016-12-20 10:36:09.389209 testLib[7707:4799800] Test lib.
call_foo in BLib.
foo in ALib.
call_foo in DLib.
foo in ALib.

  • 對于第一組測試匾二,我們調(diào)用靜態(tài)庫B的函數(shù)call_foo_b哮独,在函數(shù)call_foo_b中調(diào)用動(dòng)態(tài)庫A的函數(shù),正常察藐;
  • 對于第二組測試皮璧,我們調(diào)用靜態(tài)庫D的函數(shù)call_foo_d,在函數(shù)call_foo_d中調(diào)用動(dòng)態(tài)庫A的函數(shù)分飞,異常悴务;(預(yù)想中是調(diào)用動(dòng)態(tài)庫C的函數(shù))

結(jié)果思考??
靜態(tài)庫的生成只有編譯,沒有鏈接譬猫;
那么在靜態(tài)庫D生成的過程中讯檐,只是確定了靜態(tài)庫D需要用到動(dòng)態(tài)庫中的foo函數(shù);
當(dāng)運(yùn)行時(shí)染服,加載了動(dòng)態(tài)庫A裂垦、C,其中兩個(gè)庫均含有foo函數(shù)肌索;動(dòng)態(tài)鏈接器,按照加載的順序,取到動(dòng)態(tài)庫A中的foo函數(shù)诚亚;
所以靜態(tài)庫B晕换、D調(diào)用的foo函數(shù)均是動(dòng)態(tài)庫A中的foo函數(shù)。

驗(yàn)證:我們調(diào)換Link Binary With Libraries 中A和C的位置站宗,結(jié)果如下
2016-12-20 10:35:11.048034 testLib[7705:4799491] Test lib.
call_foo in BLib.
foo in CLib.
call_foo in DLib.
foo in CLib.

動(dòng)態(tài)庫依賴靜態(tài)庫

測試環(huán)境
庫A闸准、B、C梢灭、D均采用Cocoa Touch Framework的打包方式夷家。

  • 靜態(tài)庫A:提供函數(shù)foo();
  • 動(dòng)態(tài)庫B:提供函數(shù)call_foo_b(); 依賴靜態(tài)庫A,在call_foo_b中調(diào)用foo();
  • 靜態(tài)庫C:提供函數(shù)foo()敏释;
  • 動(dòng)態(tài)庫D:提供函數(shù)call_foo_d(); 依賴靜態(tài)庫C库快,在call_foo_d中調(diào)用foo();


測試代碼

#include "BLib.h"
#include "DLib.h"

- (void)testLib {
    NSLog(@"Test lib.");
    call_foo_b();
    call_foo_d();
}

測試結(jié)果

2016-12-20 11:08:52.715415 testLib[7746:4810080] Test lib.
call_foo in BLib.
foo in ALib.
call_foo in DLib.
foo in CLib.

  • 對于第一組測試,我們調(diào)用動(dòng)態(tài)庫B的函數(shù)call_foo_b钥顽,在函數(shù)call_foo_b中調(diào)用靜態(tài)庫A的函數(shù)义屏,正常
  • 對于第二組測試蜂大,我們調(diào)用動(dòng)態(tài)庫D的函數(shù)call_foo_d闽铐,在函數(shù)call_foo_d中調(diào)用靜態(tài)庫C的函數(shù),正常奶浦;

結(jié)果思考??
工程依賴?yán)锩嬷挥袆?dòng)態(tài)庫B兄墅、D,沒有靜態(tài)庫A澳叉、C隙咸;
靜態(tài)庫A、C同名函數(shù)foo沒有沖突耳高;
這兩個(gè)現(xiàn)象是原因是動(dòng)態(tài)庫在生成的過程中扎瓶,除了編譯還有鏈接的過程。如果動(dòng)態(tài)庫依賴靜態(tài)庫泌枪,在生成動(dòng)態(tài)庫時(shí)會(huì)將靜態(tài)庫的代碼合并到動(dòng)態(tài)庫中概荷。

擴(kuò)展
如果動(dòng)態(tài)庫B、D的函數(shù)名字使用一樣的call_foo碌燕,調(diào)用順序和Link Binary With Libraries相關(guān)误证,與embeded的順序無關(guān);(embeded只是把動(dòng)態(tài)庫放入bundle中修壕,關(guān)鍵在于鏈接器的順序)

動(dòng)態(tài)庫依賴動(dòng)態(tài)庫

測試環(huán)境
動(dòng)態(tài)庫A愈捅、B、C慈鸠、D均采用Cocoa Touch Framework的打包方式蓝谨。

  • 動(dòng)態(tài)庫A:提供函數(shù)foo();
  • 動(dòng)態(tài)庫B:提供函數(shù)call_foo_b(); 依賴動(dòng)態(tài)庫A,在call_foo_b中調(diào)用foo();
  • 動(dòng)態(tài)庫C:提供函數(shù)foo();
  • 動(dòng)態(tài)庫D:提供函數(shù)call_foo_d(); 依賴動(dòng)態(tài)庫C譬巫,在call_foo_d中調(diào)用foo();


測試代碼

#include "BLib.h"
#include "DLib.h"

- (void)testLib {
    NSLog(@"Test lib.");
    call_foo_b();
    call_foo_d();
}

測試結(jié)果

2016-12-20 11:08:52.715415 testLib[7746:4810080] Test lib.
call_foo in BLib.
foo in ALib.
call_foo in DLib.
foo in CLib.

  • 對于第一組測試咖楣,我們調(diào)用動(dòng)態(tài)庫B的函數(shù)call_foo_b,在函數(shù)call_foo_b中調(diào)用動(dòng)態(tài)庫A的foo函數(shù)芦昔,正常诱贿;
  • 對于第二組測試,我們調(diào)用動(dòng)態(tài)庫D的函數(shù)call_foo_d咕缎,在函數(shù)call_foo_d中調(diào)用動(dòng)態(tài)庫C的foo函數(shù)珠十,正常

結(jié)果思考??
四個(gè)動(dòng)態(tài)庫都需要Link和Embeded凭豪;
與靜態(tài)庫依賴動(dòng)態(tài)庫的測試樣例不同焙蹭,這次雖然動(dòng)態(tài)庫A、C存在同名函數(shù)foo墅诡,但是調(diào)用的時(shí)候沒有沖突壳嚎。
動(dòng)態(tài)庫依賴動(dòng)態(tài)庫,在生成動(dòng)態(tài)庫的時(shí)候不會(huì)把依賴的動(dòng)態(tài)庫合并到動(dòng)態(tài)庫中末早。

總結(jié)

靜態(tài)庫的生成只有編譯烟馅,沒有鏈接;
動(dòng)態(tài)庫的生成除了編譯還有鏈接的過程然磷;
如果動(dòng)態(tài)庫依賴靜態(tài)庫郑趁,在生成動(dòng)態(tài)庫時(shí)會(huì)將靜態(tài)庫的代碼合并到動(dòng)態(tài)庫中;

  • 靜態(tài)庫A依賴靜態(tài)庫B姿搜,使用時(shí)需要在Link Binary With Libraries引入靜態(tài)庫A寡润、B;
  • 靜態(tài)庫A依賴動(dòng)態(tài)庫B舅柜,使用時(shí)需要在Link Binary With Libraries引入靜態(tài)庫A和動(dòng)態(tài)庫B梭纹,并且在Embeded Binaries引入動(dòng)態(tài)庫B;
  • 動(dòng)態(tài)庫A依賴靜態(tài)庫B致份,使用時(shí)需要在Link Binary With Libraries引入動(dòng)態(tài)庫A变抽,并且在Embeded Binaries引入動(dòng)態(tài)庫A;
  • 動(dòng)態(tài)庫A依賴動(dòng)態(tài)庫B氮块,使用時(shí)需要在Link Binary With Libraries引入動(dòng)態(tài)庫A和B绍载,并且在Embeded Binaries引入動(dòng)態(tài)庫A和B;

所有的代碼都可以在這里找到滔蝉。

擴(kuò)展--Cocoa Touch Static Library的打包

Cocoa Touch Static Library打包出來的是.a格式的靜態(tài)庫击儡,會(huì)把Link Binary With Libraries里面的靜態(tài)庫一起打包到.a靜態(tài)庫中,測試工程點(diǎn)我蝠引。

如何打包一個(gè)靜態(tài)庫阳谍,但是不包含其中的依賴庫文件蛀柴?

引入依賴庫頭文件即可,因?yàn)殪o態(tài)庫只編譯不鏈接边坤。(但是如果Cocoa Touch Static Library 里面填入了第三方的靜態(tài)庫名扛,會(huì)自動(dòng)打包)

.a和.framework都是靜態(tài)庫格式,只是.framework格式包括了靜態(tài)庫文件茧痒、頭文件、資源文件融蹂,故而更容易使用旺订。

如何直接使用.a靜態(tài)庫,不要靜態(tài)庫的頭文件超燃?

Link Binary With Libraries中添加.a靜態(tài)庫区拳;
在使用靜態(tài)庫的函數(shù)前添加聲明,但是不定義實(shí)現(xiàn)意乓;

這樣編譯時(shí)樱调,會(huì)根據(jù)聲明在全局查找定義;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末届良,一起剝皮案震驚了整個(gè)濱河市笆凌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌士葫,老刑警劉巖乞而,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異慢显,居然都是意外死亡爪模,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門荚藻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屋灌,“玉大人,你說我怎么就攤上這事应狱」补” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵侦香,是天一觀的道長落塑。 經(jīng)常有香客問我,道長罐韩,這世上最難降的妖魔是什么憾赁? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮散吵,結(jié)果婚禮上龙考,老公的妹妹穿的比我還像新娘蟆肆。我一直安慰自己,他們只是感情好晦款,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布炎功。 她就那樣靜靜地躺著,像睡著了一般缓溅。 火紅的嫁衣襯著肌膚如雪蛇损。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天坛怪,我揣著相機(jī)與錄音淤齐,去河邊找鬼。 笑死袜匿,一個(gè)胖子當(dāng)著我的面吹牛更啄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播居灯,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼祭务,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怪嫌?” 一聲冷哼從身側(cè)響起义锥,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎喇勋,沒想到半個(gè)月后缨该,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡川背,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年贰拿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片熄云。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膨更,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缴允,到底是詐尸還是另有隱情荚守,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布练般,位于F島的核電站矗漾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏薄料。R本人自食惡果不足惜敞贡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望摄职。 院中可真熱鬧誊役,春花似錦获列、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鹏漆,卻和暖如春巩梢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背艺玲。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工且改, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人板驳。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像碍拆,于是被迫代替她去往敵國和親若治。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容