プログラミングの魔物

エラー、バグ、仕様変更と戦うブログ

tolua++の使い方(主にMac)

tolua++とは何か

LuaC++の関数やクラスを公開するにはグルーコードを書く必要がある。
けど、グルーコードを毎回書くのは大変!

tolua++でグルーコードを自動生成。C++の関数やクラスをLuaで使えるように(バインド)する。

tolua++でバインド可能なもの

  • 定数値(enumまたは#define)
  • クラス(class)、構造体(struct)
  • グローバル変数
  • グローバル関数
  • クラステンプレート

このうち、関数に関してはluaの汎用グルーコードでもできるが、他のパターンにはまだ対応していないのでtolua++に頼る。

tolua++の準備

Windowsならtolua++の公式でダウンロード
http://www.codenix.com/~tolua/

Macはcocos2d-xのアーカイブ内の/tools/tolua++/tolua++Mac.zipにtolua++が入ってる。

tolua++の構成

  • tolua++.exe(実行ファイル本体)
  • tolua++に指示を与えるパッケージファイル(.pkg)・・・自分で書く
  • グルーコード(.h .cpp)・・・tolua++が吐く

.pkgはヘッダファイルに似ているが、制御用の文法が追加されている。
また、#define以外のプリプロセッサマクロが無視される。

tolua++のコマンドライン文法

tolua++.exe [オプション] パッケージファイル
//例
tolua++.exe -n myproj -o my

よく使われるオプション

オプション 説明
-n パッケージ名 パッケージ名指定。
グルーコードの関数名などに使われるためプロジェクト内で一意にする
-o ファイル名 出力するグルーコードのファイル名
-H ファイル名 出力するグルーコードのヘッダファイル名

それ以外のオプション

オプション 説明
-h ヘルプ
-v バージョン情報
-p パッケージのパース。出力はしない
-P デバッグ用にパース結果表示
-L ファイル名 指定されたファイルをLuaスクリプトとして実行後に処理
-W サポートされない機能に関する警告を出力しない
-S std::stringを文字列型として扱う機能を解除。デフォルトON
-1 配列のインデックスから1を引く機能を有効。デフォルトOFF
-D クラスにコンストラクタが存在する場合、自動的にデストラクタを
バインドする機能を無効にする。デフォルトON。
パッケージファイル内のクラス定義部分で
TOLUA_PROTECTED_DESTRUCTORと記述すれば、
デストラクタはバインドされなくなる
-t C++のタイプIDのリストをエクスポート。
プリプロセッサマクロMtolua_typeidを設定することで、
toluaの型情報文字列とC++のタイプIDとの関連付けを取得
-E 変数名[=変数値] tolua++内のLuaステートに追加の変数を設定

パッケージファイルの作成

プロジェクトディレクトリにグルーコード用のディレクトリを作成しておく。
tolua++.exeをプロジェクトディレクトリにコピーして、Windowsならバッチファイル、Macなら.shを作成。
まずは空のグルーコードを出力してみる。

ディレクトリ構成は

Project/tolua_glue/sample.pkg  //空のファイル
Project/tolua++.exe

ターミナルで

cd Project/tolua_glue/
vi make_glue.sh

viで

#!/bin/sh
../tolua++ -n sample -o sample_glue.cpp -H sample_glue.h sample.pkg

ターミナルに戻り

chmod 755 make_glue.sh
sudo ./make_glue.sh

すると空のグルーコードが出力される。

sample_glue.hにはtolua_sample_open()が宣言されている。
これを実行するとsample.pkgで設定した内容がLuaに公開される。

利用方法はグルーコードをプロジェクトに追加して下記のようにする。

#include "lua.hpp"
#include "tolua++.h"
#include "tolua_glue/sample_glue.h"
//luaを開いてライブラリをロードした後
tolua_sample_open(L);//Lはlua_State*

パッケージファイルの書き方

サンプルなので適当に

luasample.h
extern const char * GetString(int index);
luasample.cpp
#include "luasample.h"
const char * GetString(int index){
	return "test";
}
sample.pkg
$#include "luasample.h"

extern const char * GetString(int index);

パッケージファイルの内容はインクルード用の宣言+ヘッダファイルのコピペ。
$#includeはsample_glue.cppでインクルードするためのもの。
なのでディレクトリの位置関係を調整する。

パッケージファイルを更新したら再びmake_glue.shを実行すればグルーコードが更新される。

xcodeのビルドフェーズでmake_glue.sh実行

毎回make_glue.shを呼出すのはめんどくさいのでビルドフェーズに実行するように設定。

  1. xcodeの左ペインからプロジェクトを開いてBuildPhasesタブを選択。
  2. 下の方にあるAddBuildPhaseボタンを押す。
  3. AddRunScriptを押す。
  4. 追加されたRunScriptをドラッグして適当な位置に配置する
  5. 「type a script〜」にmake_glue.shを入れる
#!/bin/bash
ほにゃらら/tolua_glue/make_glue.sh

RunシェルスクリプトはDerivedDataで実行されるようなので、
(/Users/user/Library/Developer/Xcode/DerivedData/Project/超長いパス〜)
make_glue.shの中の相対パス絶対パスで呼び出せるようにする。

#!/bin/sh
absdir=$(cd $(dirname $0) && pwd)
${absdir}/../tolua++ -n sample -o ${absdir}/sample_glue.cpp -H ${absdir}/sample_glue.h ${absdir}/sample.pkg

あとはビルドするたびに自動でグルーコードが作成される。・・・はず。
ここに書いたことは適当なので、失敗したら素直にmake_glue.shを実行すればいいと思います。

参考にした本

VisualStudioでのtolua++の使い方が載ってる。

スクリプト言語による効率的ゲーム開発 新訂版 (LuaとC/C++連携プログラミング)

スクリプト言語による効率的ゲーム開発 新訂版 (LuaとC/C++連携プログラミング)