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提供商一般選擇動態庫,自己開發中最好使用靜態庫
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容