iOSで共有(動的)ライブラリdylibを使う

***未完成記事ですが、個人的に参照しやすいように一時的に公開しています***

 

ベースとなる記事はこちら。

ただし結構古い情報なので、これだけ参考にしても結構つまづきます。

ということで、以下作業メモです。Xcodeのバージョンは5.1.1。

1. ファイルバックアップ

FinderのApplication/Xcode.appに対して右クリック、「パッケージの内容を表示」。以下のファイルを適当なフォルダにバックアップとして残しておく。

  1. Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX Product Types.xcspec
  2. /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX Package Types.xcspec
  3. /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Specifications/iPhone Simulator ProductTypes.xcspec
  4. /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Specifications/iPhone Simulator PackageTypes.xcspec
  5. /Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Specifications/iPhoneOSProductTypes.xcspec
  6. /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Specifications/iPhoneOSPackageTypes.xcspec

2. ファイル編集

1. の1, 3, 5(xxxProductType.xcspec)のファイルを、Xcodeで開く(右クリックで開くアプリを指定)。

1(MacOS) のファイルのitemの中から、Identifierが”com.apple.product-type.library.dynamic”になっているものを探して、そのitemを選択して3(iPhoneOS)にドラッグ(Xcode SpecificationsのArraysの数が一つ増えることを確認)。このとき「書き込み許可がない!」と怒られたら、お手数ですが該当ファイルと、そこにアクセスするまでのフォルダについて、すべて書き込み権限を追加してやってください(Finderで右クリック->「情報を見る」から可能)。無事に追加できたら、File -> Save。

同様に、5(iPhoneSimulator)にも追加。無事に追加できたら、File -> Save。このSaveは二つのファイルを変更してからまとめてSaveしようとすると何故かXcodeが固まったので、別々にSaveしておいた方が安全です。

追加するとこんな感じになります。

 

続いて、1. の2, 4, 6(xxxPackageType.xcspec)のファイルを、Xcodeで開く。

2(MacOS) のファイルのitemの中から、Identifierが”com.apple.package-type.mach-o-dylib”になっているものを探して、そのitemを選択して4(iPhoneOS)にドラッグ。無事に追加できたら、File -> Save。

同様に、6(iPhoneSimulator)にも追加。無事に追加できたら、File -> Save。

こんな感じ。

 

ここまでやったら、Xcodeを再起動。

3. dylibファイルの作成

Xcodeを立ち上げて、Create a new Xcode project-> Framework & Library -> Cocoa Touch Static Library。Product Nameは適当に、TestDylibとか。

ここまでやったら、一度Xcodeを終了。FInderで先ほどの作成したプロジェクトのフォルダまで行って、XXX.xcodeprojに対して、右クリック->パッケージの内容を表示。project.pbxprojを適当なエディタで開く。

“com.apple.product-type.library”で検索すると、

productType = “com.apple.product-type.library.static”;

が出てくるので、これを

productType = “com.apple.product-type.library.dynamic”;

に変更。再度、Xcodeでこのプロジェクトを開く。

ここからは色々やり方があるのかもしれませんが、とりあえずiPhoneでもSimulatorでも動くものにしたいので、以下も参考にしながら進めます。

RunScriptを追加するためのTargetを追加。

Menu(画面上部) > Editor > Add Taget…

iOS > Other > “Aggregate” を選択。Product Nameは適当にTestDylib-Universalとか。

“TestDylib-Universal” の Build Phase を編集します。

Menu > Editor > Add Build Phase > Add Run Script Build Phase.

Scriptを追加します。

CopyFile追加。

Architecture変更、Schemeの編集。

“Mach-O Type” set to Dynamic Library。

“Executable Extension” set to dylib。

ここまでやったら、一度実行。エラーが出るし、.aが生成される。

ここまでの作業は、TargetがTestDylib-Universalの話。同じ設定を、TestDylibターゲットに対しても設定する(Mach-O Type, Excecutable Extension, Executable Prefix, valid Architecture)。

これでもう一回、ターゲットをUniversalにして実行。すると、lipo: can’t open input file: /Users/nick/work/iPhonePractice/TestDylib/build/Release-iphoneos/libTestDylib.dylib (No such file or directory)のエラー。

頭にlibがついたものを探しにいってしまっているので、RunScriptを修正。LIB_NAME=”${PROJECT_NAME}.dylib”にする。

これでいける。。。ハズ。

ビルドが成功したら、今のところ空っぽのライブラリなので、適当に中身を追加。test.c(.h)を作成して、中身はこんな感じ。

test.c

#include “test.h”

int addHoge(int a, int b)
{
return a + b;
}

test.h

#ifndef __TestDylib2__test__
#define __TestDylib2__test__

#include <stdio.h>
int addHoge(int a, int b);
#endif /* defined(__TestDylib2__test__) */

Build PhaseのCopy Filesでtest.hを追加してから、もう一回ビルド。

4. 作成したdylibを使う

適当にiOSのプロジェクトを作る。”UseDylibTest”とか。

上記の手順で作っていれば、Finder上ではlibとincludeができているはず。プロジェクトの”Add Files to”で、これらをプロジェクトの直下に持って来る。

BuildPhaseのLink Binary With Librariesで、追加したdylibがあるかを確認。なければ手動で追加。

また、User Header Search Pathsに

$(PROJECT_DIR)/UseDylibTest/include (必要ならrecursiveに)

を追加して、Always Search User PathsをYesに。

ここまで出来たら、ViewController.mをこんな感じに。

#include “test.h”

– (void)viewDidLoad {
[super viewDidLoad];

NSLog(@”Call! %d”, addHoge(1,3));
}

これでアプリを実行して、コンソールに”Call! 4″とか出れば成功です。

しかし、これだと静的ライブラリのときの出方と同じだから、ホントに動的ライブラリとして呼び出されているのかよくわからない。。。普通にincludeとかも準備してしまっているし、名前がdylibになっているだけで、実際は静的ライブラリとして動いているのかも。

以下、個人的メモ。