当前位置: 首页 > 工具软件 > lua-resty-ffi > 使用案例 >

lua的require

耿俊彦
2023-12-01

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;;"













 类似资料: