iOS靜態庫相關-封裝lib

Library介紹

基本知識

在實際的編程過程中,通常會把一些公用函數製成函數庫,供其它程序使用,一則提搞了代碼的複用;二則提搞了核心技術的保密程度。

Library使用的兩種方式:封裝lib.a和直接引用lib工程。

一、封裝.a文件

直接封裝lib.a,向使用者提供頭文件列表。使用者引用頭文件並且使用其中方法,但是看不到實現文件的內容。這種方式每當靜態庫函數需要修改時就必須重新生成lib.a提供給使用者更換,比較麻煩,但有助於保密。

製作靜態庫

New Project -> iOS Library ->Cocoa touch Static Library 這樣就新建了一個靜態庫的工程,將你要打包成lib的.m,.h放到class目錄下面,然後選擇build就可以了. 

Bulid之後,在工程目錄下Produces文件夾下可以看到生成的.a文件引用,右鍵,show in finder可以看到.a文件。

要注意Build時的選項:

<1>iOS Device編譯出來的是在Debug-iphoneos目錄下,真機使用,終端,在該目錄下使用lipo -info **.a 可以查看你到文件類型爲armv7等ARM架構。

<2>Simulator時編譯出來的是在Debug-iphonesimulator目錄下,模擬器使用,終端查看類型顯示爲i386架構。

可以使用lipo命令生成一個通用二進制lib.a lipo -create **/**.a **/**.a -output **/**.a 生成一個兼容兩種類型的.a文件。方法雖好,但是包大小會增加。

<3>.a文件所在木有沒有include文件夾,如何設置?

在項目Target設置頁面選擇Build Phases,然後選中裏面的某一項(必須選擇一下,否則後面的操作不能進行),然後菜單欄Editor->add Build Phases->Add Copy Build Phases即可生成Copy Files,在裏面配置生成的路徑及需要生成的頭文件,選擇Product Directory,路徑例如:include/$(PRODUCT_NAME),然後Clean-Build即可發現.a文件所在目錄多了一個include目錄,包含了配置好的頭文件。

使用靜態庫

在需要調用靜態庫的工程的目錄下通過右鍵點 Frameworks->Add->Existing Files..添加之前創建的.a靜態庫文件,然後在需要調用靜態庫的函數的文件裏,import進來靜態庫中.h頭文件,這樣就可以使用靜態庫裏的函數了。(此處可以做一個頭文件包含靜態庫中所有的頭文件,只需聲明這一個頭文件就可以使用所有的相應頭文件的方法)

問題及注意事項

0. .a文件路徑:/Users/user/Library/Developer/Xcode/DerivedData/****/Build/Products/

不同模式下可以生成不同類型的.a文件 真機/模擬器與Debug/Release選項公交叉成4種.a文件。     

1.打包分清楚是debug與Release的。

選擇debug與Release在Xcode工具欄的Product選項現則Scheme->Edit Scheme.然後爲各個運行模式選擇選項。    

2.分清楚lib是i386(真機)或者ArmV7(模擬器)模式

終端下使用命令 lipo -info libPrint.a 可以查看.a的屬性。如結果:libPrint.a is architecture(構建): armv7 

3.把真機運行和模擬器運行的.a文件合併生成通用的.a文件,完成通用的靜態庫。

