Lua Modules and Packages

A module is similar to an encapsulated library. Since Lua 5.1, Lua has added a standard module management mechanism, which allows some common code to be placed in a file and called elsewhere in the form of an API interface, which is conducive to code reuse and reducing code coupling.

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

-- The file name is module.lua
-- Define a module named module
module = {}
 
-- Define a constant
module.constant = "This is a constant"
 
-- Define a function
function module.func1()
    io.write("This is a public function!"\n")
end
 
local function func2()
    print("This is a private function!")
end
 
function module.func3()
    func2()
end
 
return module

From the above, the structure of a module is the structure of a table, so you can operate and call the constants or functions in the module just like operating and calling elements in a table.

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


require Function

Lua provides a function called require to load modules. To load a module, you simply need to call it. For example:

require("<模块名>")

Or

require "<模块名>"

After executing require, it returns a table composed of module constants or functions, and also defines a global variable containing this table.

test_module.lua File

-- test_module.lua file
-- The module module is the module.lua mentioned above
require("module")
 
print(module.constant)
 
module.func3()

The execution result of the above code is:

This is a constant
This is a private function!

Or define an alias variable for the loaded module for easy calling:

test_module2.lua File

-- test_module2.lua file
-- The module module is the module.lua mentioned above
-- Alias variable m
local m = require("module")
 
print(m.constant)
 
m.func3()

The execution result of the above code is:

This is a constant
This is a private function!

Loading Mechanism

For custom modules, the module file cannot be placed in just any directory. The require function has its own file path loading strategy. It will try to load the module from a Lua file or a C program library.

The path used by require to search for Lua files is stored in the global variable package.path. When Lua starts, it initializes this environment variable with the value of the environment variable LUA_PATH. If this 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. Open the .profile file in the current user's home directory (create it if it does not exist, or open the .bashrc file). For example, add the "~/lua/" path to the LUA_PATH environment variable:

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

File paths are separated by ";" semicolons. The last 2 ";;" mean that the newly added path is followed by the original default path.

Then, update the environment variable parameters to make it take effect immediately.

source ~/.profile

At this time, assume 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 calling require("module"), it will try to open the following file directories 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 will search for the C program library.

The search 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 it now searches for files of type so or dll. If found, require will load it through package.loadlib.


C Packages

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

Unlike writing packages in Lua, C packages must first be loaded and connected before use. In most systems, the easiest implementation method is through the dynamic linking library mechanism.

Lua provides all dynamic linking functions in a function called loadlib. This function has two parameters: the absolute path of 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 a Lua function, so we can call it directly in Lua.

If an error occurs when loading the dynamic library or finding the initialization function, loadlib will return nil and an error message. We can modify the previous code to detect the error and then call the initialization function:

local path = "/usr/local/lua/lib/libluasocket.so"
-- Or path = "C:\\windows\\luasocket.dll", this is on the Windows platform
local f = assert(loadlib(path, "luaopen_socket"))
f()  -- Actually open the library

In general, we expect the binary release library to contain a stub file similar to the previous code segment. When installing the binary library, it can be placed in any directory, and only the actual path of the binary library corresponding to the stub file needs to be modified.

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

Other Extensions