Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Lua modules and packages


May 12, 2021 Lua


Table of contents


Lua modules and packages

Modules are similar to a encapsulation library, starting with Lua 5.1, which adds a standard module management mechanism that allows some common code to be put in a file and called elsewhere in the form of an API interface, which facilitates code reuse and reduces code coupling.

Lua's module is a table of known elements such as variables, functions, and so on, so it's easy to create a table, and then put the constants, functions, and so on that table that need to be exported. Here's a look at creating a .lua module module, in the following file code format:

-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
 
-- 定义一个常量
module.constant = "这是一个常量"
 
-- 定义一个函数
function module.func1()
    io.write("这是一个公有函数!\n")
end
 
local function func2()
    print("这是一个私有函数!")
end
 
function module.func3()
    func2()
end
 
return module

As you can see from above, the structure of a module is a table structure, so you can manipulate the constants or functions in the calling module just like the elements in the action call table.

The func2 above is declared as a local variable of the block, which represents a private function and therefore cannot be accessed from outside the module, which must be called by the public function in the module.


The require function

Lua provides a function called require to load modules. T o load a module, simply call it. For example:

require("<模块名>")

Or

require "<模块名>"

When require is executed, a table consisting of module constants or functions is returned, and a global variable containing that table is defined.

-- test_module.php 文件
-- module 模块为上文提到到 module.lua
require("module")
 
print(module.constant)
 
module.func3()

The above code execution results are:

这是一个常量
这是一个私有函数!

Or define an alias variable for the loaded module to call easily:

-- test_module2.php 文件
-- module 模块为上文提到到 module.lua
-- 别名变量 m
local m = require("module")
 
print(m.constant)
 
m.func3()

The above code execution results are:

这是一个常量
这是一个私有函数!

The loading mechanism

For a custom module, the module file is not placed in any file directory, and the function requires its own file path load policy, which attempts to load the module from the Lua file or C library.

The path that requires the search for lua files is stored in the global variable package.path, which is initially started with the value of the environment variable LUA_PATH when Lua starts. I f the environment variable is not found, it is initialized using a default path defined at compile time.

Of course, if you don't have the LUA_PATH environment variable, you can customize the settings to open the .profile file at the current user root (no is created, you can also open the .bashrc file), for example, by adding the "-lua/" path to the LUA_PATH environment variable:

#LUA_PATH
export LUA_PATH="~/lua/?.lua;;"

File path to "; T he numbers are separated, and the last two are ";;" I ndicates that the newly added path is followed by the original default path.

Next, update the environment variable parameters to take effect immediately.

source ~/.profile

Suppose the value of package.path is:

/Users/dengjoe/lua/?.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua

Then when you call require ("module"), you try to open the following file directory to search for the target.

/Users/dengjoe/lua/module.lua;
./module.lua
/usr/local/share/lua/5.1/module.lua
/usr/local/share/lua/5.1/module/init.lua
/usr/local/lib/lua/5.1/module.lua
/usr/local/lib/lua/5.1/module/init.lua

If the target file is found, package.loadfile is called to load the module. Otherwise, you'll go to the C library.

The file path you search for is obtained from the global variable package.cpath, which is initially LUA_CPATH environment variable.

The search strategy is the same as above, except that it is now searched for a file of the so or dll type. I f you can find it, then need will load it through package.loadlib.


C package

Lua and C are easy to combine, using C to write packages for Lua.

Unlike Lua write packages, C packages must first be loaded and connected before they can be used, and the easiest way to implement them in most systems is through a dynamic connection library mechanism.

Lua provides all the functionality of dynamic connections within a function called loadlib. T his function has two parameters: the absolute path of the library and the initialization function. So a typical example of a call is:

local path = "/usr/local/lua/lib/libluasocket.so"
local f = loadlib(path, "luaopen_socket")

The loadlib function loads the specified library and connects to Lua, but it does not open the library (that is, no initialization function is called), instead he returns the initialization function as a function of Lua so that we can call him directly in Lua.

If an error occurs loading a dynamic library or finding an initialization function, loadlib returns nil and error messages. We can modify the previous piece of code to detect errors and then call the initialization function:

local path = "/usr/local/lua/lib/libluasocket.so"
-- 或者 path = "C:\\windows\\luasocket.dll",这是 Window 平台下
local f = assert(loadlib(path, "luaopen_socket"))
f()  -- 真正打开库

In general, we expect the binary publishing library to contain a stub file similar to the previous snippy code, which can be installed in a directory at will, just modify the actual path of the stub file to the binary library.

Add the directory where the stub file is located LUA_PATH, so that you can load the C library with the require function when you set it up.