1. 程式人生 > 其它 >如何解決靜態庫的衝突問題 iOS

如何解決靜態庫的衝突問題 iOS

問題
iOS中進入靜態庫經常會出現 dulipcate symbols 的問題。分享下我的處理以及經驗。

靜態庫
在 iOS 中靜態庫有.a和framework檔案。下面講解如何對靜態庫解包和處理衝突的問題。

Fat檔案
首先需要了解的是,一般來說我們拿到的靜態庫都是Fat檔案,我們都知道一個靜態庫包可能支援各個架構(eg:arm64,armv7),所謂Fat檔案意思就是這個檔案很胖,他包含了不止一個架構。

我們通過 lipo -info 和 file 命令可以檢視 靜態庫 framework 的架構

gensees-iMac-2:~ gensee$ lipo -info /Volumes/CaiCai/3.7.9/sdk.ios.3.7.9_20191226/Frameworks/GPUImage.framework/GPUImage
Architectures in the fat file: /Volumes/CaiCai/3.7.9/sdk.ios.3.7.9_20191226/Frameworks/GPUImage.framework/GPUImage are: i386 armv7 x86_64 arm64


gensees-iMac-2:~ gensee$ file /Volumes/CaiCai/3.7.9/sdk.ios.3.7.9_20191226/Frameworks/GPUImage.framework/GPUImage
/Volumes/CaiCai/3.7.9/sdk.ios.3.7.9_20191226/Frameworks/GPUImage.framework/GPUImage: Mach-O universal binary with 4 architectures: [i386:current ar archive] [arm64]
/Volumes/CaiCai/3.7.9/sdk.ios.3.7.9_20191226/Frameworks/GPUImage.framework/GPUImage (for architecture i386): current ar archive
/Volumes/CaiCai/3.7.9/sdk.ios.3.7.9_20191226/Frameworks/GPUImage.framework/GPUImage (for architecture armv7): current ar archive
/Volumes/CaiCai/3.7.9/sdk.ios.3.7.9_20191226/Frameworks/GPUImage.framework/GPUImage (for architecture x86_64): current ar archive
/Volumes/CaiCai/3.7.9/sdk.ios.3.7.9_20191226/Frameworks/GPUImage.framework/GPUImage (for architecture arm64): current ar archive
1
2
3
4
5
6
7
8
9
10
這表示GPUImage.framework/GPUImage檔案是一個胖檔案(Fat),它包含了arm64,armv7,i386,x86_64 四種架構

此外.a 也有可能是Fat檔案,例如ffmpeg庫

Architectures in the fat file: /Volumes/CaiCai/3.7.9/sdk.ios.3.7.9_20191226/Libs/ffmpeg/libavcodec.a are: i386 armv7 x86_64 arm64
1
Fat檔案就是表示各個架構的靜態庫的集合


這裡值得注意的是xxx.a和xxx.framework/xxx檔案都可以是Fat檔案,他們的字尾不一樣而已,Fat檔案只是一個概念。

thin檔案
根據Fat概念是不是很好聯想thin檔案意義,沒錯,它就是Fat檔案中的一個架構的包檔案。

上面的圖可以換成這樣:

我們如何完成fat檔案和thin檔案之間的轉換呢?

fat -> thin
假如需要拆出arm64架構的thin檔案

lipo xxx.a -thin arm64 -output xxx_arm64.a
1
thin -> fat
假如需要合併兩個thin檔案為fat

lipo create xxx_arm64.a xxx_armv7.a -output xxx_conbined.a
1
指令同樣適用於xxx.framework/xxx檔案

.a檔案的構成
.a檔案由.o檔案組成,.o檔案是編譯器編譯的產物,一個編譯過程經過

.m -> .i(彙編檔案) -> IR(中介軟體) -> .o(各個架構的.o)

解包
我們將thin檔案進行解包,就可以看到,用ar -x指令進行解包

//拆分thin
lipo /Volumes/CaiCai/Python/GPUImage.framework/GPUImage -thin arm64 -output GPUImage_arm64
//這裡建議先cd到一個新資料夾 ar -x 指令直接解壓當前檔案了
//ar解包
ar -x /Volumes/CaiCai/Python/arm64/GPUImage_arm64
1
2
3
4
5
這裡附上一個關於 ar指令的說明

