2012年2月17日金曜日

Lua 5.2.0 on Android (1)

まずはLua 5.2.0をAndroid NDK上でビルドするところから。最終的にはOpenGLを使って何かやりたい。

Luaソースのダウンロード
Luaの最新版ソース(5.2.0)を下記よりダウンロードする。
Luaソースの配置
Android ProjectのjniフォルダにLuaのソース一式(*.c, *.h, *.hpp)をコピーする。自分は、jniの下にluaというフォルダを作ってそこに入れている。Android ProjectやNDKのセットアップ等の説明はここでは省略。

Android.mk、Application.mkを作成
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
 
LOCAL_ARM_MODE  := arm
LOCAL_MODULE    := lua
LOCAL_SRC_FILES :=  \
 lua/lapi.c  lua/lcorolib.c lua/ldump.c  lua/llex.c  lua/lopcodes.c lua/lstrlib.c lua/luac.c \
 lua/lauxlib.c lua/lctype.c lua/lfunc.c  lua/lmathlib.c lua/loslib.c lua/ltable.c lua/lundump.c \
 lua/lbaselib.c lua/ldblib.c lua/lgc.c  lua/lmem.c  lua/lparser.c lua/ltablib.c lua/lvm.c \
 lua/lbitlib.c lua/ldebug.c lua/linit.c  lua/loadlib.c lua/lstate.c lua/ltm.c  lua/lzio.c \
 lua/lcode.c  lua/ldo.c  lua/liolib.c lua/lobject.c lua/lstring.c 
 
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_OPTIM   := release
APP_STL     := stlport_static

ビルド
$ ndk-build clean all
ただし、ビルド中に下記のようなエラーがでる。

/Volumes/Share/jun/eclipse_workspace/LuaGL/jni/llex.c: In function 'trydecpoint':
/Volumes/Share/jun/eclipse_workspace/LuaGL/jni/llex.c:214: error: 'struct lconv' has no member named 'decimal_point'


Luaは、C標準ライブラリのlocal.hで定義されているlconv構造体のdecimal_pointメンバを参照しているが、Android環境のlocal.hにはその定義がないようだ。このdecimal_pointには小数点を表す文字が入っており、たいてい「.」(ピリオド)なのでここでは直に入れてしまおう。llex.cの202行目付近を下記のように修正する。

#if !defined(getlocaledecpoint)
//#define getlocaledecpoint()   (localeconv()->decimal_point[0])                                                   
#define getlocaledecpoint() '.'
#endif

再度ビルドすれば通るはずだ。libs/armeabi/liblua.soが出来てればOK。

2012年2月16日木曜日

AS2でAS3のドキュメントクラス的なことをやる方法

Flashなネタをぜんぜん書いてなかったのでとりあえず。有名なノウハウだが、すぐ忘れてしまうので覚え書きとして。

AS2環境でフレーム1に下記のようなスクリプトを記述すれば、HogeClassがAS3のドキュメントクラスのように使えるというノウハウ。

import HogeClass

this.__proto__ = Function(HogeClass).prototype;
Function(HogeClass).apply(this, null);

最初、_proto_とprototypeの意味が今ひとつよく分からなかったのだが、野中先生のページに詳しく記されていた。


ActionScriptの、プロパティを使った継承メカニズムを使ってる訳だ。あるクラス(ClassAとする)をnewしたときコンストラクタが呼ばれるわけだが、コンストラクタが呼ばれたタイミングでClassAのクラスプロパティにprototypeってのが追加される。このprototypeはデフォルトプロパティと呼ばれるもので、これに他のクラス(たとえばClassB)のprototypeを指定してやると、ClassAのデフォルトメソッドやプロパティがClassBのものを使用するようになる。つまり継承そのもの。_proto_は、ClassAをインスタンス化したとき、コンストラクタが呼ばれたタイミングでインスタンス側に追加されるprototypeプロパティ。なので、

this.__proto__ = Function(HogeClass).prototype;
は、rootの継承元をHogeClassに設定

Function(HogeClass).apply(this, null);
は、apply()を使ってHogeClassのコンストラクタを実行、という意味だ。

アプリのパッケージ名を変更する

アプリのパッケージ名は、端末内部やAndroid Marketでアプリを識別する際のユニークなIDとして使われており非常に重要な意味を持っているが、ここで紹介するアプリのパッケージ変更方法は、あとで変更する可能性がある場合に知っておくと便利である。

アプリのパッケージ名を変更する際、Eclipseのリファクタリング機能で何も考えずに各ソースのパッケージ名を変更すればいいと思われるが、SubversionやBazaarなどのvcsを使ってソースを管理している場合は、ソースの多くがアプリのパッケージ名に依存しているとリファクタリングによってsrc内のファイルの位置も変わるので、リポジトリにpushした際にリポジトリ内のファイルが大量に移動されしまい、変更履歴の管理が厄介になる。

であれば、最初からすべてのソースをアプリのパッケージ名に依存しないパッケージ名しておけばよい。ただ、AndroidManifestに記述するActivity等のクラスのパッケージ名は、デフォルトではアプリのパッケージ名からの相対(「.」から始まる)になっているので、ここのパッケージ名を絶対パスで記述すればよい。

相対パスのパッケージ名



絶対パスのパッケージ名




受託で開発する際は、アプリのパッケージ名にはクライアントのドメインを含めることが多いが、ソースコードはクライアントのドメインに依存しないパッケージ名(たとえば自社のパッケージ名)であると、自社でのソースコードの再利用性も高まるはずだ。

この状態でアプリのパッケージ名を変更する際に注意する点がある。projectフォルダのgenの下にあるR.javaはアプリのパッケージ名をベースとして自動生成される。Rクラスをimportしているソースコードは多数あるはずで、アプリのパッケージ名を変更するとRクラスを参照する多数のソースのリファクタリングも必要になる。しかし、AndroidManifestの変更だけではリファクタリングはしてくれないので手動でやることになる。手動といってもソースコードをひとつひとつ修正していくのではなく、Eclipseのリファクタリング機能を手動で実行するという意味である。

ソースコードのパッケージ名を変更せずにアプリのパッケージ名を変更する手順

  1. AndroidManifestに記述するクラスのパッケージ名を絶対パスで記述。
  2. R.javaのパッケージ名を新しいアプリのパッケージ名でリファクタリング。この時点でエラーがたくさんでるが気にしない。
  3. AndroidManifestのアプリのパッケージ名(manifestタグのpackage属性の値)を新しい名前に変更。

プロジェクトをリビルド(リフレッシュ&クリーンした上でビルド)。2で出たエラーはすべて消えてるはず。

これで、ソースコードのパッケージ名を変更せずに目的のアプリのパッケージ名を持つapkが作成できる。