騰訊提供的iOS SDK ——TencentOpenApi 是靜態庫,然后因為業務需求,需要把它轉換為動態庫(取名:DynamicTencentOpenApi)。在實際開發時,發現了一個奇怪的事情:
整個工程如下:
(有興趣的讀者,可直接下載該工程,進行實驗)
Demo 的測試 DynamicTencentOpenApi.Framework 的主要代碼如下:
// 測試TencentOAuth
NSString *version = [TencentOAuth sdkVersion];
NSLog(@"%@",version);
// 測試QQApiInterface
NSString *qqInstallUrl = [QQApiInterface getQQInstallUrl];
NSLog(@"%@",qqInstallUrl);
運行編譯工程的 DynamicTencentOpenApi Target 和 Demo Target,得到結果如下:
- DynamicTencentOpenApi.Framework 編譯運行成功
- Demo 編譯鏈接失敗,報錯誤:
Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_QQApiInterface"
這里奇怪的地方在于:
- DynamicTencentOpenApi.Framework 編譯運行成功
- Demo 編譯鏈接時,TencentOAuth 的 symbol 能找到,QQApiInterface 的 symbol 卻找不到?
用 MachOView 查看 DynamicTencentOpenApi.Framework 里的 binary 文件發現:
-
_OBJC_CLASS_$_QQApiInterface
symbol 的類型是:N_PEXT
-
_OBJC_CLASS_$_TencentOAuth
symbol 的類型是:N_EXT
N_PEXT
和 N_EXT
的區別是:
N_PEXT (0x10)—If this bit is on, this symbol is marked as having limited global scope. When the file is fed to the static linker, it clears the N_EXT bit for each symbol with the N_PEXT bit set. (The ld option -keep_private_externs turns off this behavior.) With macOS GCC, you can use the private_extern function attribute to set this bit.
N_EXT (0x01)—If this bit is on, this symbol is an external symbol, a symbol that is either defined outside this file or that is defined in this file but can be referenced by other files.
翻譯過來,這2者的區別是:
-
N_PEXT
,意思是:private_extern。該類型的 symbol 在指定范圍內可見 -
N_EXT
,意思是:extern。該類型的 symbol,在任何范圍內均可見
關于范圍如圖所示:
因此,在編譯Demo-OC時,到鏈接階段時,就找不到這個_OBJC_CLASS_$_QQApiInterface
symbol,繼而編譯失敗。
那么如何解決這個問題呢?
創建一個QQApiInterface鏡像類
,鏡像類 wrap QQApiInterface
,對外提供和QQApiInterface
一致的接口,在內則把對應的方法響應轉發給QQApiInterface
。具體可看例子中的鏡像類 QQApiInterfaceMirror。
原來準備按照這個方案實現 DynamicTencentOpenApi ,但是后面發現,TencentOpenApi SDK 里不止 QQApiInterface 的 symbol 是N_PEXT
類型,還有QQApiTextObject
、QQApiExtendObject
、QQApiImageObject
、QQApiWebImageObject
等類的 symbol 都是N_PEXT
類型的。考慮到開發成本(為這些類創建同等的鏡像類)和維護成本(TencentOpenApi SDK 升級后,每個鏡像類都得重新測試),最終是放棄把 TencentOpenApi 從靜態庫轉換到動態庫 DynamicTencentOpenApi。
這種編譯鏈接的錯誤(symbol的范圍受限導致鏈接失敗),相對來說,是比較少見的,因而花了很多時間去查,才找到了原因。希望這篇文章能讓后面的來者可以避開此坑。enjoy~
參考資料: