从Lua
用户的观点来看,module
就是一段可以通过require
加载的代码(C
或Lua
),并且生成和返回一个table
。Lua
中所有的标准库都是module
。
通过require
命令加载module
的步骤:
(1)查看module
是否已经在package.loaded table
中了,如果已经在了,就返回table
中的值;否则转向步骤(2);
(2)查找以module
命名的Lua
文件。找到就使用loadfile
加载,会得到一个称之为“loader
”的函数。否则转向步骤(3);
(3)查找以module
命名的C
库文件。找到就使用package.loadlib
加载,寻找luaopen_modname
函数,也就是“loader
”的函数。
有了loader
以后,require
会调用loader
函数,并传入模块名和得到loader
的文件名作为参数(很多module
会忽略参数)。loader
的返回值会被存入package.loaded table
中,如果没有返回值,require
表现会像loader
返回了true
,这样可以防止多次加载同一module
。
有时,为了避免module
名冲突,需要重命名module
(比如,加载同一module
的不同版本)。Lua module
没有把名字固定在内部,所以简单地重命名Lua
文件就好了。但是对binary
文件,由于无法改luaopen_*
函数,所以需要一个trick
:当module
名有“-
”时,require
期待的open
函数是使用”-
“以后的名字。举个例子,如果一个module
名字是v1-mod
,则require
期待的open
函数就是luaopen_mod
。所以只要把module
前面加上版本和”-
“以进行区分就可以了。
require
查找module
的path
是一系列用“;
”分开的template
,例如:
/usr/local/share/lua/5.3/?.lua;/usr/local/share/lua/5.3/?/init.lua;/usr/local/lib/lua/5.3/?.lua;/usr/local/lib/lua/5.3/?/init.lua;./?.lua;./?/init.lua
对每个template
,require
用module
名字代替?
,看是否存在这个文件。找到就返回,没有就尝试下一个template
。
require
查找Lua
文件的path
是package.path
变量里的值。这个值是这样得到的:
1)首先看是否定义环境变量LUA_PATH_5_2
(取决于具体的Lua
版本,这里只是个例子),如果有,则把这个值赋给package.path
,没有转向2);
2)如果定义了环境变量LUA_PATH
,则把这个值赋给package.path
,没有转向3);
3)使用预定义的default path
的值赋给package.path
)。
需要注意的是,当使用环境变量定义的值时,如果有“;;
”,则要把它替换成default path
。举例来说,如果LUA_PATH_5_2
的值是“mydir/?.lua;;
”,则最后得到package.path
应该是mydir/?.lua
后面跟上default path
。
查找C
库是package.cpath
变量里的值。类似地,也有LUA_CPATH_5_2
(同样取决于具体的`Lua`版本)和LUA_CPATH
。