わけあって、Lua再起動中。
おさらい
前回の様子。もう2年も経ってる…。
- LuaとGLUTをつなげてみる - エンジニアのソフトウェア的愛情
- LuaとGLUTをつなげてみる、のその後 - エンジニアのソフトウェア的愛情
- LuaとGLUTをつなげてみる、のその後のその後 - エンジニアのソフトウェア的愛情
「つなげる」ということで。GLUTのライブラリをLuaから扱えるように、つなぎのコードをC++で書いてみていました。このときはLuaそのものよりも、LuaのライブラリをC++で書くことに目が向いていて、ライブラリを組み込んだ実行ファイルまで作ってしまっています。でも、ふつう、動的に拡張する(ライブラリを読み込む)方法があるよね、ということで。Shared Libraryをつくってそれを読み込ませてみることに今回は挑戦です。
ライブラリ作成には前回の成果を利用します。
先に結果をリンクしておきます。このあとで、ここに至る道のりを解説します。
Mac OS XでShared Libraryを作る方法
Shared LibraryをGCCでつくるには。検索すると「-shared
オプションを付ければいい」とすぐにヒットします。ふつうはこれでいいみたいです。Mac OS Xはこれではダメでした。
どうも期待したとおりにならないと、「man gcc
」で-shared
オプションの説明を読んでみると。
-shared (説明省略) This option is not supported on Mac OS X.
…orz。
気を取り直して。Mac OS XでShared Libraryのオプションについて検索すると。
オプションが -shared ではなくて -dynamiclib 。
一刀両断。
これで解決しました。
LuaでShared Libraryを使う方法
Luaでは動的にライブラリや他のスクリプトファイルを読み込む方法のひとつに、[http://www.lua.org/manual/5.1/manual.html#pdf-require:title=require]
関数を使う方法があります。
require "foo"
ためしに、読み込むファイルがないところで上の行を実行してみると、わたしの環境のばあいこんなエラーが表示されます。
$ lua Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio > require "foo" stdin:1: module 'foo' not found: no field package.preload['foo'] no file './foo.lua' no file '/opt/local/share/lua/5.1/foo.lua' no file '/opt/local/share/lua/5.1/foo/init.lua' no file '/opt/local/lib/lua/5.1/foo.lua' no file '/opt/local/lib/lua/5.1/foo/init.lua' no file './foo.so' no file '/opt/local/lib/lua/5.1/foo.so' no file '/opt/local/lib/lua/5.1/loadall.so' stack traceback: [C]: in function 'require' stdin:1: in main chunk [C]: ?
foo.lua
あるいはfoo
フォルダ下のinit.lua
というファイルをライブラリパスの順に検索し、見つからないばあい次にShared Libraryのfoo.so
あるいはfoo
フォルダ下のloadall.so
を検索しています。
ここで検索されるフォルダは、Luaのファルであれば[http://www.lua.org/manual/5.1/manual.html#pdf-package.path:title=package.path]
(対応する環境変数はLUA_PATH
)、Shared Libraryであれば
[http://www.lua.org/manual/5.1/manual.html#pdf-package.cpath:title=package.cpath]
(対応する環境変数はLUA_CPATH
)で指定されています。
またrequire
関数はフォルダの階層構造にも対応しています。
階層をつけて次のように書くと、
> require "foo.bar" stdin:1: module 'foo.bar' not found: no field package.preload['foo.bar'] no file './foo/bar.lua' no file '/opt/local/share/lua/5.1/foo/bar.lua' no file '/opt/local/share/lua/5.1/foo/bar/init.lua' no file '/opt/local/lib/lua/5.1/foo/bar.lua' no file '/opt/local/lib/lua/5.1/foo/bar/init.lua' no file './foo/bar.so' no file '/opt/local/lib/lua/5.1/foo/bar.so' no file '/opt/local/lib/lua/5.1/loadall.so' no file './foo.so' no file '/opt/local/lib/lua/5.1/foo.so' no file '/opt/local/lib/lua/5.1/loadall.so' stack traceback: [C]: in function 'require' stdin:1: in main chunk [C]: ?
このようにサブフォルダを検索します。
ライブラリファイルの存在はわかったので、次はライブラリの呼び出し方。
require "foo"
を実行するとfoo.so
(あるいはfoo/init.so
)というライブラリが読み込まれますが、読み込まれたあとにライブラリの中のluaopen_foo
という関数が呼び出されます。
引数戻り値も書くとこうなります。
LUALIB_API int luaopen_foo(lua_State* L)
ここで使われているマクロや型はlua.h
で定義されています。
階層化している場合、たとえばrequire "foo.bar"
を実行するとfoo/bar.so
(あるいはfoo/bar/init.so
)というライブラリが読み込まれますが、読み込まれたあとにライブラリの中のluaopen_foo_bar
という関数が呼び出されます。
これらの詳細についてはLuaのマニュアルのここを読んでみてください。
ちなみに。ここではバージョン5.1のマニュアルにリンクしてあるのは、わたしが使っているバージョンが5.1だからというだけという理由。5.2を使われている方は5.2のマニュアルを参照してみてください。
LuaとGLUTをつなげてみる、ふたたび
で。ようやく準備が整いました。
じつは。前回書いたコードですが、C++のコードの部分はエントリポイントまでほぼ条件を満たしていて、Shared Libraryとしてビルドするだけでライブラリができる状態になっていました。偶然にも。既存のコードをまねて書いた結果、偶然に条件を満たしていたようです。
一カ所。C++でコードを書いたわけですが、エントリポイントになる関数の名前はC++の名前の修飾があると呼び出せないのでextern "C"
をつける必要があります。
extern "C" LUALIB_API int luaopen_glut(lua_State* L)
あるいは
extern "C" { LUALIB_API int luaopen_glut(lua_State* L) { ... } }
あとはフレームワークやライブラリを指定してビルド。
g++ -ansi -Wall -framework OpenGL -framework GLUT -framework Foundation -dynamiclib -o glut.so glut.cpp -llua
これでLua用GLUT Shared Libraryができてしまいました。
なんで今になってこんなことを始めたかについては、また後日。
いつか読むはずっと読まない:弩級艦
“The Lost Fleet: Beyond the Frontier Dreadnaught”の邦訳が刊行されました。
これは“The Lost Fleet”シリーズ、邦訳「彷徨える艦隊」シリーズの続編になるのですが、以前予想したとおり「彷徨える艦隊7」と通巻になりました。
いきなり冒頭で政治に巻き込まれるのですけど、どこでも「ダメな政治」に巻き込まれるのは嫌なものです、はい。
- 作者: ジャックキャンベル,Jack Campbell,月岡小穂
- 出版社/メーカー: 早川書房
- 発売日: 2012/01/25
- メディア: 文庫
- クリック: 6回
- この商品を含むブログ (15件) を見る