ほとんどのUNIX系OSにおけるCライブラリはAutotoolsを使って開発されています(./configure && make install
の手順でビルドする)。
普通に./configure && make install
すると実行している環境(MacやLinux)用のバイナリが生成されますので、そのままではiOSで利用できません。
iOSで使用できるようにするにはiOS環境用にビルド、いわゆるクロスコンパイルする必要があります。
Autotools(./configure
)ではクロスコンパイルのことが初めから考慮されていてそのための機能がサポートされているので、./configure
の設定を正しくできれば、意外と簡単にさまざまなCのライブラリをiOS上で動くようにビルドできます。
設定について
iOSではデバイスとシミュレータでCPUアーキテクチャが異なるのでそれぞれのアーキテクチャのバイナリをビルドします。
デバイス用にビルドするときの./configure
の例
./configure \ --host=x86_64-apple-darwin \ CC=`xcrun -find clang` \ CFLAGS="-O3 -arch armv7 -arch armv7s -arch arm64 -isysroot `xcrun -sdk iphoneos --show-sdk-path` -fembed-bitcode -mios-version-min=8.0" \ CXX=`xcrun -find clang++` \ CXXFLAGS="-O3 -arch armv7 -arch armv7s -arch arm64 -isysroot `xcrun -sdk iphonesimulator --show-sdk-path` -fembed-bitcode -mios-version-min=8.0" \ --prefix="$TARGETDIR_IPHONEOS" \ --disable-shared --enable-static
シミュレータ用にビルドするときの./configure
の例
./configure \ --host=x86_64-apple-darwin \ CC=`xcrun -find clang` \ CFLAGS="-O3 -arch i386 -arch x86_64 -isysroot `xcrun -sdk iphonesimulator --show-sdk-path` -fembed-bitcode-marker -mios-simulator-version-min=8.0" \ CXX=`xcrun -find clang++` \ CXXFLAGS="-O3 -arch i386 -arch x86_64 -isysroot `xcrun -sdk iphoneos --show-sdk-path` -fembed-bitcode-marker -mios-simulator-version-min=8.0" \ --prefix="$TARGETDIR_IPHONESIMULATOR" \ --disable-shared --enable-static
--host
はクロスコンパイル(ビルド環境と実行環境が異なる)を有効にするために必要なオプションで、ビルドしたバイナリが実行される環境を指定します。
CC
はCコンパイラの指定、CFLAGS
はCコンパイラのオプションです。CXX
、CXXFLAGS
はC++コンパイラとコンパイラオプションの指定です。
デバイス用のビルドとシミュレータ用のビルドではアーキテクチャ(-arch
オプション)とシステムルート(-isysroot
オプション)、ビットコードの埋め込み方(-fembed-bitcode
または-fembed-bitcode-marker
)、Deployment Target(-mios-version-min
または-mios-simulator-version-min
)が異なります。
--prefix
はmake install
したときのバイナリのインストール先を指定します。iOS用にライブラリをビルドする際は、デバイス用とシミュレータ用の2種類のバイナリを生成する必要があるので、続けてビルドした際に上書きされてしまわないようにそれぞれ別のディレクトリを指定しておくと便利です。
--disable-shared
はダイナミック(共有)ライブラリ(*.dylib)を生成しないオプション、--enable-static
は静的ライブラリを生成するオプションです。静的ライブラリの方が使い勝手がいいので私はこちらを指定することが多いですが、必要に応じて使い分けてください。
もし、watchOSやtvOS用のビルド(制限が強いのでこちらはそのままビルドできることは少ないですが)をしたい場合は、この要領でアーキテクチャやシステムルートを、そのデバイス向けに変更します。
実践(secp256k1をiOS用にビルド)
それでは試しにCで書かれたオープンソースのライブラリをiOS向けにビルドしてみましょう。
例として、Bitcoinで使われている楕円曲線暗号 secp256k1
のライブラリをiOSで使えるようにビルドしてみましょう。
Autotoolsがインストールされていない場合は先にautoconf
とautomake
をインストールします。
$ brew install autoconf automake
リポジトリをクローンします。
$ git clone https://github.com/bitcoin-core/secp256k1 src
クローンしたリポジトリに移動します。
$ cd src
autoreconf
コマンドでconfigure
スクリプトを生成します。
$ autoreconf -if
成果物を保存するためのディレクトリを作っておきます。このディレクトリを--prefix
オプションで指定します。
$ mkdir -p build/iphoneos
iOSデバイス向けの設定で./configure
を実行します。
$ ./configure \ --host=arm-apple-darwin \ CC=`xcrun -find clang` CFLAGS="-O3 -arch armv7 -arch armv7s -arch arm64 -isysroot `xcrun -sdk iphoneos --show-sdk-path` -fembed-bitcode -mios-version-min=8.0" \ CXX=`xcrun -find clang++` \ CXXFLAGS="-O3 -arch armv7 -arch armv7s -arch arm64 -isysroot `xcrun -sdk iphonesimulator --show-sdk-path` -fembed-bitcode -mios-version-min=8.0" \ --prefix="$PWD/build/iphoneos" \ --disable-shared --enable-static
特にエラーがなければ続けて、make install
を実行します。
$ make install
成功したらbuild/iphoneos/lib/
以下のlib
ディレクトリにlibsecp256k1.a
が生成されています。
正しくiOSデバイス向けにビルドされているか、アーキテクチャを確認します。
$ xcrun lipo -info build/iphoneos/lib/libsecp256k1.a
このコマンドの出力は下記のようになります。iOSデバイス用のビルドなのでARMアーキテクチャ用のバイナリが出力されています。
Architectures in the fat file: build/iphoneos/lib/libsecp256k1.a are: armv7 armv7s arm64
続けてシミュレータ用のビルドを作成します。
成果物が上書きされないように、出力先のディレクトリを別名で作成します。
$ mkdir -p build/iphonesimulator
シミュレータ用のビルド設定にして./configure
をやり直します。
$ ./configure \ --host=x86_64-apple-darwin \ CC=`xcrun -find clang` \ CFLAGS="-O3 -arch i386 -arch x86_64 -isysroot `xcrun -sdk iphonesimulator --show-sdk-path` -fembed-bitcode-marker -mios-simulator-version-min=8.0" \ CXX=`xcrun -find clang++` \ CXXFLAGS="-O3 -arch i386 -arch x86_64 -isysroot `xcrun -sdk iphoneos --show-sdk-path` -fembed-bitcode-marker -mios-simulator-version-min=8.0" \ --prefix="$PWD/build/iphonesimulator" \ --disable-shared --enable-static
$ make install
ビルドが成功したら、build/iphonesimulator/lib
にバイナリが生成されています。同様にアーキテクチャを確認してみましょう。
xcrun lipo -info build/iphonesimulator/lib/libsecp256k1.a
このコマンドの出力は以下のようになります。
Architectures in the fat file: build/iphonesimulator/lib/libsecp256k1.a are: i386 x86_64
デバイス用のバイナリとシミュレータ用のバイナリをそれぞれ生成しました。 このままでも工夫すれば使えますが、不便なので2つのバイナリを結合した1つのファイル(Fatバイナリ)を作ります。
Fatバイナリの生成は、lipo
コマンドを使います。
$ xcrun lipo -create "build/iphoneos/lib/libsecp256k1.a" \ "build/iphonesimulator/lib/libsecp256k1.a" \ -o "build/libsecp256k1.a"
xcrun lipo -info build/libsecp256k1.a
このコマンドの出力は次のようになります。ARMアーキテクチャとIntelアーキテクチャの両方が1つのバイナリに含まれています。
Architectures in the fat file: build/libsecp256k1.a are: armv7 armv7s i386 x86_64 arm64
後は、ライブラリをリンクし、ヘッダファイル(include
ディレクトリにコピーされています)を適切に参照すればSwift/Objective-Cからこのライブラリを使用できます。
Swiftで使う場合にはアプリで使う場合(ブリッジヘッダ)とライブラリで使う場合(Module Map File)で多少利用方法が異なるので、実際にアプリ・ライブラリに組み込む方法は別の記事で解説します。
まとめ
このように、多くのCのライブラリは、iOS向けに書かれていないライブラリでも、簡単にiOS向けにビルドして使用できます。
私は上記で説明したような手順をスクリプトにまとめて、それぞれのライブラリごとの微修正して使用しています。
- BitcoinKit/build_secp256k1.sh at master · yenom/BitcoinKit · GitHub
- swift-magic/build_deps.sh at master · kishikawakatsumi/swift-magic · GitHub
OpenSSLなどAutotoolsを使用していないライブラリも存在しますが、基本的な考え方は同様です。そのビルドシステム(多くは単なるShellスクリプト)にアーキテクチャなどiOS用にビルドするためのコンパイラオプションを渡します。
下記の例は、OpenSSL(のlibcrypto)をiOS用にビルドするためのスクリプトの例です。OpenSSL のビルドスクリプトに環境変数を通じてコンパイラオプションを渡しています。
BitcoinKit/build_crypto_impl.sh at master · yenom/BitcoinKit · GitHub