一般に動的ライブラリを扱う場合には2つの方針があると思います。
- ライブラリはシステムにインストールして、アプリはそれを使う
- ライブラリをアプリ用に用意してまとめて配布する
後者の場合のよろしいやり方について調べたのでまとめました。
構成
コマンドラインアプリと一緒にlibディレクトリを置き、その中にdylibが入っているという構成にします。ファイルをリストすると下記のようになります。
- app_dir/app
- app_dir/lib/libfoo.dylib
- app_dir/lib/libbar.dylib
ライブラリはfooとbarがあって、barはfooに依存しているとします。
ライブラリの本体パスと依存パスの設定
macのdylibはバイナリ内部に自身のパスと依存するライブラリ達のパスが書き込まれています。この自身のパスは下記のようにして得られます。
$ otool -D libfoo.dylib
また、依存するライブラリのパスは下記のようにして得られます。
$ otool -L libfoo.dylib
まず、自身のパスを @rpath
直下の形に書き換えます。
$ install_name_tool -id "@rpath/libfoo.dylib" libfoo.dylib
$ install_name_tool -id "@rpath/libbar.dylib" libbar.dylib
また、依存するライブラリのうち、一緒に配布するものは @rpath
直下を探すように書き換えます。この例ではbarの中にfooへの依存があるのでこれを修正します。コマンドの引数として元々のパスを指定しますが、これは先述の方法で取得した結果を用います。
$ install_name_tool -change "/Users/omochi/temp/libfoo.dylib" "@rpath/libfoo.dylib" libbar.dylib
ここで設定した @rpath
は変数で、アプリが起動する時に変数展開されます。
アプリの実行時rpathの設定
アプリの実行時のrpath変数はビルド設定で指定できます。Xcode > ターゲット設定 > Build Settings > Runpath Search Pathesを下記の値に設定します。
@executable_path/lib
@executable_path
は変数で、アプリ実行時のアプリ自体のファイルパスになります。これにlibを付けておくことで、同じディレクトリにあるlibディレクトリの中からライブラリが探索されます。
アプリのビルド時のライブラリの設定
dylibはxcode上で登録しておき、アプリターゲットに対してリンクされるよう設定しておきます。さらに、ビルド時にアプリと一緒にlibディレクトリを作りその中にコピーされるように、Build PhasesでCopy Filesの設定を作ります。DestinationはProducts Directoryにして、Subpathは lib
にします。そしてdylib全てを登録します。
アプリの状態
rpathの設定内容はアプリバイナリ自体に書き込まれます。また、アプリの依存ライブラリは、リンクしたライブラリに書かれていた、ライブラリ自身のパスが書き込まれます。これらは下記のコマンドで確認できます。
otool -l app
配布
これで、ビルドした際にProductsの中にアプリとlibディレクトリが作られるようになるので、これらをまとめて配布すれば実行が可能になります。