iOS-開發進階05:動態庫

iOS 開發進階 文章匯總

目錄


一、可執行文件鏈接動態庫.dylib

準備代碼如下:


test.m文件中代碼如下:

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

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

參照上篇文章編譯鏈接動態庫:

1、生成目標文件

使用clang命令編譯main.m代碼

cd main.m 文件目錄下

clang -x objective-c \
-target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-I./AFNetworking \
-c test.m -o test.o
2、鏈接靜態庫生成可執行文件

使用clang命令鏈接動態庫命令如下:

clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-L./AFNetworking \
-lAFNetworking \
test.o -o test

3、在終端執行test可執行文件


這里就出現鏈接動態庫和鏈接靜態不同的地方。



二、dyld加載動態庫流程

從上面這張流程圖中我們可以看到dyldMach-O中讀取LC_LOAD_DYLIB保存動態庫信息來加載動態庫,因此上面鏈接AFNetworking動態庫的test可執行文件中沒有找到動態庫的路徑所以運行時報了錯。

1、查看Mach-OLC_LOAD_DYLIB信息

// -A:向下尋找   -B:向上尋找    5:5行
otool -l test | grep 'DYLIB' -A 5

由此可以看出動態庫的路徑由兩部分組成,一部分是@rpath可執行文件提供,另一部分是動態庫中提供

2、@rpath

Runpath search Paths:dyld搜索路徑,誰需要鏈接動態庫誰就需要提供@rpath
運行時@rpath指示dyld按順序搜索路徑列表,以找到動態庫。@rpath保存一個或 多個路徑的變量

因此可以分析出test可執行文件沒有提供@rpath,導致動態庫的路徑不完整。

查看Mach-O@rpath信息

可以看到此Mach-O中的確沒有@rpath

3、Mach-O中添加@rpath

install_name_tool -add_rpath /Users/ztkj/Desktop/鏈接動態庫AFN test

4、修改動態庫中的路徑

由于AFNetworking生成動態庫時的路徑和我們現在的文件結構不一致,所以還需要修改動態庫中的路徑

這里和前面查看Mach-OLC_LOAD_DYLIB信息是一致的,修改路徑(name-->參數使用-id)代碼如下:

install_name_tool -id @rpath/AFNetworking libAFNetworking.dylib

重新鏈接動態庫生成可執行文件test(執行第三步添加@rpath)后即可運行

Xcode如果引入了第三方動態庫,那么在Build Settings中也會自動加上install namerpath


三、創建動態庫.dylib

準備如下代碼:


build.sh中的代碼如下:

echo "編譯test.m --- test.o"
clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-I./dylib \
-c test.m -o test.o

pushd ./dylib
echo "編譯TestExample.m --- TestExample.o"
clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-c TestExample.m -o TestExample.o

echo "編譯TestExample.o --- libTestExample.a"

# Xcode提供的工具生成靜態庫
libtool -static -arch_only x86_64 TestExample.o -o libTestExample.a


echo "編譯TestExample.a --- libTestExample.dylib"
# 通過.o生成動態庫
#clang -dynamiclib \
#-target x86_64-apple-macos11.1 \
#-fobjc-arc \
#-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
#-Xlinker -install_name -Xlinker @rpath/TestExample \
#TestExample.o -o libTestExample.dylib

# dylib 最終鏈接產物 -》
ld -dylib -arch x86_64 \
-macosx_version_min 11.1 \
-syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-lsystem -framework Foundation \
-Xlinker -install_name -Xlinker @rpath/TestExample \
-all_load \
libTestExample.a -o libTestExample.dylib

popd

echo "鏈接libTestExample.dylib -- test EXEC"
clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-Xlinker -rpath -Xlinker @executable_path/dylib \
-L./dylib \
-lTestExample \
test.o -o test

# 添加@rpath
#install_name_tool -add_rpath @executable_path/dylib test

echo "-------DYLIB---------"
otool -l test | grep 'DYLIB' -A 5
echo "-------RPATH---------"
otool -l test | grep 'RPATH' -A 5

其中為動態庫(install_name)和可執行文件(rpath)添加路徑的參數如下:

-Xlinker -install_name -Xlinker @rpath/TestExample \

//添加@rpath
-Xlinker -rpath -Xlinker @executable_path/dylib \
install_name_tool -add_rpath @executable_path/dylib test


四、創建動態庫Framework

準備的目錄結構如下:

第一個build.sh文件代碼如下:

clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-I./Frameworks/TestExample.framework/Headers \
-c test.m -o test.o

clang   \
-target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-F./Frameworks \
-framework TestExample \
test.o -o test

install_name_tool -add_rpath @executable_path/Frameworks test

echo "-------DYLIB---------"
otool -l test | grep 'DYLIB' -A 5
echo "-------RPATH---------"
otool -l test | grep 'RPATH' -A 5

第二個build.sh文件代碼如下:

clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-I./Headers \
-c TestExample.m -o TestExample.o
#需要再鏈接動態庫的頭文件
#-I./Frameworks/TestExampleLog.framework/Headers \

clang -dynamiclib  \
-target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-Xlinker -install_name -Xlinker @rpath/TestExample.framework/TestExample \
-F./Frameworks \
TestExample.o -o TestExample
#需要再鏈接動態庫的庫名
#-framework TestExampleLog \

#如果這個動態庫中需要再鏈接動態庫,就需要在這里為鏈接的動態庫提供rpath
#install_name_tool -add_rpath @loader_path/Frameworks TestExample

echo "-------DYLIB---------"
otool -l TestExample | grep 'DYLIB' -A 5
echo "-------ID---------"
otool -l TestExample | grep 'ID' -A 5
echo "-------RPATH---------"
otool -l TestExample | grep 'RPATH' -A 5
  • @executable_path: 表示可執行程序所在的目錄,解析為可主程序執行文件的絕對路徑。
  • @loader_path: 表示被加載的Mach-O所在的目錄,用于動態庫鏈接其他動態庫時提供的rpath路徑。

先執行第二個build.sh文件再執行第一個build.sh文件即可生成動態庫Framework。此外在第二個build.sh文件中還可以添加動態庫鏈接動態庫的參數。


五、tdb格式

什么是tdb格式?

tbd全稱是text based stub libraries, 本質上就是一個YAML描述的文本文件。他的作用是用于記錄動態庫的一些信息,包括導出的符號、動態庫的架構信息、動態庫的依賴信息。用于避免在真機開發過程中直接使用傳統的dylib
對于真機來說,由于動態庫都是在設備上,在Xcode上使用基于tbd格式的偽framework可以大大減少Xcode的大小。
Xcode編譯時通過讀取動態庫的tbd即可完成編譯,只有運行時才會在執行動態庫中的代碼。


六、靜態庫與動態庫的區別

靜態庫:鏈接時會被完整的復制到可執行文件中,被多次使用就有多份拷貝。
動態庫:鏈接時不復制,程序運行時由系統動態加載到內存,系統只加載一次,多個程序共用(如系統的UIKit.framework等),節省內存。

總結

  • 靜態庫可以鏈接變成動態庫,動態庫是最終的編譯產物,因此動態庫不能合并
  • 上架動態庫需要簽名,過多的動態庫會影響啟動速度
  • SDK提供商一般選擇動態庫,自己開發中最好使用靜態庫
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容