Xcode 5 で作る Universal Static Library
なぜ Static Library なのか
全てのソースコードを GitHub にアップロードし、Cocoapods に podspec をマージしてもらって、
他のデベロッパー達とのコラボレーションを楽しむのが現在の iOS 界隈の Social Coding の主流になっているのかなと思います。
しかし、以下のような要因などによっては上記のようなアクションを取り辛い場合があると思います。
コード自体は自由に使ってもらいたいが、実装ファイルは見られたくない
ファイルが山ほどあるので、それらを使いやすくパッケージ化したうえで共有したい
そんなときに有効な手段の一つとなるのが Static Library です。
Static Library は指定した header file とコンパイル済みの archive file (.a 拡張子)がインターフェースとなります。
そのため、実装部分が利用者には見えなくなり隠蔽できるうえ、利用者にも扱いやすくなります。
プロジェクトの作成
では実際に Xcode 5 を用いて Static Library を作成してみましょう。
まずは Static Library 作成用のプロジェクトを新規に作成します。
Xcode を起動し、メニューから File -> New… -> Project を選択します。
左ペインの iOS セクションから Framework & Library を選択し、以下の Cocoa Touch Static Library を選択します。
適当な Product Name を付けたら完成です、早速ビルドしてみましょう。
Product フォルダに libProject.a という archive file ができていると思います。
これを選択状態にし、 Show in Finder を選択して実際にどんなファイルが生成されているかを確認してみましょう。
Product フォルダ内にある lib
それを選択して右クリックメニューから Show in Finder です。
上記でも説明した、header file と archive file の2種類が生成されています。
手順としてはこれだけです。
あとは生成された Static Library を、利用したいプロジェクトに追加し適切にリンクするだけです。
Universal Library
実は上記の手順だけだと、一つ問題があります。
このままだとビルドした時に選択している Architecture 用にコンパイルされた Static Library しか生成されないからです。
例えば iOS Simulator を選択してビルドした Static Library は iPhone など実機のArchitecture とは異なるため使用できません。
Xcode が Universal Library 用のテンプレートなりを用意してくれても良い気がするのですが、そんなものはありません。
なので lipo コマンドを使い、各 Architecture 毎に生成した Static Library を結合する処理を追加します。
手順をみていきましょう。
まず先ほど作成した Static Library 作成用プロジェクトに Aggregate ターゲットを追加します。
Aggregate ターゲットは、複数のターゲットを一度にビルドしてくれ、コマンドラインのスクリプトを記述できるターゲットです。
ソースコードをコンパイルしたり、ライブラリをリンクするなど普通のターゲットとは違うので、ターゲット同士を結合するための非常にシンプルかつ透明性のあるターゲットという位置付けになっています。
ターゲットが作成できたら、下記のようにメニューを辿ってスクリプトを追加するための項目を以下のようにして追加します。
スクリプトは以下のようなものを追加しましょう。
# Universal Libraryを配置する場所 UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal # 実機用ライブラリ生成 xcodebuild -target TestTarget ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}” # iOS Simulator用ライブラリ生成 xcodebuild -target TestTarget -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" # Universal Library用フォルダ生成 mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" # lipo コマンドで実機・iOS Simulatorライブラリを結合 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" # lipoコマンドにより生成されたUniversal Libraryをコピー cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "${UNIVERSAL_OUTPUTFOLDER}/"
簡単に言うと、iOS Simulator 向けの i386, iOS Device の向けの arm の Architecture を生成し、それらを lipo で結合してアウトプットを作っています。
これでビルドするターゲットを Aggregate に設定すれば Universal ビルドを作成出来るようになります。
終わりに
ここまで読んで頂いた方は気付いたかもしれませんが、私たちが SDK 普段使っているなどで使用している Static Library は凄い簡単に作れます。
次回はもう一つ先を行った Framework の作り方を書こうと思います。