終端使用命令 lipo -create 真機.a路徑 模擬器.a路徑 -output 目標路徑(如/users/user/desktop/***.a)。然後info查看合併後.a的信息就會發現它已經同時具備了armv7和i386的條件

4.在Build Phases->Compile Source中的文件,表示這些代碼會被編譯進lib中,你可以刪掉你不希望被編譯的。

5.標準的Unix引入慣例是一個include文件夾,用來存放所有引用的外部頭文件,一個lib文件夾用來存放庫文件(.a)。這種文件夾結構這是一種慣例,並不強制。

附:自動生成通用lib.a

生成通用二進制lib.a需要lipo,一個命令行工具,它允許在通用文件上執行操作(類似於創建通用二進制, 列出通用文件內容等等)。本教程中使用lipo的目的是聯合不同架構的二進制文件到單個輸出文件中。你可以直接在命令行中使用lipo命令,但在本教程中你可以讓Xcode執行一段創建通用庫的命令行腳本來爲你做這件事。

Xcode中一個集合目標可以一次構建多個目標,包括命令行腳本。在選中lib工程文件,點擊+號增加新的Target,選擇iOS/Other並點擊Aggregate,如下圖:

將目標命名爲UniversalLib,確保選中你的lib工程中。然後選擇UniversalLib Target。切換到Build Phases標籤;點擊+號增加Add Run Script Build Phase,如下圖:

現在你需要設置腳本項。展開Run Script模塊,在Shell行下粘貼如下代碼:

# define output folder environment variable

UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

TARGET_NAME=ProjectName

# Step 1. Build Device and Simulator versions

xcodebuild -target ${TARGET_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"

xcodebuild -target ${TARGET_NAME} -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"


# make sure the output directory exists

mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"


# Step 2. Create universal binary file using lipo

lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib${PROJECT_NAME}.a"


# Last touch. copy the header files. Just for convenience

cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "${UNIVERSAL_OUTPUTFOLDER}/"

注意:修改其中的TARGET_NAME=ProjectName爲你的lib工程名。

代碼並不十分複雜,它是這樣工作的:

UNIVERSAL_OUTPUTFOLDER 包括了通用二進制包將要被存放的文件夾:“Debug-universal”

Step 1. 第2行執行了xcodebuild並命令它構建ARM架構的二進制文件。

下一行再次執行了xcodebuild命令並在另一個文件夾中構建了一個針對Inter架構的iPhone模擬器的二進制文件,在這裏關鍵參數是-sdk iphonesimulator -arch i386。

Step 2. 現在已經有了2個.a文件分別對應兩個架構。執行lipo -create,用它們創建出一個通用二進制。

最後一行的作用是複製頭文件到通用構建文件夾的外層。

現在你已經準備好構建一個靜態庫的通用版本。

選擇UniversalLib然後Run,你就會在產品目錄發現一個新的文件夾Debug-Universal或者Release-Universal,裏面包含了合併之後的lib.a以及頭文件。

詳細操作參考鏈接:http://www.cocoachina.com/applenews/devnews/2013/1204/7468.html

二、引用lib工程

靜態庫工程被包含在項目工程中或者與項目工程放在同一個WorkSpace中,做成聯調靜態庫。這種方式的靜態庫工程與項目工程一起使用,故沒有對Libray中的代碼進行封裝,可以查看修改。

創建聯調工程   

1.在工程的Targets上右鍵.Add -> New Target -> Static Library 比如我們建了一個LibExample的target。這樣是一個工程包含多個Target的形式,沒有新建Lib工程。創建好Target之後你會發現原來的工程下面會多出幾個文件夾:LibExample和LibExampleTest,用來存放跟Library相關的代碼。

另外,也可以直接在原工程上右鍵新建一個lib工程,或者在工程中右鍵add Existing File..增加已經存在的lib工程進來(不要選擇copy to folder)。這種形式是一個工程下面包含一個Lib工程。

2.在LibExample的目錄中增加你需要加入的.h.m文件,然後查看在Build Phases->Compile Source中的文件,表示這些代碼會被編譯進lib中,你可以刪掉你不希望被編譯的,增加你想要編譯進去的文件。

3在工程的target上雙擊,targets->Build Phases裏面Target Dependencies裏面增加lib工程的target,這樣編譯工程時也會編譯lib工程生成lib.a文件。同時在Link Binary With Libraries中增加選擇lib.a,表示對library庫的引用。 

4.使用Lib工程而非Target時,需要修改工程的Scheme->Build中增增加Lib工程的Target。這樣才能編譯工程的同時編譯lib工程,生成.a。

5.引用lib頭文件:在項目文件工程文件的target的build Setting->Header Search Paths中增加頭文件路徑(../文件名(lib工程文件名/ 例如../MyLibPrint/),這個路徑適應於lib工程與項目工程在同一目錄),選擇成遞歸類型。

6.最後在工程中可以使用lib.a中的文件了,使用時引用一下lib工程的頭文件,如果不報錯說明頭文件引用成功,然後就可以使用了。

Lib相關部分錯誤信息

1.undefine symbols for architecture i386 錯誤。

其實這個錯誤原因很簡單,就是因爲,我們用錯了編譯出來的libUITab.a lib,

在模擬器裏面,我們需要的是基於i386構架編譯的static lib,但是這個a文件,大家還記得前面說的arm6 arm7構架的麼。這個a其實是在iphone這個arm構架上運行的代碼。

那如何編譯i386的庫呢?運行之前選擇Print>IOS Device,將這個iOS Device修改成iPhone5.0 Simulator。在進行編譯,這樣就可以編譯出i386下面的庫。

下面最多有四個文件夾分別命名爲:Debug-iphoneos/Debug-iphonesimulator/Release-iphoneos/Release-iphonesimulator這四條目錄每個目錄下同樣也有一個libPrint.a文件。Release-iphoneos裏面的是基於arm6 arm7編譯出來的庫文件。Release-iphonesimulator文件夾下面的是基於i386編譯出來的文件。

2.在編譯RegexKitLite的時候,報錯如下:

在項目的編譯設置中找到Other Linker Flags,然後在後面字段空白處雙擊,添加“-licucore”就可以了,引用正則框架必須打開此開關。-licucore,注意不要打錯,打錯了會報錯誤:clang: error: no such file or directory: ‘-licucore'

對64bit的支持

Xcode5.1生成的項目,默認的便已選擇是支持64bit編譯的,可以查看工程的build Setting中的Architectures選項,包含了arm64的設置。

項目支持arm64要求項目中所引用的lib.a和.framework文件均支持arm64,否則就會報錯。

ld: symbol(s) not found for architecture x86_64

當然,可以直接設置項目不支持x86_64。

  • build Settings中在Architectures選項設置爲armv7和armv7s
  • Valid Architectures中刪除arm64

但是能兼容肯定是更好的:

  • lib或者framework工程創建是需要包含對arm64的支持。查看上述選項如果沒有需要添加。
  • 使用lipo -info查看是否包含x86-64,判斷是否成功。

使用本文中的通用工程生成時,在模擬器編譯時需要修改爲如下,

xcodebuild -target ${TARGET_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 -arch x86_64 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"

增加ONLY_ACTIVE_ARCH=NO和-arch x86_64。然後編譯即可生成符合要求的.a。

其他參考

Library官方文檔:https://developer.apple.com/library/ios/technotes/iOSStaticLibraries/Introduction.html#//apple_ref/doc/uid/TP40012554-CH1-SW1

XCode的各種參數配置參考:http://www.cnblogs.com/xiaodao/archive/2012/03/28/2422091.html

發佈了32 篇原創文章 · 獲贊 5 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章