lua的require,
lua的require,
1. require的伪代码
function require(modname)
if not package.loaded[modname] then
local loadfunc = package.preload[modname]
if loadfunc ~= nil then -- Case 1
package.loaded[modname] = true -- "true" is just to mark module as loaded
local module = loadfunc(modname);
if module ~= nil then
package.loaded[modname] = module -- replace "true" with actual module
end
else -- loadfunc is nil
local fname = string.gsub(modname, "%.", "/") -- replace "." with /; we get a file name
local loaded = false
for each item in package.path do
local luafile = string.gsub(item, "?", fname)
if open luafile success then -- Case 2
loaded = true
package.loaded[modname] = package.loadfile(luafile)
end
end
if not loaded then -- failed to load the module from lua, then try .so files;
for each item in package.cpath do
local sofile = string.gsub(item, "?", fname)
if open sofile success then -- Case 3
loaded = true
package.loaded[modname] = package.loadlib(sofile)
end
end
end
end
end
return package.loaded[modname]
end
这里面有3中情况:
- Case 1:使用package.preload table里的load函数来加载模块。这种机制一般是为了一些特殊情况——比如静态链接到Lua的C库(不甚清楚,不过如后面所示,LuaJIT里的table.new是通过这种方式load的)——所以,package.preload table经常是空的(你可以写一个test.lua脚本,把这个表打印出来看看)。不过在open resty环境下,这个表不是空的,LuaJIT的table.new就是通过这种方式load的。这种方式的过程如伪代码所示:首先找到函数,然后执行函数,函数返回的结果即加载目标。
- Case 2:使用package.loadfile加载Lua模块;
- Case 3:使用package.loadlib加载c模块;c模块应该export一个luaopen_{modname}的函数;当package.loadlib链接库之后,就会调用这个函数。
2. 脚本环境测试
# vim test.lua
print("--------------[package.loaded]--------------")
for n in pairs(package.loaded) do
print(n)
end
print("--------------[package.preload]--------------")
for n in pairs(package.preload) do
print(n)
end
print("--------------[package.path]--------------")
print(package.path)
print("--------------[package.cpath]--------------")
print(package.cpath)
# lua test.lua
--------------[package.loaded]--------------
string
debug
package
_G
io
os
table
math
coroutine
--------------[package.preload]--------------
--------------[package.path]--------------
./?.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua;/usr/lib64/lua/5.1/?.lua;/usr/lib64/lua/5.1/?/init.lua
--------------[package.cpath]--------------
./?.so;/usr/lib64/lua/5.1/?.so;/usr/lib64/lua/5.1/loadall.so
[root@localhost local]#
可见package.preload为空。
3. openresty环境测试
# vim test.lua
ngx.say("--------------[package.loaded]--------------")
for n in pairs(package.loaded) do
ngx.say(n)
end
ngx.say("--------------[package.preload]--------------")
for n in pairs(package.preload) do
ngx.say(n)
end
ngx.say("--------------[package.path]--------------")
ngx.say(package.path)
ngx.say("--------------[package.cpath]--------------")
ngx.say(package.cpath)
# vim nginx.conf
<pre name="code" class="plain"> ......
location /test {
default_type 'text/html';
lua_code_cache off;
content_by_lua_file /var/objstore/lua/test.lua;
}
....
# curl -s "http://127.0.0.1:8080/test"
--------------[package.loaded]--------------
coroutine
table
ndk
jit.opt
math
package
os
_G
bit
string
debug
jit
io
ngx
--------------[package.preload]--------------
table.clear
ngx.upstream
ffi
jit.util
table.new
jit.profile
--------------[package.path]--------------
/var/objstore/lualib/?.lua;/usr/local/openresty-1.9.15.1/lualib/?.lua;/usr/local/openresty-1.9.15.1/lualib/?/init.lua;./?.lua;/usr/local/openresty-1.9.15.1/luajit/share/luajit-2.1.0-beta2/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/openresty-1.9.15.1/luajit/share/lua/5.1/?.lua;/usr/local/openresty-1.9.15.1/luajit/share/lua/5.1/?/init.lua;
--------------[package.cpath]--------------
/var/objstore/lualib/?.so;/usr/local/openresty-1.9.15.1/lualib/?.so;./?.so;/usr/local/lib/lua/5.1/?.so;/usr/local/openresty-1.9.15.1/luajit/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/loadall.so;
[root@localhost local]#
可见,package.preload里面包含一些函数。
例1: local ok, new_tab = pcall(require, "table.new")
使用Case 1的方式加载,因为package.preload table里有对应得加载函数。
例2:前一篇博客点击打开链接中的 local redis = require "resty.redis"
使用Case 2的方式加载,因为:"resty.redis"的"."替换为"/"得到"resty/redis"。把package.path中的"?"替换为"resty/redis",其中有一项为
/usr/local/openresty-1.9.15.1/lualib/resty/redis.lua
这是一个合法的Lua模块。故加载它。
4. 自定义package.path和package.cpath
如前所述,这两个路径是用于搜索Lua模块和C模块的。
- 在脚本环境下,可以设置环境变量LUA_PATH和LUA_CPATH;
- 在openresty环境下,可以在nginx.conf中设置lua_package_path和lua_package_cpath;
若不设置,将使用默认配置。若想在默认配置的基础上,增加更多路径,";;"代表默认配置。例如:
openresty环境:
# vim nginx.conf
lua_package_path "/var/objstore/lualib/?.lua;;";
lua_package_cpath "/var/objstore/lib/?.so;;";
脚本环境:
# vim ~/.bashrc
export LUA_PATH="/var/objstore/lualib/?.lua;;"
export LUA_CPATH="/var/objstore/lib/?.so;;"
# vim test.lua
package.path="/var/objstore/lualib/?.lua;;"
package.cpath="/var/objstore/lib/?.so;;"
评论暂时关闭