Io話を続けるつもりだったのだけれども。ネタを仕込んでいる間にわけあってLuaに手を出すことになり。そういや昨年末に新しいバージョン、Lua 5.2がリリースされたっけ、と思って調べてみたら。気をつけないとならない互換性のない変更があるのを見つけたので、それのめも。
ライブラリの登録の方法が変更になりました
バージョン5.2とそれ以前のバージョンとの非互換の部分について、リファレンスマニュアルの中に「Incompatibilities with the Previous Version」という項目があります。そこに「Function luaL_register is deprecated.」と、さらっと書かれています。
この[http://www.lua.org/manual/5.1/manual.html#luaL_register:title=luaL_register]
という関数はライブラリを登録するのに使う関数なので、最低この1カ所とはいえ既存のライブラリで必ず書き換える必要がある変更です。
マニュアルでは[http://www.lua.org/manual/5.1/manual.html#luaL_register:title=luaL_register]
の代わりに[http://www.lua.org/manual/5.2/manual.html#luaL_setfuncs:title=luaL_setfuncs]
を利用するように記載されています。あるいはもう少し簡単に扱えるようにした[http://www.lua.org/manual/5.2/manual.html#luaL_newlib:title=luaL_newlib]
マクロを使うことになります。
変更の理由ですが。
[http://www.lua.org/manual/5.1/manual.html#luaL_register:title=luaL_register]
の書式を見てもらうとわかるのですが、この関数はグローバル環境に名前を登録してしまいます。結果としてライブラリを追加で読み込むたびにグローバル環境を「よごして」しまうことになります。これを嫌っての変更のようです。全体的にもグローバル環境に影響を与えない方向に変更が加わっているようです。
具体的にライブラリを書いてみる
まずC++あるいはCでライブラリを書いてビルドします。
extern "C" { #include <lua.h> #include <lauxlib.h> #include <lualib.h> } #include <sstream> namespace { int Hoge_hoge(lua_State* L) { const char* s = luaL_checkstring(L, 1); std::stringstream ss; ss << "<hoge>" << s << "</hoge>"; lua_pushstring(L, ss.str().c_str()); return 1; } const luaL_Reg hogelib[] = { { "hoge", Hoge_hoge }, { NULL, NULL } }; } // namespace extern "C" int luaopen_hoge(lua_State* L) { luaL_register(L, "Hoge", hogelib); return 1; }
shared libraryを作ります。
g++ -shared -o hoge.dll hoge.cpp -llua
Macな人のばあい。
g++ -dynamiclib -o hoge.so hoge.cpp -llua
MS-Windowsな人のばあい。
g++ -shared -o hoge.dll hoge.cpp -llua
ライブラリを使うサンプル。
require "hoge" print(Hoge.hoge("ほげ"))
hoge.soがあるフォルダで実行してください。
$ lua sample.luaほげ
オブジェクトHoge
はLuaのスクリプト中で宣言されていませんが利用できます。ライブラリの中で名前付けされているためです。
Lua 5.2ではライブラリのエントリポイントluaopen_hoge
を次のように書き換えます。
extern "C" int luaopen_hoge(lua_State* L) { luaL_newlib(L, hogelib); return 1; }
見てのとおりHoge
という名前は登録されません。
なので先ほどのスクリプトをそのまま実行すると、こうなります。
$ lua sample.lua lua: sample.lua:3: attempt to index global 'Hoge' (a nil value) stack traceback: sample.lua:3: in main chunk [C]: in ?
require
は読み込んだライブラリのオブジェクトを返すので、スクリプトを次のように書き換えます。
Hoge = require "hoge" print(Hoge.hoge("ほげ"))
これで期待どおりに動作するようになりました。このスクリプトはLua 5.1でも動作するので、当面5.2を使う予定がなというばあいでもLua側はこのように書いておくのがよさそうです。
この例ではグローバル環境でHoge
を宣言しているので結果的には同じですが、特定のスコープでだけライブラリを使うばあいにはグローバル環境をよごさずにすみます。
5.1用、5.2用のどちらのライブラリも作成したいばあい、LUA_VERSION_NUM
というマクロにバージョン番号が定義されているのでそれを見て登録関数を使い分けることになるかと。
extern "C" int luaopen_hoge(lua_State* L) { #if LUA_VERSION_NUM >= 502 luaL_newlib(L, hogelib); #else luaL_register(L, "Hoge", hogelib); #endif return 1; }