その1の続きです
【Cocos2d-x】Script Bindingの作り方(その1)
それではbindings-generatorの実装方法を説明します。
#Lang言語用のファイルを作る
まずはCococ2d-xのtoolsディレクトリ配下で、Lang言語用のディレクトリを作成します。
一から作るのは大変なので、Luaのディレクトリをコピーすることにします。
cp -r tools/tolua tools/lang
cp -r tools/bindings-generator/targets/lua tools/bindings-generator/targets/lang
まずはtools/langディレクトリのファイルを見てみましょう。
genbindings.pyというPythonスクリプトと、"cocos2dx"で始まるiniファイルがいくつかあるかと思います。
genbindings.pyを開き、try〜except句の以下の部分を書き換えます。
- tolua / luaとなっているのをlangに変更
- cmd_argsの中身を一旦"cocos2d-x.ini"のみにする
try:
lang_root = '%s/tools/lang' % project_root
output_dir = '%s/cocos/scripting/lang-bindings/auto' % project_root
cmd_args = {'cocos2dx.ini' : ('cocos2d-x', 'lang_cocos2dx_auto'), \
}
target = 'lang'
generator_py = '%s/generator.py' % cxx_generator_root
for key in cmd_args.keys():
args = cmd_args[key]
cfg = '%s/%s' % (lang_root, key)
print 'Generating bindings for %s...' % (key[:-4])
command = '%s %s %s -s %s -t %s -o %s -n %s' % (python_bin, generator_py, cfg, args[0], target, output_dir, args[1])
_run_cmd(command)
if platform == 'win32':
with _pushd(output_dir):
_run_cmd('dos2unix *')
print '---------------------------------'
print 'Generating lang bindings succeeds.'
print '---------------------------------'
except Exception as e:
if e.__class__.__name__ == 'CmdError':
print '---------------------------------'
print 'Generating lang bindings fails.'
print '---------------------------------'
sys.exit(1)
else:
raise
こんな感じになります。
cmd_argsには生成する対象のソースとその設定ファイルを記述します。
最初から全てに対応するのは難しいので、まずは一番基本となる"cocos2d-x.ini"だけに限定しています。
"cocos2d-x.ini"が完璧になったところで、対応ファイルを1つずつ増やしていくと良いと思います。
次に、"cocos2d-x.ini"の中身を見てみましょう。
色々と設定がありますが、書き換えることがありそうな項目は以下のあたりだと思います。
- headers
解析する対象のC++のヘッダ。指定したヘッダファイルを起点にincludeを辿って解析していく。
- classes
生成対象のクラス。
- skip
classesで指定したクラスの中で、除外するメソッドを記載。
例えば Sprite::[getQuad] は、SpriteクラスのgetQuadメソッドは除外するということ。
[*]は、全てのメソッドということ。
- rename_functions
Lang言語上に作るメソッド名を、C++のメソッド名と異なるものにする場合に指定。
やたら長いメソッド名を短くしたりする。
- rename_classes
Lang言語上に作るクラス名を、C++のメソッド名と異なるものにする場合に指定。
- abstract_classes
抽象クラスを指定。(コンストクタを作らない)
iniファイルの中身を確認したら、一旦何も変更せずに閉じてください。
それではこの状態でbindings-generatorを実行し、グルーコードを生成してみましょう。
先ほど書き換えたgenbindings.pyを実行してください。
いくつかログが出た後に、"Generating lang bindings succeeds." と表示されれば成功です。
成功した場合、以下のファイルが生成されているはずです。
cocos2d-x/cocos/scripting/lang-bindings/auto/lang_cocos2dx_auto.hpp
cocos2d-x/cocos/scripting/lang-bindings/auto/lang_cocos2dx_auto.cpp
生成コードはまだ何も変更していないので、中身はLua用の記述のままになってます。
#グルーコード生成用のテンプレートファイルを編集
生成されるコードを変更するには以下のディレクトリ配下にある、テンプレートファイルを変更します。
なお、bindings-generatorはCheetahというPythonのテンプレートエンジンを使用しているため、
Cheetahの文法に従って書いていくことになります。
cocos2d-x/tools/bindings-generator/targets/lang/templates/
templatesディレクトリの下には以下のテンプレートファイルがあります。
- layout_head.h
生成される.hppファイルの先頭に出力される。#include等を書く。
register_all_cocos2dx関数のプロトタイプをここで書いておく。
- layout_head.c
生成される.cppファイルの先頭に出力される。#include等を書く。
- layout_foot.h
生成される.hppファイルの末尾に出力される。
- layout_foot.c
生成される.cppファイルの末尾に出力される。register_all_cocos2dx関数を実装し、
各クラス毎に定義したregisterメソッドを呼び出す処理を書く。
- prelude.h
各クラス毎のまとまりの最初に出力される。
- prelude.c
各クラス毎のまとまりの最初に出力される。クラス毎に生成したいコードがあれば書く。
- register.c
lang_register_cocos2dx_*関数を実装する。クラス毎にbinding登録関数をまとめたもの。
- ifunction.c
メンバ関数毎に出力される。
- ifunction_overloaded.c
メンバ関数毎に出力される。オーバーロードしている場合はこちらが出力される。
- sfunction.c
静的メンバ関数毎に出力される。
- sfunction_overloaded.c
静的メンバ関数毎に出力される。オーバーロードしている場合はこちらが出力される。
- lambda.c
std::functionをbindingする際に出力される。
- function.h
メンバ関数毎に.hppファイルで出力される。(function.c共通のファイル)
関数をオーバーロードしている場合は別ファイルになっていますが、これはオーバーロードしている場合は
Lang言語から渡された引数の数や型で、どのオーバーロード関数を実行するかを判定する必要があり、
処理が複雑になるためです。
また、apidoc_*というテンプレートがあるかと思いますが、これはapidoc用に
Lang言語上に生成される関数のシグネチャをコメントで出力するためのものです。
テンプレート関連で、もう一つ以下のYamlファイルを編集する必要があります。
cocos2d-x/tools/bindings-generator/targets/lang/conversions.yaml
中身を見るとなんとなくわかるかと思いますが、型の変換方法を定義しているファイルです。
C++⇔Lang言語間の型変換関数を使って、型ごとに呼び出す変換関数を定義します。
"to_native"は、Lang言語 -> C++、from_nativeはその逆です。
なお、キーの文字列で、"@"で始まるものがいくつかあると思いますが、"@"で始まる文字列は正規表現として扱います。
#generator.pyを編集
C++のコードを解析しながら、テンプレートを使ってコードを出力していくのがgenerator.pyです。
つまり、bindings-generatorの本体のスクリプトとなります。
テンプレートの修正だけでは足りない場合等は、generator.pyを直接いじることになります。
なお、C++コードの解析には以下のスクリプトを使っています。
cocos2d-x/tools/bindings-generator/clang/cindex.py
これはClangのPython bindingで、Clangのソースコードに付属しているものです。
#最後に
説明が足りないところも多いかとは思いますが、とりあえずここまでです。
cocosコマンドの対応については私自身現在実装しているところだったりするので、
ある程度まとまったら(その3)として書くかもしれません。
私は現在Squirrelという言語のbindingを少しずつ作っているところです。
明日のAdvent Calendarは、giginetさんです。
giginetさんは12/24にCocos2d-x本を出版されるそうです。おめでとうございます!
私は既にAmazonで予約しました。
以上です。
(書いている間に12月4日が終わっていました。ごめんなさい...)