iOS:靜態(tài)庫(kù)和dead code strip

1.前沿

.a:常見的靜態(tài)庫(kù)文件格式
.dylib:傳統(tǒng)意義上的動(dòng)態(tài)庫(kù)文件格式
.framework:可以是靜態(tài)庫(kù)也可以是動(dòng)態(tài)庫(kù)。
.xcframework:剛推出方妖,不同架構(gòu)庫(kù)放到一塊狭魂。

什么是庫(kù)
庫(kù)(Library)說(shuō)白了就是一段編譯好的二進(jìn)制代碼,加上頭文件就可以供別 人使用党觅。
什么時(shí)候會(huì)用到庫(kù)(Library)?

  1. 某些代碼需要給別人使用雌澄,但是我們不希望別人看到源碼,就需要以
    庫(kù)的形式進(jìn)行封裝杯瞻,只暴露出頭文件镐牺。
  2. 對(duì)于某些不會(huì)進(jìn)行大的改動(dòng)的代碼,我們想減少編譯的時(shí)間又兵,就可以 把它打包成庫(kù)任柜,因?yàn)閹?kù)是已經(jīng)編譯好的二進(jìn)制了,編譯的時(shí)候只需 要 Link 一下沛厨,不會(huì)浪費(fèi)編譯時(shí)間宙地。
    什么是鏈接(Link)?
    庫(kù)在使用的時(shí)候需要鏈接(Link),
    鏈接 的方式有兩種:
  3. 靜態(tài)
  4. 動(dòng)態(tài)
    什么是靜態(tài)庫(kù)?
    靜態(tài)庫(kù)即靜態(tài)鏈接庫(kù):可以簡(jiǎn)單的看成一組目標(biāo)文件的集合逆皮。即很多目 標(biāo)文件經(jīng)過壓縮打包后形成的文件宅粥。Windows 下的 .lib,Linux 和 Mac 下的 .a电谣。Mac獨(dú)有的.framework秽梅。
    缺點(diǎn):
    浪費(fèi)內(nèi)存和磁盤空間,模塊更新困難
    什么是動(dòng)態(tài)庫(kù)?
    與靜態(tài)庫(kù)相反剿牺,動(dòng)態(tài)庫(kù)在編譯時(shí)并不會(huì)被拷?到目標(biāo)程序中企垦,目標(biāo)程序 中只會(huì)存儲(chǔ)指向動(dòng)態(tài)庫(kù)的引用。等到程序運(yùn)行時(shí)晒来,動(dòng)態(tài)庫(kù)才會(huì)被真正加 載進(jìn)來(lái)钞诡。格式有:.framework、.dylib、.tdb荧降。
    缺點(diǎn):
    會(huì)導(dǎo)致一些性能損失接箫。但是可以優(yōu)化,比如延遲綁定(Lazy Binding)技術(shù)
    什么是tdb格式?
    tbd全稱是text-based stub libraries朵诫,本質(zhì)上就是一個(gè)YAML描述的文本文
    件辛友。
    他的作用是用于記錄動(dòng)態(tài)庫(kù)的一些信息,包括導(dǎo)出的符號(hào)剪返、動(dòng)態(tài)庫(kù)的架構(gòu)信息废累、動(dòng)
    態(tài)庫(kù)的依賴信息
    用于避免在真機(jī)開發(fā)過程中直接使用傳統(tǒng)的dylib。
    對(duì)于真機(jī)來(lái)說(shuō)随夸,由于動(dòng)態(tài)庫(kù)都是在設(shè)備上九默,在Xcode上使用基于tbd格式的偽 framework可以大大減少Xcode的大小。
    Framework
    Mac OS/iOS 平臺(tái)還可以使用 Framework宾毒。Framework 實(shí)際上是一種打包 方式驼修,將庫(kù)的二進(jìn)制文件,頭文件和有關(guān)的資源文件打包到一起诈铛,方便管 理和分發(fā)乙各。
    Framework 和系統(tǒng)的 UIKit.Framework 還是有很大區(qū)別。系統(tǒng)的 Framework 不需要拷?到目標(biāo)程序中幢竹,我們自己做出來(lái)的 Framework 哪怕 是動(dòng)態(tài)的耳峦,最后也還是要拷?到 App 中(App 和 Extension 的 Bundle 是 共享的),因此蘋果又把這種 Framework 稱為 Embedded Framework
    Embedded Framework
    開發(fā)中使用的動(dòng)態(tài)庫(kù)會(huì)被放入到ipa下的framework目錄下焕毫,基于沙盒運(yùn)行蹲坷。
    不同的App使用相同的動(dòng)態(tài)庫(kù),并不會(huì)只在系統(tǒng)中存在一份邑飒。而是會(huì)在多 個(gè)App中各自打包循签、簽名、加載一份疙咸。

