編譯器之打包動態/靜態庫

hivo3646 8年前發布 | 10K 次閱讀 編譯器 動態庫 iOS開發 移動開發

一、簡介

I. 庫的類型分類

靜態庫

  • 以 .a 或 .framework 為文件后綴名
    .a 是一個二進制文件,不能直接拿來用,使用時需要 .a 文件 + 頭文件 + 資源文件
    靜態庫打包時, 只能打包代碼 ,圖片文件、本地 JSON 文件和 xib 等資源文件無法打包進去
  • 靜態庫 連接時 完整的復制到可執行文件中,多個文件使用,多份拷貝
  • OC 建議使用靜態庫,OC 使用動態庫審核可能會不通過
  • 靜態庫無法再包含其他的 .a 靜態庫。 只能把源碼放進去一起編譯

動態庫

  • 以 .dylib 或 .framework 為文件后綴名「Xcode7 后 .dylib 變為 .tbd 文件」
    .framework 文件,能直接拿來用。 .framework 文件 = 二進制文件(.a 文件 + .h 文件) + 資源文件
    .tbd 文件,只是一個文本文件,其中包含架構信息,以及在真實運行時候二進制所在的位置,以及包含了動態庫的符號表還有類的一些信息,這些信息在編譯階段足夠了。「減少了所有設備 SDK 二進制動態庫的體積」
  • 動態庫 運行時 動態加載到內存,只加載一次,多個文件公用,節省內存
  • Swift 只能使用動態庫,不支持靜態庫
  • 大部分第三方庫就是動態庫,可以暴露出來,放在源碼的外部引用使用
  • 動態庫的特性使得 軟件版本實時模塊升級 、應用插件化、etc

II. iOS 設備的 CPU 架構

iOS 庫的打包,根據 CPU 架構的不同而不同

架構不同, 不能編譯通過

模擬器的 CPU 架構

  • i386:iPhone 4s ~ 5
  • x86_64:iPhone 5s ~ 7 Plus

真機的 CPU 架構

  • armv6:iPhone、iPhone 2、iPhone 3G、iPod Touch「第一代」、iPod Touch「第二代」
  • armv7:iPhone 3Gs、iPhone 4、iPhone 4s、iPad、iPad 2
  • armv7s:iPhone 5、iPhone 5c 「靜態庫只要支持了 armv7,就可以在 armv7s 的架構上運行」
  • armv64:iPhone 5s、iPhone 6、iPhone 6 Plus、iPhone 6s、iPhone 6s Plus、iPad Air、iPad Air2、iPad mini2、iPad mini3

二、打包靜態庫

I. .a 文件 靜態庫打包

  1. 創建靜態庫的工程

    創建后執行 運行 或 編譯 ,都可以生成靜態庫「保存在項目的 Products 中」

  1. 通過在不同架構的設備下 編譯/運行 生成支持不同架構的靜態庫

  1. 在 編譯/運行 時, 所有項目 都可以設置是 Debug 還是 Release

  1. 設置庫的接口 頭文件

  1. 通過設置不僅在當前運行的 CPU 架構上,適配所有的機型號架構

    一般 debug = no,release = yes 為了 debug 的時候編譯更快「只編譯連接當前的 CPU 架構所用的包」

    可以控制 測試版本 和 發布版本 是否都不僅僅能在真機上使用

II. .framework 文件 靜態庫打包

  1. 前三步和 在 .a 文件 打包方式一致

  2. 設置庫的接口 頭文件

  1. 設置打包的是 靜態庫,因為動態庫也可以以 framework 的形式存在

    設為Static Library「這個默認選項是動態的」

III. 使用靜態庫

1. 防止項目中的文件和 靜態庫的同名文件在運行時會覆蓋,只保留一張圖片

  • 把圖片文件單獨的放在一個 .bundle 文件中「一般 .bundle 的名字和 .a 或 .framework 的名字相同」
  • .bundle 文件制作方法:將文件夾,重命名為 XXX.bundle
    同理,其他資源文件也放在一個 .bundle 中

2. 在使用 category 靜態庫的工程中,調用方法時,會出現找不到該方法的運行時錯誤: selector not recognized

