這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
鑒於目前動態庫在iOS App中使用越來越廣泛,二進位的相容問題可能會成為一個令人頭疼的問題。本文主要對比一下C++、Java、Objecive-C和Swift的二進位相容問題。
iOS端動態庫使用方式
iOS 8開始支援App使用動態庫。
蘋果對提交的App的__TEXT__段大小是有限制的,很多巨無霸App容易超出這個限制。iOS9之前每個架構的__TEXT__段比較小,iOS9放大到了500MB。詳細情況請看:To submit an app for review。
開源庫只能通過Podfile做源碼引入,源碼依賴,編譯非常慢。
可持續構建也需要基於蘋果的環境,比如使用Mac Pro/Mac Mini構建。Mac Pro比較昂貴,Mac mini效能不行,構建一次需要花費大量時間。
大型App為了加快編譯速度,可以維護自己的私人倉庫,把依賴的庫盡量編譯成Framework,加快編譯速度。
Swift目前必須基於動態庫開發。
基於動態庫構建App,升級一個動態庫需要將整個依賴樹編譯一遍。尤其是一些頻繁變動的基礎組件,比如視覺組件的改動,牽一髮而動全身。
測試環境
C++、Java、OC和Swift分別實現Foo這個基類,然後再實現Bar這個子類,main則使用Bar類列印成員變數的資訊。給Foo類新增成員變數member0,重新編譯Foo(make foo && ./main),Bar和main不變,然後觀察執行結果。
代碼地址:binary_compatibility_test。
LLDB一點有用的調試技巧。更多的調試功能,請參看:The LLDB Debugger。
測試結果
1.C++會出現錯位,但是沒有崩潰。二進位也是比較脆弱的。
2.Java能正常工作。
3.OC能正常工作。OC非常適合基於動態庫的組件方式。
4.Swift構造Bar對象就會崩潰。現狀讓我們非常頭疼。
結果分析
C++的設計沒有考慮到二進位相容的問題,所以相容很一般。
Java的二進位相容非常完美,對象成員改變,方法增刪,都不會輕易導致二進位相容問題。詳細情況請參看:Chapter 13. Binary Compatibility。
OC使用方法和屬性都使用訊息派發,增加和刪除方法,移動方法的順序,都不會導致問題;另外對成員變數的改變做了支援,所以二進位相容完美。
作為一種嶄新的語言,Swift的二進位相容最差,匪夷所思啊。
另外大家討論的時候也提到C++虛函數改變順序會不會出問題。針對這個問題我驗證了一下,確認C++虛函數表裡面函數的順序完全取決於函數在標頭檔中聲明的順序。
比如Foo有func1和func2兩個虛函數,調換func1和func2的順序,不重新編譯main。在main裡面調用func2,實際上會調用到func1。
參考文章
1.C++ ABI Compliance Checker
2.Objective-C類成員變數深度剖析
3.Non Fragile ivars
4.Objc源碼
5.Swift庫二進位介面(ABI)相容性研究
最後的最後:
Golang也是一門嶄新的語言,我非常好奇它對二進位相容這塊是怎麼考慮的,所以歡迎廣大有為青年補充一個Golang版本。