Protocol BuffersはGoogleが開発しているフリーのシリアライズライブラリ。
構造を定義したファイルをprotocでコンパイルしてコードを生成して利用する。
cocos2d-xで利用するにはiOS/Android用のバイナリを作成する必要がある。
URL
Protocol Buffersをマシン上で利用する
環境
- Mac OS X 10.9.4
インストール
-
brewでinstall
以下で完了。
brew install protobuf
-
ソースからコンパイルしてinstall
ここから最新のものをダウンロードして解凍。以下ではバージョン2.5.0を選択。curl https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz | tar xvz
解凍したソースをmakeしてインストール
cd protobuf-2.5.0 ./configure make make install
データの読み書きをする
以下、チュートリアル通り。
以下の内容のaddressbook.protoというファイルを作成する。
package tutorial;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
}
コマンドでコンパイル。以下ではカレントにソースを出力。
protoc -I=. --cpp_out=. addressbook.proto
addressbook.pb.hとaddressbook.pb.ccが生成されるのでこれらを利用する。
コンパイルは以下のコマンドで実行。
clang++ -g -Wall -std=c++11 -lprotobuf main.cc addressbook.pb.cc
iOS/AndroidでProtocol Buffersを利用する
iOS/Androidで利用するには別途コンパイルが必要。
iOS向けにコンパイル
スクリプトが公開されているのでそれを利用する。
こちらの環境では上記のスクリプトが動作しないのでこれを利用。
注意
上記スクリプトでコンパイルすると名前空間がgoogleからgoogle_publicに変更される
git clone https://gist.github.com/7150245.git build-protobuf
cd build-protobuf
sh ./build-protobuf-2.5.0.sh
protobufディレクトリ以下にバイナリ等が配置される。ライブラリはuniversalになるのでターゲットはどれでも利用できる。
protobuf/
├── bin
│ └── protoc
├── include(省略)
└── lib
├── libprotobuf-lite.a
├── libprotobuf-lite.la
├── libprotobuf.a
├── libprotobuf.la
├── libprotoc.a
├── libprotoc.la
└── pkgconfig
├── protobuf-lite.pc
└── protobuf.pc
Android向けにコンパイル
ほぼ、こちらの通り。
注意
前のiOSスクリプトを利用してコンパイルしていると名前空間が変更されるのでcocos2d-xでも利用するには/tmp/protobuf-*内のソースを利用する必要がある(undefinedエラーでコケる)
以下要点。
-
解凍したディレクトリ名をjniに変更
- undefinedエラーが出ないためには/tmp/protobuf-*内のソースを上書きコピーしておく
cd jni cp -prf /tmp/protobuf-2.5.0/* .
-
適当なディレクトリを作成し、そこにjniを移動
-
AndroidManifest.xml(適当なもの)を作成したディレクトリに配置
-
Android.mkをjniに配置
-
Application.mkをjniに配置
- cocos2d-x v3.2だとc++_staticを利用しないとundefinedエラーが発生する
-
スクリプトを実行。${ANDROID_NDK_HOME}にはndkのパスを指定
-
ビルド
${ANDROID_NDK_HOME}/ndk-build
作成したバイナリはobj以下にできる。
obj/
└── local
├── armeabi
│ └── libprotobuf.a
├── armeabi-v7a
│ └── libprotobuf.a
└── x86
└── libprotobuf.a
Protocol Buffersをcocos2d-xで利用する
cocos2d/externalにライブラリを追加する
生成したファイルを以下のように配置する。
protobuf
├── include(省略)
└── prebuilt
├── android
│ ├── Android.mk
│ ├── armeabi
│ │ └── libprotobuf.a
│ ├── armeabi-v7a
│ │ └── libprotobuf.a
│ └── x86
│ └── libprotobuf.a
└── ios
└── libprotobuf.a
Android.mkは以下の内容で作成した。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := protobuf_static
LOCAL_MODULE_FILENAME := protobuf
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libprotobuf.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../include
include $(PREBUILT_STATIC_LIBRARY)
プロジェクトにライブラリを追加する
cocosコマンドで新しいプロジェクトを作成しておく。
iOSに追加
- XCodeで作成したプロジェクトを開き、protobufをcocos2d_libs.xcodeproj内のexternalにD&D
- 「Add To Target」はチェックなしにして追加
- 追加したprotobuf内のprebuilt/ios/libprotobuf.aファイルを選択して「Target Membership」のうちcocos2d Mac/cocos2dx iOSにチェックを入れる
- コンパイルできることを確認する
- エラーが出る場合はLibraryやHeader Search Pathsを確認する。
Androidに追加
-
cocos2d/cocos/Android.mkに以下を追加
LOCAL_WHOLE_STATIC_LIBRARIES += protobuf_static $(call import-module,external/protobuf/prebuilt/android)
-
コンパイルできることを確認する
cocos2d-xからライブラリを呼び出す
- protocで生成したファイルをClassesに追加
- ここを参考にHelloWorld内の適当な所にコードを書く
// ファイル書き込み
{
tutorial::AddressBook address_book;
for (auto i = 0; i < 5; ++i) {
auto person = address_book.add_person();
person->set_id(i);
person->set_name(StringUtils::format("Name-%d", i));
person->set_email(StringUtils::format("email-%d", i));
}
CCLOG("### %s", address_book.DebugString().c_str());
auto filename = FileUtils::getInstance()->getWritablePath() + "addressbook.bin";
std::fstream output(filename, std::ios::out | std::ios::trunc | std::ios::binary);
if (!address_book.SerializeToOstream(&output)) {
CCLOG("Failed to write address book.");
return false;
}
}
// ファイル読み込み
{
tutorial::AddressBook address_book;
auto filename = FileUtils::getInstance()->getWritablePath() + "addressbook.bin";
std::fstream input(filename, std::ios::in | std::ios::binary);
if (!address_book.ParseFromIstream(&input)) {
CCLOG("Failed to parse address book.");
return false;
}
CCLOG("### %s", address_book.DebugString().c_str());
}
google_public::protobuf::ShutdownProtobufLibrary();
- コンパイルして確認