2.鏈接靜態(tài)庫(kù)生成目標(biāo)文件

2.1.創(chuàng)建一個(gè)靜態(tài)庫(kù)

創(chuàng)建一個(gè)靜態(tài)庫(kù)县匠,里面有一個(gè)oc類ReplaceAFNetWorking,編譯后里面兩個(gè)文件撒轮,一個(gè)是libReplaceAFNetWorking.a一個(gè)是頭文件ReplaceAFNetWorking.h
查看.a文件到底是什么

file libReplaceAFNetWorking.a
// libReplaceAFNetWorking.a: current ar archive random library

2.2查看.a文件的內(nèi)容

我們查看a文件的內(nèi)容乞旦,需要使用ar命令
查看ar命令作用 man ar

  ar -- create and maintain library archives

SYNOPSIS
     ar -d [-TLsv] archive file ...
     ar -m [-TLsv] archive file ...
     ar -m [-abiTLsv] position archive file ...
     ar -p [-TLsv] archive [file ...]
     ar -q [-cTLsv] archive file ...
     ar -r [-cuTLsv] archive file ...
     ar -r [-abciuTLsv] position archive file ...
     ar -t [-TLsv] archive [file ...]
     ar -x [-ouTLsv] archive [file ...]

ar可以修改查看a文件的內(nèi)容

ar -t libReplaceAFNetWorking.a
__.SYMDEF SORTED
ReplaceAFNetWorking.o

我們創(chuàng)建的庫(kù)里面就一個(gè)目標(biāo)文件

2.3創(chuàng)建test文件去調(diào)用我們的庫(kù)

#import <Foundation/Foundation.h>
#import <ReplaceAFNetWorking.h>

int main(){
    ReplaceAFNetWorking *manager = [ReplaceAFNetWorking new];
    NSLog(@"testApp----%@", manager);
    return 0;
}

2.3把我們的test文件編譯成目標(biāo)文件(.o文件)

我們用clang編譯我們的m文件成目標(biāo)文件

man clang 
clang - the Clang C, C++, and Objective-C compiler
SYNOPSIS
       clang [options] filename ...

DESCRIPTION
       clang  is  a C, C++, and Objective-C compiler which encompasses prepro-
       cessing, parsing, optimization, code generation, assembly, and linking.
       Depending  on  which high-level mode setting is passed, Clang will stop
       before doing a full link.  While Clang  is  highly  integrated,  it  is
       important to understand the stages of compilation, to understand how to
       invoke it.  These stages are:

使用如下命令

clang -x objective-c \
-target x86_64-apple-macos11.0.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-I./ReplaceAFNetWorking \
-c test.m -o test.o

2.4.生成可執(zhí)行文件

clang -target x86_64-apple-macos11.0.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-L./ReplaceAFNetWorking \
-lReplaceAFNetWorking \
test.o -o test

clang命令參數(shù):
-x: 指定編譯文件語(yǔ)言類型
-g: 生成調(diào)試信息
-c: 生成目標(biāo)文件,只運(yùn)行preprocess题山,compile兰粉,assemble,不鏈接
-o: 輸出文件
-isysroot: 使用的SDK路徑
1. -I<directory> 在指定目錄尋找頭文件 header search path
2. -L<dir> 指定庫(kù)文件路徑(.a.dylib庫(kù)文件) library search path
3. -l<library_name> 指定鏈接的庫(kù)文件名稱(.a.dylib庫(kù)文件)other link flags -lAFNetworking
-F<directory> 在指定目錄尋找framework framework search path
-framework <framework_name> 指定鏈接的framework名稱 other link flags -framework AFNetworking

