常用命令
-
file - 用于判斷是動態(tài)庫還是靜態(tài)庫
動態(tài)庫: 顯示“Mach-O 64-bit dynamically linked shared library arm64”
靜態(tài)庫: 顯示“current ar archive random library” 或“current ar archive ”场梆。
-
lipo - 用于查看庫包含的架構信息及合并拆分
lipo -info /framework路徑/xxx.framework/xxx
lipo -create 庫1 庫2 -output 合并后的fat庫
lipo 待拆分的fat庫 -thin 需拆分框架 -output 新庫
基礎知識
- mach-o文件類型
- Executable:應用的主要二進制
- Dylib Library:動態(tài)鏈接庫(又稱DSO或DLL)
- Static Library:靜態(tài)鏈接庫
- Bundle:不能被鏈接的Dylib延柠,只能在運行時使用dlopen( )加載,可當做macOS的插件
- Relocatable Object File:可重定向文件類型
- 文件類型
靜態(tài)庫一般是.a文件昭殉,也可能沒有后綴。
動態(tài)庫一般是.framework文件郁稍,.framework文件其實只是個文件夾烙心,真正的二進制文件在.framework里面。.framework里面的二進制文件也可能是靜態(tài)庫拙已,也有可能是動態(tài)庫。有后綴也可能沒有后綴摧冀。
c語言文件處理過程為:
// 預處理階段倍踪。預處理為.i文件 系宫,所有的預處理器指令都是以井號 # 開頭,只有空格字符可以出現(xiàn)在預處理指令之前建车。
// 例如#define,#import,#include,#ifdef #endif
// OC的#import相對#include來講扩借,優(yōu)勢就是解決了預處理階段的循環(huán)包含的問題。
// A文件#include B文件缤至,同事B文件include A文件潮罪,就會相互展開。#import只會展開一次领斥。
gcc –E hello.c -o hello.i
// 編譯階段嫉到。編譯為.s匯編語言文件
// 這個階段編譯器主要做詞法分析、語法分析月洛、語義分析等何恶,在檢查無錯誤后后,把代碼翻譯成匯編語言嚼黔。 匯編語言程序导而,即低級機器語言指令
gcc -S hello.i -o hello.s
// 匯編階段。匯編器as 將.s文件 翻譯成機器語言隔崎,打包形成可重定位的目標文件hello.o 中(二進制文本形式)。
gcc -c hello.s -o hello.o
// 鏈接階段韵丑。此階段完成文件中調用的各種函數(shù)的靜態(tài)鏈接和動態(tài)鏈接爵卒,并將它們一起打包合并形成目標文件,即可執(zhí)行文件撵彻。
// 靜態(tài)鏈接:是指把要調用的函數(shù)或者過程拷貝到可執(zhí)行文件中钓株,成為可執(zhí)行文件的一部分。
// 動態(tài)鏈接:所調用的函數(shù)代碼并沒有被拷貝到應用程序的可執(zhí)行文件中去陌僵,而是僅僅在其中加入了所調用函數(shù)的描述信息(往往是一些重定位信息)轴合。
// mac、iOS中的可執(zhí)行文件幾乎都是mach-o文件類型
gcc hello.o -o hello
mach-o文件解析
// Header頭部碗短,包含可以執(zhí)行的CPU架構受葛,比如x86,arm64
// Load commands 加載命令偎谁,包含文件的組織架構和在虛擬內存中的布局方式
// Data总滩,數(shù)據(jù),包含load commands中需要的各個段(segment)的數(shù)據(jù)巡雨,每個Segment的大小都是Page的整數(shù)倍闰渔。
mach-o文件加載過程
// 1. 加載dyld到App進程
// 2. 加載動態(tài)庫(包括所依賴的所有動態(tài)庫)
// 3. Rebase
// 4. Bind
// 5. 初始化Objective C Runtime。
// 6. 其它的初始化代碼
- 靜態(tài)庫和動態(tài)庫的區(qū)別
靜態(tài)庫:鏈接時會被完整的復制到可執(zhí)行文件中铐望,所以如果兩個程序都用了某個靜態(tài)庫冈涧,那么每個二進制可執(zhí)行文件里面其實都含有這份靜態(tài)庫的代碼茂附。
動態(tài)庫:鏈接時不復制,在程序啟動后用動態(tài)加載督弓,所以理論上動態(tài)庫只用存在一份营曼,好多個程序都可以動態(tài)鏈接到這個動態(tài)庫上面,達到了節(jié)省內存(不是磁盤是內存中只有一份動態(tài)庫)咽筋,還有另外一個好處溶推,由于動態(tài)庫并不綁定到可執(zhí)行程序上,所以我們想升級這個動態(tài)庫就很容易奸攻,windows和linux上面一般插件和模塊機制都是這樣實現(xiàn)的蒜危。
iOS動態(tài)庫:
iOS平臺上規(guī)定不允許存在動態(tài)庫,并且所有的 IPA 都需要經過Apple的私鑰加密后才能用睹耐。
基本你用了動態(tài)庫也會因為簽名不對無法加載辐赞,所以iOS下并不存在真正的動態(tài)庫。
iOS8之前因為 iOS 應用都是運行在沙盒當中硝训,不同的程序之間不能共享代碼响委,并且iOS是單進程的,也就是某一時刻只有一個進程在運行窖梁,那么你寫個共享庫赘风,給誰共享呢。
同時動態(tài)下載代碼又是被蘋果明令禁止的纵刘,沒辦法發(fā)揮出動態(tài)庫的優(yōu)勢邀窃,綜上所以上動態(tài)庫也就沒有存在的必要了。
但是后來iOS8之后假哎,iOS有了App Extesion特性瞬捕,而且Swift也誕生了。
由于iOS主App需要和Extension共享代碼舵抹,Swift語言機制也需要動態(tài)庫肪虎,于是蘋果后來提出了Embedded Framework。
這種動態(tài)庫允許APP和APP Extension共享代碼惧蛹,但是這份動態(tài)庫的生命被限定在一個APP進程內扇救。簡單點可以理解為被閹割的動態(tài)庫。
但是這種動態(tài)庫(Embedded Framework) 和系統(tǒng)的 UIKit.Framework 還是有很大區(qū)別香嗓。
傳統(tǒng)的動態(tài)庫是給多個進程用的爵政,而這里的動態(tài)庫(Embedded Framework)是給單個進程里面多個可執(zhí)行文件用的。
系統(tǒng)的 Framework 不需要拷貝到目標程序中陶缺,我們自己做出來的 動態(tài)庫(Embedded Framework) 哪怕是動態(tài)的钾挟,最后也還是要拷貝到 App 中(App 和 Extension 的 Bundle 是共享的)。
所以蘋果沒有直接把這種Embedded Framework稱作動態(tài)庫而是叫Embedded Framework饱岸。
iOS中的Embedded Framework可以理解為獨立的沒有main函數(shù)的可執(zhí)行文件掺出。
- Cocoapods的做法
use_frameworks!選項:在使用CocoaPods的時候在Podfile里加入use_frameworks! 徽千,那么你在編譯的時候就會默認幫你生成動態(tài)庫,我們能看到每個源碼Pod都會在Pods工程下面生成一個對應的動態(tài)庫Framework的target汤锨,我們能在這個target的Build Settings -> Mach-O Type看到默認設置是Dynamic Library双抽。也就是會生成一個動態(tài)Framework,我們能在Products下面看到每一個Pod對應生成的動態(tài)庫闲礼。
對于swift寫的庫牍汹,想通過cocoapods引入工程,必須加入use_frameworks! 選項柬泽。因為 Swift 是不支持靜態(tài)庫的慎菲。造成這個問題的原因主要是 Swift 的運行庫沒有被包含在 iOS 系統(tǒng)中,而是會打包進 App 中(這也是造成 Swift App 體積大的原因)锨并,靜態(tài)庫會導致最終的目標程序中包含重復的運行庫露该。
打包進工程的動態(tài)庫,可在 ipa 文件解壓后的 Frameworks 文件夾下看到第煮。
參考:
編譯入門
深入理解iOS App的啟動過程
iOS動態(tài)庫解幼、靜態(tài)庫及使用場景、方式
最后編輯于 :
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者