原因:

  • Unix 的標準靜態庫實現和 Objective-C 的動態特性之間有一些沖突
  • Objective-C 沒有為每個函數定義鏈接符號,它 只為每個類創建鏈接符號
  • 當在一個靜態庫中使用類別來擴展已有類的時候,鏈接器不知道如何把類原有的方法和類別中的方法整合起來

解決辦法:

  • 在使用靜態庫的工程中配置 other linkerflags 的值為 -ObjC 如果還崩潰,在添加 -all_load 「或者 -force_load 」
  • all_load 作用于所有的庫,而 -force_load 后面必須要指定具體的文件
    這樣,會將靜態庫中所有和對象相關的文件都加載進來

3. 避免暴露過多的 .h 文件

使用

  • 在靜態庫的內部創建一個 .h 文件「一般這個.h文件的名字和靜態庫的名字相同」
    然后把所有需要暴露出來的 .h 文件名都集中放在這個 .h 文件中,只需要把這個 .h 暴露出來
  • 一般這個總頭文件內部引入其他頭文件的格式為
    #import <framework名字/其他頭文件.h> ,這是以調用這個庫的 項目的角度來寫的

搜索頭文件

  • Header Search Paths

    系統的搜索路徑,用來引入項目中 沒有添加 的 header 文件

    通過 #import <名稱.h> 來引入

  • User Header Search Paths

    用戶的搜索路徑,用來引入項目中的 已添加 的 header 文件

    通過 #import <名稱.h> 或 #import "名稱.h" 來引入

  • Always Search User Paths

    Header Search Paths 作為系統級別路徑一定會被搜索

    設 Always Search User Paths 為 YES,編譯器會先搜索 User Header Search Paths 路徑下的目錄

    設 Always Search User Paths 為 NO,編譯器不會搜索 User Header Search Paths 路徑下的目錄「默認」

  • 設置格式舉例: $(SRCROOT)/項目名稱/AppDelegate.h
    $(SRCROOT) 宏和 $(PROJECT_DIR) 宏都指 xxx.xcodeproj 所在的 父目錄 ,新建項目后的目錄為:

  • Project的 Building Settings 中得設置 默認 并不被 Targets 繼承

    只有 Targets 的設置加入了 $(inherited) 時才被繼承,添加目錄的時候寫上 $(inherited) 就表示從 frameworks 里面讀取

  • 設置查找路徑的參數

    recursive:遍歷該目錄,編譯的時候在找庫的路徑的時候,會遍歷該目錄下的所有子目錄的庫文件

    non-recursive:不遍歷該目錄「默認,推薦使用,可減少編譯速度」

4. 拖拽項目/將項目當做靜態庫處理

  • 給當前項目在 Link Binary With Libraries 中添加拖拽項目的 庫文件
  • 如果當前的 Target 需要依賴其他庫文件,在 Target Dependencies 中添加所需的庫文件
  • 如果庫文件在 Link Binary With Libraries 中已經添加 「必要」 ,但也可能需要在 Target Dependencies 中再次添加 「非必要」

5. 其他

  • 查看靜態庫所支持的 CPU 架構

    在命令行找到靜態庫所在的文件夾,執行 lipo -info 靜態庫文件名 命令

  • 合并靜態庫

    在命令行找到靜態庫所在的文件夾,執行 lipo -create 靜態庫1 靜態庫2 -output 新靜態庫名稱.a 命令

三、打包動態庫

1. 制作、編譯過程與靜態庫相同

2. 在 Embedded Binaries 中添加動態庫

Paste_Image.png

3. 合并動態庫文件

合并動態庫文件并非合并的是 .framework 文件,而是其中的二進制代碼文件

4. 動態庫的使用注意

I. 自定義的 .a 靜態庫,不可以包含動態庫

II. 自定義的 .framework 靜態庫,可以包含動態庫文件

繞過 Xcode 的 UI 界面來連接動態庫,步驟如下

  • 項目中不需要引用連接的動態庫「.tbd 的動態庫」

  • 通過格式: -l<library_name> 添加動態庫,例:添加 libiconv.tdb 記為 -liconv

缺陷

  • 雖然自定義的靜態庫中已經導入了動態庫 X.tbd ,但是,當自定義的 framework 的靜態庫被調用時,可能需要再次導入動態庫 X.tbd 到當前項目中

 

來自:http://www.jianshu.com/p/543965d30c16

 

 本文由用戶 hivo3646 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!