A common problem with Lua newbies is the setup of the Lua environment. As many other programming/scripting languages Lua allows you to load external libraries. To prevent you from having to type exact system paths, Lua uses so called library paths to automatically look them up.
For this purpose Lua has 2 environment variables, LUA_PATH and LUA_CPATH. The former is used for loading Lua libraries, the latter for C libraries. Despite the different targets, they both work the same. And if you are familiar with the regular system PATH variables, then you already know the concept.
NOTE: from Lua 5.2 onwards, the versioned variables eg. LUA_PATH_5_2 and LUA_CPATH_5_2 for Lua 5.2, take precedence over the unversioned ones.
Most applications use external libraries, so it is quite essential to understand the paths, especially if your system setup deviates from the most common standards.
Lua uses the `require` function to load external libraries, to find the modules Lua uses package searchers. The use of those is beyond the scope of this post, but the one thing you need to know is that the searcher for Lua modules is tried first and if it fails, the searcher for C modules will be used. These two are the ones using the path variables to find what they are looking for.
When a module is requested as in
local socket = require("socket")
Then Lua will start looking for the module named “socket” within the configured paths.
Each search location in the path is separated by “;” (semicolon), and a “?” (question mark) indicates the name of the module. So an example LUA_PATH could look like this;
This example specifies two locations (in order) to look for the module (assuming we’re still requiring “socket“);
In Lua, if a package consists of multiple modules, they usually are organized in a tree structure. When requiring a module on this tree, the individual path elements are dot separated `.`
local mime = require("socket.mime")
In this case the separating `.` denotes the directory structure, think of replacing them by ‘/‘ (or ‘\‘ on Windows). So in this case, with the following paths;
The files Lua will look for will be;
There is a caveat to this; if you include the exact location of the module, but then ‘require‘ it using a nested module name, the module will not be found;
and then requiring
local mime = require("socket.mime")
will look for
Note the double ‘socket‘ in there, and Lua will fail to find it.
If the environment variables are not found Lua will use it’s defaults. The default paths are denoted by `;;` (double semi-colon). So in the example above, if you want Lua to first check the specific directory, and then check its default locations, it would look like this;
Note the double semicolon at the end, which is the placeholder where the default Lua paths will be inserted.
If you look at the default paths you’ll probably see `/?/init.lua` in there. So what is this about?
If you create a module that in itself contains multiple sub modules then the `init.lua` can help you to keep things nice and tidy. Consider a module with 2 sub modules
./mymodule.lua ./mymodule/api.lua ./mymodule/config.lua
So this module has a module file as well as a sub directory by the same name. A common pattern is to use `init.lua` in those cases. `init.lua` will have the contents of `mymodule.lua` and be located inside the subdirectory:
./mymodule/init.lua #contents of: mymodule.lua ./mymodule/api.lua ./mymodule/config.lua
So now our entire module is encapsulated inside the directory with the module name, as said: nice and tidy.
By using a Lua path like this:
Everything will still work as it did before, because when we do `require(“mymodule”)` the second clause will expand to `./mymodule/init.lua`. So all together there is nothing special about it, it is just a practice that was so common, that it actually made it into the Lua defaults.
What if you want to change the paths from inside Lua? In that case there are 2 global properties; `package.path` and `package.cpath` which contain the paths searched. In those variables, the placeholder for the defaults, “;;“, will already have been expanded to the actual defaults.
Now what if you set everything up, but it still doesn’t work?
- Try inserting this line to see what paths are being searched;
print("LUA MODULES:\n",(package.path:gsub("%;","\n\t")),"\n\nC MODULES:\n",(package.cpath:gsub("%;","\n\t")))
(this will do a pretty-print of the paths) and see whether they match what you configured/expected.
- Check the error message (which is usually quite descriptive)
- Check the casing of the module name, names and paths are case sensitive (except on Windows)
- If using a Lua version 5.2 or higher, check the versioned environment variables, eg. LUA_PATH_5_2, etc.
- Check any command-line scripts being invoked for path manipulation, eg. LuaRocks usually inserts extra paths to its package repository (rocktrees) to make sure packages can be found
- Check your application documentation, Lua is often embedded into a host application. Obviously the host application might override any default Lua behaviours.
That’s pretty much all there is to it!!