開發第三方庫時, 若是沒有進行特殊處理, 很容易把其餘第三方庫的符號暴露出來, 致使連接時產生符號重複. 以下圖所示架構
若是用戶連接了其餘版本的libjpeg, 會由於入口地址不正確讓程序直接崩潰函數
本文就從這個問題入手, 簡要介紹Mac OS X系統下幾個經常使用二進制文件修改工具的使用工具
咱們都知道, 代碼到可執行文件須要通過編譯(compile)和連接(link)兩個主要步驟. 編譯是把程序語言轉換爲機器指令, 這個不在本文的討論範圍.spa
連接是把分塊編譯的對象文件(obj)合併成一個完整的程序, 主要解決函數入口重定向的問題. 其功能主要就是把全部的對象文件打個包, 生成一個導出符號表, 讓其餘程序能夠知道本文件的結構.3d
而對於蘋果系統來講, 豐富的設備包含了多種架構平臺, armv7, arm64, i386, x86_64是最多見的指令集, 一個程序庫爲了兼容各個平臺, 經常要把不一樣平臺編譯的程序合併起來, 生成所謂的胖文件(Fat File), 這樣子開發者就不須要專門準備一套真機版本庫和模擬器版本庫了(在早期, 不少第三方庫確實是提供了不一樣版本的二進制文件來減小庫文件大小).調試
所以對於一個可執行文件, 其實包含了3層結構: Universal Fat File -> Single Architecture Binary File -> Mach-O Object.code
本文將要介紹的lipo, ar, nm, strip, ld等工具的功能就是對這三層結構進行轉換和修改.orm
本文以高德地圖iOS SDK MAMapKit.framework 4.0.3爲例, 演示如何從這個庫文件裏剔除暴露的png符號.對象
lipo是管理Fat File的工具, 能夠查看平臺列表, 提取特定平臺, 從新打包.blog
首先運行 lipo -info MAMapKit
能夠看出這個文件包含了4個平臺的代碼. 接下來的全部操做都是要針對單一平臺進行的, 所以先提取出來armv7平臺,
lipo -thin armv7 MAMapKit -output MAMapKit.armv7
能夠看出單平臺的程序文件要小得多.
接下來咱們來查看一下這個文件的符號表
nm用來顯示一個程序包的符號表, 默認會顯示入口地址, 符號類型, 符號名.
nm -j MAMapKit.armv7 | grep png > symbols 能夠得到全部的libpng導出符號, 存入到symbols文件, 爲接下來的工做作準備. -j 選項控制只輸出符號名.
strip用來刪除程序裏的符號表. -R 用來指定一個要刪除的符號列表, 使用上述生成的symbols文件. 添加 -S 選項來保留其餘符號.
strip -S -R symbols MAMapKit.armv7 -o MAMapKit.armv7.strip
能夠驗證生成的新文件已經沒有了png符號.
咱們用這個方法應用到其餘全部平臺.
咱們用上述方法處理arm64時遇到了問題
這個文件裏的一些符號用做了重定向入口, strip命令不容許刪除, 這時就須要更強力的工具ld登場了. ld 其實蘋果系統下的連接器, 能夠更精確的控制符號表的導出.
ld的操做對象是obj, 所以咱們須要先用到ar打包工具. ar能夠查看一個程序包裏的對象文件列表, 解壓出其中的對象文件並從新打包.
ar -t MAMapKit.arm64
能夠看到整個包就包含了一個主對象文件.
使用 -x 解壓出來, 接下來就要輪到 ld 上場了.
本問題須要的ld功能和strip基本一致, 使用下述命令
ld -x -r -unexported_symbols_list symbols MAMapKit-arm64-master.o -o MAMapKit-arm64-master.o.strip
由今生成對象文件就剔除了png符號表
接下來要作的就是上述逆過程, 對象文件合併成程序文件
ar -r MAMapKit.arm64 MAMapKit-arm64-master.o.strip Pods-MAMapKit-dummy.o
最後是把各個平臺的程序打包成Fat File便可.
2016-09-02 更新
使用 Xcode 編譯選項便可以完成上述任務!
1. Perform Single-Object Prelink
這個參數設置爲 Yes
這一步, 把全部的object文件合併成一個object文件, 至關於進行預編譯
這是最核心的操做, 由於該命令會觸發Xcode調用 ld 命令
2. Single-Object Prelink Flags
這個參數設置 -unexported_symbols_list $(PROJECT_DIR)/symbol.txt
這就至關於給 ld 命令傳遞參數, 正式咱們上文提到的操做
經過這兩個選項的配置, 咱們就在Xcode裏設置好了符號刪除的任務, 不用再在編譯完成後手動刪除.
其餘的一些參數, 好比 Strip Style, 能夠根據須要手動決定, 由於刪除後就不能再斷點調試了!