可以看到拆分了很多.o檔案,__.SYMDEF 檔案是符號定義,我們可以通過cat檢視

我這裡截取了一段供參考,可以看到類變數以及方法都在裡面。

_OBJC_CLASS_$_GPUImageContext_OBJC_IVAR_$_GPUImageContext._context_OBJC_IVAR_$_GPUImageContext._contextQueue_OBJC_IVAR_$_GPUImageContext._coreVideoTextureCache_OBJC_IVAR_$_GPUImageContext._currentShaderProgram_OBJC_IVAR_$_GPUImageContext._framebufferCache_OBJC_IVAR_$_GPUImageContext._sharegroup_OBJC_IVAR_$_GPUImageContext.shaderProgramCache_OBJC_IVAR_$_GPUImageContext.shaderProgramUsageHistory_OBJC_METACLASS_$_GPUImageContext_OBJC_CLASS_$_GLProgram_OBJC_IVAR_$_GLProgram._fragmentShaderLog_OBJC_IVAR_$_GLProgram
1
這裡我們需要注意的的是__.SYMDEF 不包含分類的符號,我們通常使用-ObjC的意思就是:不僅僅只載入__.SYMDEF 檔案中的符號,還載入庫中的分類。

下面講反向操作,怎麼將.o合併為.a

將.o合併為.a
同樣使用ar命令,不過是ar -r -s,這裡合成armv7的包

ar -r -s yourname_armv7.a *.o
1
這裡就會將所有.o合併為yourname.a,-s表示無論ar 命令是否修改了庫內容都強制重新生成庫符號表。請在庫上使用 strip 命令之後,使用此標誌來恢復庫符號表。

你也可以使用

libtool -static -o ../yourname_armv7.a *.o
1
來合併

注意:strip -x name.a 用來去除lib庫中的符號表資訊,可以大量的減少lib庫的包體積,一般來說靜態庫上線之前我們會進行strip指令,以減少包體積。

好了,說了這麼多,如何解決 duplicate symbols 問題?

多個靜態庫的合併
使用 Xcode libtool 合併多個靜態庫

xcrun -r libtool -no_warning_for_no_symbols \
-static -o output.a 1.a 2.a 3.a 4.a
1
2
-no_warning_for_no_symbols 不輸出 has no symbols 的警告
-static 連結的型別為靜態庫
-o 指定合併後的檔案路徑
xcrun -r libtool 使用 Xcode Toolchain 裡的 libtool,直接執行 libtool 會使用 $PATH 的路徑的

duplicate問題
我們經常出現 duplicate symbols for architecture x86_64

看下詳細說明就如下面這種:

duplicate symbol `_OBJC_CLASS_$_XXX` in:
1
去除重複 .o
這裡是檔案的重複,例如xxx.o同時存在與兩個靜態庫A.a和B.a中,我們需要做的就是將一份.a檔案拆開,刪除其中的xxx.o檔案,然後再還原,這樣工程中就只有一份xxx.o。當然這個前提是兩份xxx.o檔案實現是一樣的,不然內部的符號不一樣,還是會造成符號丟失,會出現undefine symbols類似的錯誤。

將編譯的.m檔案去除
由於.o檔案是由.m檔案(這裡舉例,可以是cpp,c檔案等等)編譯而成,那麼我們只需要刪除.m檔案就可以處理掉。同時這裡可以處理兩份xxx.o檔案實現不一樣的情況,或者main函式重複的情況。

各個架構的支援
如果需要一個靜態庫即支援模擬器(i386,x86_64)又支援真機(arm64,armv7),那麼我們就需要將thin檔案進行合併成fat檔案來達到。

值得注意的是各個架構的thin檔案互不影響,意思就是一個庫A可能在模擬器上是空實現,在真機上有具體實現,你同樣可以將真機和模擬器包合併,互不衝突


————————————————
版權宣告:本文為CSDN博主「CaicaiNo.1」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/shengpeng3344/article/details/105384180

在北京的燈中,有一盞是我家的。這個夢何時可以實現?哪怕微微亮。北京就像魔鬼訓練營,有能力的留,沒能力的走……