3靜態(tài)庫(kù)原理

3.1探究的環(huán)境顶瞳。

image.png
//TestExample的h文件
#import <Foundation/Foundation.h>

@interface TestExample : NSObject

- (void)lg_test:(_Nullable id)e;

@end
//TestExample的m文件
@implementation TestExample

- (void)lg_test:(_Nullable id)e {
    NSLog(@"TestExample----");
}
@end
//test文件的內(nèi)容
#import <Foundation/Foundation.h>
#import "TestExample.h"

int main(){
    NSLog(@"testApp----");
   return 0;
}

3.2. TestExample文件編譯成目標(biāo)文件

 clang -x objective-c \
-target x86_64-apple-macos11.0.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-c TestExample.m -o TestExample.o

3.3修改目標(biāo)文件為庫(kù)文件

把TestExample.o文件修改成libTestExample.a亲桦。如果系統(tǒng)比較新可以把o文件改成后綴dylib的文件

3.4編譯test.m文件為目標(biāo)文件

 clang -x objective-c \
-target x86_64-apple-macos11.0.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-I./StaticLibrary \
> -c test.m -o test.o

3.5鏈接

clang \
-target x86_64-apple-macos11.0.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk \
-L./StaticLibrary \
-lTestExample \
test.o -o test

3.6執(zhí)行

lldb
file test
//Current executable set to '/Users/MacW/Desktop/loginlearn/強(qiáng)化版/強(qiáng)化班-3-靜 
//態(tài)庫(kù)/上課代碼/靜態(tài)庫(kù)原理/test' (x86_64).
r
//Process 14790 launched: '/Users/MacW/Desktop/loginlearn/強(qiáng)化版/強(qiáng)化班-3-靜
//態(tài)庫(kù)/上課代碼/靜態(tài)庫(kù)原理/test' (x86_64)
//2021-01-21 19:19:24.535476+0800 test[14790:1474339] testApp----
//2021-01-21 19:19:24.535943+0800 test[14790:1474339] TestExample----
//Process 14790 exited with status = 0 (0x00000000)

總結(jié)崖蜜,靜態(tài)庫(kù)就是目標(biāo)文件.o文件的合集,Framework的合成和.a差不多,唯一區(qū)別就是在鏈接的時(shí)候-L和-l換成-F 和-framework

4.靜態(tài)庫(kù)合并

