6.3 モジュール

モジュールライブラリは Lua でモジュールを読み込むための基礎的な機能を提供します。このライブラリは require という関数をグローバル環境に直接公開し、その他の値を全て package というテーブルに公開します。

require (modname)

指定されたモジュールを読み込みます。この関数はまず package.loaded テーブルを見て modname が読み込まれているかどうかを確認します。もし読み込まれていれば、requirepackage.loaded[modname] にある値を返します (読み込みが行われなかったことは二番目の返り値が存在しないことから分かります)。そうでなければ、モジュールのローダーの検索が行われます。

ローダーの検索では package.searchers というテーブルが使われます。このテーブルの要素は与えられたモジュールを何らかの方法で検索する関数であり、このテーブルを変更することで require によるモジュール検索の方法を変更できます。デフォルトの package.searchers を使った場合の検索処理を次に示します。

まず requirepackage.preload[modname] を調べます。この値が見つかれば、それがローダーとなります (この値は存在するなら必ず関数です)。見つからなければ package.path にある Lua ローダーが検索されます。そこでも見つからなければ、package.cpath にある C ローダーが検索されます。なお見つからなければ、オールインワンローダーが試されます (参照: package.searchers)。

ローダーが見つかると、require は二つの引数と共にそれを呼びます。一つ目の引数は modname で、もう一つの省略可能な引数はローダーデータです。ローダーデータはローダーを検索する関数がローダーとは別に返す値であり、モジュールが使う値であれば何でも構いません。デフォルトの検索関数はローダーを見つけたインデックスをローダーデータとします (他にも、ファイルから読み込まれたときはファイルパスをローダーデータにするといった使い方が考えられます)。ローダーが nil でない値を返した場合にはその値が package.loaded[modname] に代入され、nil を返した場合には truepackage.loaded[modname] に代入されます。いずれの場合でも、require は最終的な package.loaded[modname] の値を返します。それに加えて検索関数が返したローダーデータが二つ目の返り値となり、require がモジュールをどのように見つけたかがここから分かります。

モジュールの読み込みと実行でエラーが発生した場合、およびモジュールのローダが見つからなかった場合には、require はエラーを送出します。

package.config

パッケージライブラリのコンパイル時に定義される設定を表す文字列です。この文字列の意味は次の通りです:

package.cpath

require が C ローダーを検索するときに使うパスを表す文字列です。

Lua は C 用のパス package.cpath を Lua 用のパス package.path と同じ方法で初期化します。そのときには環境変数 LUA_CPATH_5_4 または LUA_CPATH が定義されていればその値が、定義されていなければ luaconf.h にあるデフォルトパスが使われます。

package.loaded

読み込まれたモジュールの管理に require が利用するテーブルです。modname を require したときに package.loaded[modname]nil でないなら、require はその値を返して処理を終えます。

この変数は実際のテーブルへの参照でしかありません: この変数へ値を代入しても、require が使うテーブルは変化しません。

package.loadlib (libname, funcname)

C ライブラリ libname をホストプログラムに動的リンクします。

funcname"*" の場合にはライブラリのリンクだけを行い、ライブラリに含まれるシンボルを他の動的リンクされるライブラリから利用可能にします。そうでなければ、loadlib はライブラリに含まれる funcname 関数を探し、それを C 関数として返します。このためライブラリの funcname 関数は lua_CFunction のプロトタイプを持つ必要があります。

これは低レベルの関数であり、パッケージとモジュールのシステムを完全に無視します。require とは異なりパスの探索は行われず、拡張子を自動的に付与することもありません。libname は C ライブラリの完全なファイル名でなければならず、場合によってはパスと拡張子が必要です。また funcname は C ライブラリによってエクスポートされるのと全く同じ名前でなければなりません (この名前は使用される C コンパイラとリンカによって変化する可能性があります)。

この関数は標準 C でサポートされていないので、一部のプラットフォームでしか利用できません。具体的には、loadlib が利用できるのは Windows, Linux, Mac OS X, Solaris, BSD, および標準 dlfcn をサポートする Unix システムだけです。

package.path

require が Lua ローダーを検索するときに使うパスを表す文字列です。

