1. 程式人生 > >結合實際問題的 Bitcode 適配指南 (一)

結合實際問題的 Bitcode 適配指南 (一)

隨著XCode7的釋出,Apple提供了一項新的技術來支援App瘦身功能,那就是Bitcode。本文章將會結合自己在支援bitcode過程中遇到的問題,來闡述支援bitcode的過程。

BitCode是什麼

Bitcode is an intermediate representation of a compiled program. Apps you upload to iTunes Connect that contain bitcode will be compiled and linked on the store. Including bitcode will allow Apple to re-optimize your app binary in the future without the need to submit a new version of your app to the store.


Xcode hides symbols generated during build time by default, so they are not readable by Apple. Only if you choose to include symbols when uploading your app to iTunes Connect would the symbols be sent to Apple. You must include symbols to receive crash reports from Apple.

其大概意思是Bitcode類似於一箇中間碼,被上傳到applestore之後,蘋果會根據下載應用的使用者的手機指令集型別生成只有該指令集的二進位制,進行下發。從而達到精簡安裝包體積的目的。

23.png

一點編譯原理

為了更好的理解什麼是bitcode,我們簡短的看一下編譯器編譯的過程:

  1. Lexer :讀入原始檔,並將其轉化成字元流

  2. Parser :將字元流轉換成AST(抽象語法樹)

  3. Semantic Analysis: 對輸入的AST進行語法檢查。

  4. Code Generation: 程式碼生成,將AST轉換成低層次的IR指令

  5. Optimization: 分析IR指令,將其中潛在會拖慢執行速度的指令幹掉。

  6. AsmPrinter: 通過IR(中間碼)生成特定CPU架構的彙編程式碼

  7. Assemble: 將彙編程式碼轉化成二進位制

  8. Linker: 通常程式會引用其他的二進位制檔案(.a或者framework),但是這些連結在程式中沒有正確的地址,只是個佔位符。Linker的工作就是給這些佔位符正確的地址。

一般情況下,在真實的編譯器構架那種,會將上述過程分成前端和後端兩部分來處理:

7df22103jw1eyd62a1opyj21f816sn5d.jpg

在前後端之間傳遞的就是IR(中間碼),而bitcode就是一種特殊形式的中間碼。原本前後端的工作都是在本地LLVM中完成,雖然Apple沒有給出具體的Bitcode實現,但是通過他們的文件可以猜測,是將一部分後端的工作移到了伺服器進行。從Xcode上傳IR到伺服器,伺服器來真對不同的機型進行後續操作。從而達到真對不同機型生成對應指令集的二進位制,而減小報體積的目的。

開啟bitcode設定

實際上在Xcode 7中,我們新建一個iOS程式時,bitcode選項預設是設定為YES的。我們可以在”Build Settings”->”Enable Bitcode”選項中看到這個設定。

不過,我們現在需要考慮的是三個平臺:iOS/Mac OS/watchOS。

  • 對應iOS,bitcode是可選的。

  • 對於watchOS,bitcode是必須的。

  • Mac OS不支援bitcode。

如果我們開啟了bitcode,在提交包時,下面這個介面也會有個bitcode選項:

012.png

但是如果其中包含第三方庫,不支援bitcode時候。需要將”Enable BitCode”設定成NO。而且這個選項是,只要有一個第三方庫不支援,就不能開的。否則連線錯誤。

確保打包的時候使用的是fembed-bitcode, 而不是fembed-bitcode-maker

You should be aware that a normal build with the -fembed-bitcode-marker option will produce minimal size embedded bitcode sections without any real content. This is done as a way of testing the bitcode-related aspects of your build without slowing down the build process. The actual bitcode content is included when you do an Archive build.

  • fembed-bitcode-maker:只是簡單的標記一下在archive出來的二進位制中bitcdoe所在的位置。

  • fembed-bitcode: 真的會生成bitcode指令,並且嵌入到二進位制中,這個設定不止要在app中設定,同樣你也必須在編譯靜態連結庫的時候使用。而且需要主題的是該引數系統只預設在archive模式下會新增

需要注意的是bitcode只預設在archive下編譯。在debug和release下並不會。

如果您開發的是app那麼走正常的打包archive流程就好了。如果你正在開發.a靜態庫或者framework,請注意打包方式設定為archive,或者在打包指令碼中加入-fembed-bitcode引數。如果需要的話,需要在Build Settings中開啟 DEPLOYMENT_POSTPROCESSING=YES,設定Strip Style為debugging。

檢測是否開啟Bitcode

當開啟bitcdoe選項之後,我們可以使用otool工具來檢查二進位制檔案中是否包含bitcode段。

針對於靜態連結庫.a檔案

otool -arch armv7 -l xxxx.a | grep __bitcode | wc -l

如果是當前庫支援.a檔案則會輸出一個數字
7df22103jw1ey7d1wkb9aj21a7032gmo.jpg

如果不支援bitcode則不會出現該數字。

上述命令只檢查了armv7架構,同時,也必須使用改指令檢查其他的指令集是否包含bitcode如:arm64,armv7s等等

檢查app或者framework中是否包含bitcode

由於app中二進位制和framework中二進位制檔案與.a檔案存在差異,因為需要檢查的是__LLVM段,當出現該段的時候,則表示支援bitcdoe,否則不支援。

otool -l xxxx | grep __LLVM | wc -l

這裡otool有個bug,當你的framework使用過lipo命令,進行拆解和合並之後,需要指定指令集進行檢查才可以。

otool -arch armv7 -l xxxx | grep __LLVM | wc -l

BUT, 上述檢查過了之後,也不一定是真的支援bitcode,在實際的測試中,發現上述檢測命令通過之後,某個使用的第三方庫,依然報錯不支援bitcode。因而最終結果,還是需要以是否能夠連線成功為準。重要事情說三遍,上述網上流傳的檢測方法只做參考,最終還是要以實際效果為準。

最終結果檢查

如果您是一個APP,可以直接進行Archive打包,如果是一個庫,則建議建一個Demo工程進行打包,記得要開啟bitcode設定。

CheckPoint1 連線是否報錯

如果有任何一個庫沒有開啟bitcode連結,將會出現類似下方的錯誤。只要連結過了,那麼恭喜了,基本上是OK了。 
7df22103jw1eyc7gbmexbj21fy04o7as.jpg

CheckPoint2 檢查最終效果

使用開發模式匯出ipa

03.jpg

04.jpg

選擇出包的方式

這裡建議使用第二種,生成針對具體機型的包

05.jpg

出現了,Compiling Bitcode,這個過程!!!!!

06.jpg

最終結果

在最後輸出的檔案中,你能夠看到一個App Thinning的結果,裡面有針對各個機型的ipa包。

07.jpg

在App Thinning Size Report中能夠明顯看到,由於使用了bitcode等技術之後,所帶來的收益:

App Thinning Size Report for All Variants of Black
Variant: Black-iPad (4th generation)-etc.ipa
Supported devices: iPad (3rd generation) and iPad (4th generation)
App + On Demand Resources size: 368 KB compressed, 737 KB uncompressed
App size: 368 KB compressed, 737 KB uncompressed
On Demand Resources size: Zero KB compressed, Zero KB uncompressed
....