可以通過ar命令客峭,
ar`壓縮目標(biāo)文件,并對(duì)其進(jìn)行編號(hào)和索引抡柿,形成靜態(tài)庫(kù)舔琅。同時(shí)也可以解壓縮靜態(tài)庫(kù),查看有哪些目標(biāo)文件:
ar -rc a.a a.o
-r: 像a.a添加or替換文件
-c: 不輸出任何信息
-t: 列出包含的目標(biāo)文件
ar -rc libTestExample.a TestExample.o
我們一般使用xcode給我提供的libtool

libtool \
 -static \
 -o libmerge.a \
 libSDWebImage.a \
 libAFNetworking.a

5.dead code strip

我們?cè)?的探究庫(kù)原理的時(shí)候洲劣,只引用了TestExample頭文件备蚓,但是沒有對(duì)TestExample使用,那TestExample代碼是否被鏈接到我們的test文件中的呢

objdump --macho -d test
test:
(__TEXT,__text) section
_main:
100003f60:  55  pushq   %rbp
100003f61:  48 89 e5    movq    %rsp, %rbp
100003f64:  48 83 ec 10 subq    $16, %rsp
100003f68:  48 8d 05 99 00 00 00    leaq    153(%rip), %rax ## Objc cfstring ref: @"testApp----"
100003f6f:  c7 45 fc 00 00 00 00    movl    $0, -4(%rbp)
100003f76:  48 89 c7    movq    %rax, %rdi
100003f79:  b0 00   movb    $0, %al
100003f7b:  e8 08 00 00 00  callq   0x100003f88 ## symbol stub for: _NSLog
100003f80:  31 c0   xorl    %eax, %eax
100003f82:  48 83 c4 10 addq    $16, %rsp
100003f86:  5d  popq    %rbp
100003f87:  c3  retq

從命令中看出TestExample的代碼并沒有
我們?cè)趍ain中做如下修改

int main(){
    NSLog(@"testApp----");
    TestExample *manager = [TestExample new];
    [manager lg_test: nil];
    return 0;
}

編譯連接后查看

100003ef9:  48 8b 35 c8 41 00 00    movq    16840(%rip), %rsi ## Objc selector ref: lg_test:

這樣會(huì)出現(xiàn)一個(gè)問題囱稽,因?yàn)槲覀兊姆诸愂窃谶\(yùn)行時(shí)創(chuàng)建的郊尝,但是我們dead code是在連接的時(shí)候生效的,所以我們的分類就會(huì)被strip掉战惊,當(dāng)我們運(yùn)行時(shí)就會(huì)出現(xiàn)實(shí)例找不到方法的情況流昏。我們配置other linkers flags
我們?cè)赾onfig文件配置如下

OTHER_LDFLAGS=-Xlinker -all_load

-Xlinker -all_load:不dead strip,加載全部代碼
-Xlinker -ObjC:加載全部OC相關(guān)代碼吞获,包括分類
-Xlinker -force_load: 要加載那個(gè)靜態(tài)庫(kù)的全部代碼
dead code strip和-all_load的區(qū)別
-all_load 指定對(duì)靜態(tài)庫(kù)的鏈接情況况凉,-ObjC 是全部鏈接還是只鏈接oc符號(hào), -force_load是指定鏈接某一個(gè)靜態(tài)庫(kù)各拷。和-dead_strip的作用如下

-dead_strip
                 Remove functions and data that are unreachable by the entry
                 point or exported symbols.

我們?cè)趯?shí)際應(yīng)用中刁绒,可以如下指定參數(shù)

clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot $SYSROOT \
-Xlinker -dead_strip \
-Xlinker -all_load \
-Xlinker -why_live -Xlinker _global_function \
-L./StaticLibrary \
-lTestExample \
${FILE_NAME}.o -o ${FILE_NAME}

-why_live -Xlinker:指某個(gè)符號(hào)為什么存在

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市烤黍,隨后出現(xiàn)的幾起案子知市,更是在濱河造成了極大的恐慌,老刑警劉巖速蕊,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫂丙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡互例,警方通過查閱死者的電腦和手機(jī)奢入,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)媳叨,“玉大人腥光,你說(shuō)我怎么就攤上這事『眩” “怎么了武福?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)痘番。 經(jīng)常有香客問我捉片,道長(zhǎng)平痰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任伍纫,我火速辦了婚禮宗雇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘莹规。我一直安慰自己赔蒲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布良漱。 她就那樣靜靜地躺著舞虱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪母市。 梳的紋絲不亂的頭發(fā)上矾兜,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音患久,去河邊找鬼椅寺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛墙杯,可吹牛的內(nèi)容都是我干的配并。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼高镐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼溉旋!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起嫉髓,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤观腊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后算行,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梧油,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年州邢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了儡陨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡量淌,死狀恐怖骗村,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情呀枢,我是刑警寧澤胚股,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站裙秋,受9級(jí)特大地震影響琅拌,放射性物質(zhì)發(fā)生泄漏缨伊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一进宝、第九天 我趴在偏房一處隱蔽的房頂上張望刻坊。 院中可真熱鬧,春花似錦党晋、人聲如沸紧唱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蛹锰,卻和暖如春深胳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背铜犬。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工舞终, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人癣猾。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓敛劝,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纷宇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子夸盟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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