Lua はスタートアップ時にこの変数を初期化します。初期値は環境変数 LUA_PATH_5_4 または LUA_PAH が定義されていればその値であり、定義されていなければ luaconf.h にあるデフォルトのパスです。環境変数の値に含まれる ";;" はデフォルトのパスで置換されます。

package.preload

モジュールごとのローダーを保存するテーブルです (参照: require)。

この変数は実際のテーブルへの参照でしかありません。この変数へ値を代入しても、require が使うテーブルは変化しません。

package.searchers

モジュールの検索方法を管理するために require 関数が使うテーブルです。

このテーブルの各要素は検索関数です。モジュールを探すとき、require は検索関数を昇順に、モジュールの名前 (require への引数) を唯一の引数として呼んでいきます。検索関数はモジュールを見つけると、モジュールのローダーと呼ばれる別の関数とローダーデータと呼ばれる追加の値を返します。ローダーデータはローダーに渡され、その後 require の二つ目の返り値として返されます。モジュールを見つけられなかった検索関数はその理由を説明する文字列を返します (特に理由がないなら nil です)。

Lua はこのテーブルを四つの検索関数で初期化します。

一つ目の検索関数は package.preload テーブルからローダーを検索します。

二つ目の検索関数は package.path にあるパスを使って Lua ライブラリとしてローダーを検索します。この関数による検索は package.searchpath で説明されるように行われます。

三つ目の検索関数は変数 package.cpath にあるパスを使って C ライブラリとしてローダーを検索します。この関数による検索も package.searchpath で説明されるのと同様です。例えば、もし package.cpath に定義される C 用のパスが文字列

"./?.so;./?.dll;/usr/local/?/init.so"

なら、モジュール foo の検索では ./foo.so, ./foo.dll, /usr/local/foo/init.so がこの順番で検索されます。C ライブラリが見つかると検索関数はまず動的リンク機能を使ってそれをアプリケーションにリンクし、その後ローダーとして使われる C 関数をライブラリから関数を検索します。このとき検索される C 関数の名前はモジュールの名前に含まれるドットをアンダースコアに置き換えた文字列を "luaopen_" の後ろに付けた文字列です。またモジュールの名前にハイフンが含まれると、最初のハイフンより後の (ハイフンを含む) 部分は削除されます。例えばモジュールの名前が a.b.c-v2.1 なら、検索される関数の名前は luaopen_a_b_c となります。

四つ目の検索関数はオールインワンローダーを試します。このローダーは与えられたモジュールのルート名 (最初のドットまでの文字列) と同じ名前のライブラリを C パスから検索します。例えば a.b.crequire するときには、オールインワンローダーはまず a という C ライブラリを検索します。これが見つかれば、その中にサブモジュールとして含まれる関数を検索します。今の例であれば luaopen_a_b_c が検索されます。この機能を使ってパッケージを作ると、それぞれが独自のオープン関数を持った複数の C サブモジュールを単一のライブラリに入れられるようになります。

一つ目 (preload を使うもの) を除いた全ての検索関数はモジュールを発見したファイルパスを二つ目の返り値として返します。これは package.searchpath が返すのと同じ値です。一つ目の検索関数は常に文字列 ":preload:" を返します。

検索関数はエラーを送出してはならず、また Lua に副作用を及ぼしてはいけません (アプリケーションにライブラリにリンクするといった C における副作用は許されます)。

package.searchpath (name, path [, sep [, rep]])

指定された path から指定された name を検索します。

path はセミコロンで区切られたテンプレートの列です。テンプレートに含まれるクエスチョンマークは name で置換され、sep (デフォルトではドット) は rep (システムのディレクトリ分離文字) で置換されます。この置換結果のファイルのオープンが試みられます。

例えば path が次の文字列だったとします:

"./?.lua;./?.lc;/usr/local/?/init.lua"

このとき foo.a に対して searchpath を行うと ./foo/a.lua, ./foo/a.lc, /usr/local/foo/a/init.lua がこの順番で検索されます。

読み込みモードでオープンできた最初のファイルの置換後の名前が返ります。どのファイルもオープンできなければ、fail とエラーメッセージが返ります (エラーメッセージには開こうとしたファイル名の一覧が表示されます)。