Other Linker Flags到底是用來干嘛的?
- 它是用來鏈接的, 一個(gè)程序從
代碼
到可執(zhí)行文件
往往要經(jīng)歷以下步驟:
源代碼 > 預(yù)處理器 > 編譯器 > 匯編器 > 機(jī)器碼 > 鏈接器 > 可執(zhí)行文件
為什么我們調(diào)用靜態(tài)庫
的方法時(shí)候會閃退
- selector not recognized
- 簡單來說枝嘶,因?yàn)閁NIX 靜態(tài)庫(.a文件) 與 OC 的動態(tài)機(jī)制不協(xié)調(diào)導(dǎo)致, 因?yàn)镺bjective-C的鏈接器并不會為
每個(gè)方法
建立符號表,而是僅僅為類
建立了符號表督赤。這樣的話檀轨,如果靜態(tài)庫中定義了已存在的一個(gè)類的分類射众,鏈接器就會以為這個(gè)類已經(jīng)存在,不會把分類和核心類
的代碼合起來吃粒。這樣的話闺金,在最后的可執(zhí)行文件中碉怔,就會缺少分類里的代碼烘贴,這樣函數(shù)調(diào)用就失敗了。
- 簡單來說枝嘶,因?yàn)閁NIX 靜態(tài)庫(.a文件) 與 OC 的動態(tài)機(jī)制不協(xié)調(diào)導(dǎo)致, 因?yàn)镺bjective-C的鏈接器并不會為
UNIX靜態(tài)庫及C程序鏈接過程:
當(dāng)一個(gè)C語言程序編譯時(shí)撮胧,所有源碼會編譯為對象文件桨踪,即.o文件(object file)。這些對象文件中包含了可執(zhí)行程序和靜態(tài)數(shù)據(jù)芹啥。鏈接器最終將所有文件組合到一起, 產(chǎn)生最終的可執(zhí)行文件锻离。
當(dāng)一個(gè)源文件
引用了定義在其他文件中
的一些東西時(shí)(一個(gè)方法)铺峭,一個(gè) undefined symbol 就寫入了它所產(chǎn)生的object 文件中,等待最終被解釋掉汽纠。在最終構(gòu)建可執(zhí)行文件的時(shí)卫键,鏈接器將包含這些undefined symbols的object文件中拉取信息, 解決掉被標(biāo)記的undefined symbols。
一個(gè)UNIX的靜態(tài)庫其實(shí)就是一系統(tǒng)object file的集合虱朵,一般情況下, 它只會拉取它需要的文件莉炉。好處是減小最終可執(zhí)行文件的大小。
舉個(gè)例子
比如main.c
使用一個(gè)函數(shù)碴犬,名叫foo( )
絮宁,而這個(gè)函數(shù)定義myMain.c里面。在生成.o文件
的時(shí)候服协,main.o
就會有一個(gè)foo( )
的undefined symbols
標(biāo)記绍昂。鏈接期間,myMain.o
便會被打入最終的可執(zhí)行文件中偿荷。但是窘游,假如還有一個(gè)heMain.c
文件,但是里面的函數(shù)沒被使用跳纳,那這個(gè)heMain.o
文件便不會出現(xiàn)最后的可執(zhí)行文件中张峰。
Objective-C鏈接過程有什么不同?
oc是動態(tài)性語言棒旗,對象方法的實(shí)現(xiàn)
只有到被調(diào)用
時(shí)候才被確定喘批。基于這個(gè)原因铣揉,Objective-C沒有方法級別
定義符號饶深,只有類級別
定義符號。
舉個(gè)例子
main.c中包含以下代碼: [[FooClass alloc] initWithBar:nil];
那么在鏈接的時(shí)候逛拱,main.o文件就會生成一個(gè)未定義符號如:(Undefined Symbols) FooClass
敌厘,但不會定義initWithBar方法
的符號。
坑在哪朽合?
Category只是一個(gè)類的分類
- 如果靜態(tài)庫中已經(jīng)定義這個(gè)類, 鏈接器就會認(rèn)為這個(gè)類已經(jīng)存在都鏈接過了, 還鏈接啥俱两。不會把
分類
和這個(gè)類
的代碼合起來, 所以會缺少分類里的代碼, 報(bào)錯(cuò)selector not recognized
- 如果靜態(tài)庫中沒有定義這個(gè)類的,Category只是一個(gè)方法的集合曹步,而Objective-C沒有
方法級別
定義符號宪彩。于所以連接器不會加載Cateogry生成的文件。
解決方法
在Other Linker Flags里加上所需的參數(shù)讲婚,用到的參數(shù)一般有以下3個(gè):
-ObjC
-all_load
-force_load
- 首先是-ObjC尿孔,連接器會把靜態(tài)庫中所有的Objective-C類和分類都加載到最后的可執(zhí)行文件中,雖然這樣可能會因?yàn)榧虞d了很多不必要的文件而導(dǎo)致可執(zhí)行文件變大
重要提示: 對于64位和iPhone OS應(yīng)用程序,當(dāng)靜態(tài)庫只包含類別活合,沒有類, 會存在一個(gè)鏈接器bug雏婶,它阻止-ObjC從靜態(tài)庫加載對象文件
- 再說說-all_load, 會讓鏈接器把所有找到的目標(biāo)文件都加載到可執(zhí)行文件中
重要提示: 假如你使用了不止一個(gè)靜態(tài)庫文件,那么很可能會遇到ld: duplicate symbol錯(cuò)誤白指,因?yàn)椴煌膸煳募锩婵赡軙邢嗤哪繕?biāo)文件
- 最后說說-force_load, 做的事跟-all_load一樣, 但是-force_load需要指定庫文件路徑留晚,這樣, 就只是完全加載了一個(gè)庫文件,不影響其余庫文件告嘲。