Lua modules and packages


A module is similar to a package library. Starting from Lua 5.1, Lua has added a standard module management mechanism, which allows you to put some common code in a file and call it elsewhere in the form of an API interface. Conducive to code reuse and reducing code coupling.

Lua's module is a table composed of known elements such as variables and functions. Therefore, creating a module is very simple. It is to create a table, then put the constants and functions that need to be exported into it, and finally return the table. That’s it. The following is the creation of a custom module module.lua. The file code format is as follows:

-- 文件名为 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 can be seen from the above, the structure of the module is a table structure, so you can operate the calling module just like you operate the elements in the calling table. constant or function.

The above func2 is declared as a local variable of the program block, which means it represents a private function. Therefore, this private function in the module cannot be accessed from the outside and must be called through the public function in the module.


require function

Lua provides a function called require for loading modules. To load a module, simply call it. For example:

require("<模块名>")

or

require "<模块名>"

After executing require, a table consisting of module constants or functions will be returned, and a global variable containing the table will also be defined.

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

The execution result of the above code is:

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

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

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

The execution result of the above code is:

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

Loading mechanism

For custom modules, the module file does not matter which file directory it is placed in. The function require has its own file path loading strategy. It will try to load it from a Lua file or C library. Load module.

require The path used to search for Lua files is stored in the global variable package.path. When Lua is started, this environment variable will be initialized with the value of the environment variable LUA_PATH. If the environment variable is not found, a default path defined at compile time is used for initialization.

Of course, if there is no LUA_PATH environment variable, you can also customize the settings and open the .profile file in the current user root directory (create it if it does not exist, or open the .bashrc file), for example, put "~/lua /" Add the path to the LUA_PATH environment variable:

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

The file path is separated by ";", and the last two ";;" means that the new path is followed by the original default path.

Next, update the environment variable parameters so that they take effect immediately.

source ~/.profile

At this time, assume that 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 require("module") is called, it will 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 will be called to load the module. Otherwise, it goes to the C library.

The searched file path is obtained from the global variable package.cpath, and this variable is initialized through the environment variable LUA_CPATH.

The search strategy is the same as above, except that now the search is for so or dll type files. If it is found, require will load it via package.loadlib.


C package

Lua and C are easily combined. Use C to write packages for Lua.

Unlike packages written in Lua, C packages must be loaded and connected first before use. In most systems, the easiest way to implement this is through the dynamic link library mechanism.

Lua provides all dynamic link functions in a function called loadlib. This function takes two parameters: the absolute path to the library and the initialization function. So a typical call example is as follows:

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. However, it does not open the library (that is, it does not call the initialization function). Instead, it returns the initialization function as Lua's A function so we can call it directly in Lua.

If an error occurs when loading a dynamic library or finding an initialization function, loadlib will return nil and error information. 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()  -- 真正打开库

Generally, we expect that the binary release library contains a stub file similar to the previous code snippet. You can install the binary library casually Place it in a certain directory and just modify the actual path of the binary library corresponding to the stub file.

Add the directory where the stub file is located to LUA_PATH. After setting it, you can use the require function to load the C library.