LuaRocks is the package manager for Lua. When you decide to install a package (or module1 ) there are a few places it can be installed.
The directory that LuaRocks installs to is called a tree. It’s a specially structured directory that contains all the installed module files, along with metadata about those modules.
A common request I've heard is “I wish LuaRocks worked like npm and let me
install modules in the current directory.” I'm glad to report it already can!
I've written this guide to clear up any confusion about how and where LuaRocks
installs modules.
There are three ways of choosing where packages get installed:
/usr/share/lua/5.1)--local--tree some/directoryFor general purpose modules, ones that will be available for any Lua script you
execute, the local tree should be used. This tree is located in your home
directory (~/.luarocks). A global install is not recommended because it
requires root access.
If you're building a project in Lua you'll probably want to more closely control the dependencies and their versions. For this scenario I recommend using a tree that is located in the project’s directory. This is the approach used by other package mangers such as npm.
This section is not specific to LuaRocks, but LuaRocks utilizes this system to provide Lua a way to load the modules it installs.
When executing require("hello.world") Lua must figure out where the file for
this module is in order to load it. A module can resolve to either Lua source
code, a .lua file, or a native code library, a .so on Linux or .dll on
Windows.
Similar to your operating system’s PATH environment variable for finding
executables, Lua has a path to find modules. As mentioned above, there are
two types of modules, so Lua has two paths.
You can view (and edit) the paths using package.path and package.cpath
within a Lua script:
print(package.path) -- where .lua files are searched for
print(package.cpath) -- where native modules are searched for
-- add a new directory to the path
package.path = package.path .. ";/opt/custom/?.lua"
require("hello.zone") -- might load /opt/custom/hello/zone.lua
The initial value of package.path and package.cpath comes from the defaults
compiled into your Lua executable, and the special environment variables
LUA_PATH and LUA_CPATH.
LuaRocks has a built in command for setting the Lua path environment variables.
It’s called luarocks path
Running it the command might produce:
$ luarocks path
export LUA_PATH='/home/leafo/.luarocks/share/lua/5.1/?.lua;/home/leafo/.luarocks/share/lua/5.1/?/init.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua;;./?.lua;/usr/lib/lua/5.1/?.lua;/usr/lib/lua/5.1/?/init.lua'
export LUA_CPATH='/home/leafo/.luarocks/lib/lua/5.1/?.so;/usr/lib/lua/5.1/?.so;;./?.so;/usr/lib/lua/5.1/loadall.so'
The special syntax
;;can be used in the environment variable’s value to represent the default value provided by the Lua runtime.
This is a shell script that will set the Lua path environment variables to correctly load modules from the global and local install locations of LuaRocks.
You might want to append this to your .bashrc like this:
$ luarocks path >> ~/.bashrc
Now you can require() any modules that you've installed locally or globally
without any additional steps. (After restarting your shell or sourcing the rc
file)
Modules installed globally will work without adjusting the Lua path since they are installed in the default Lua system path.
Don’t care about the explanation, go to the quick guide.
Installing packages to the current directory is as simple as
luarocks install --tree lua_modules lpeg
This will install the package lpeg (and any dependencies if necessary) to the
directory lua_modules in the current directory.
Loading those modules is a bit more complicated.
The structure of the tree, at lua_modules/, after installing lpeg looks
like this:
lua_modules/
├── lib
│ ├── lua
│ │ └── 5.1
│ │ └── lpeg.so
│ └── luarocks
│ └── rocks-5.1
│ ├── lpeg
│ │ └── 1.0.0-1
│ │ ├── lpeg-1.0.0-1.rockspec
│ │ └── rock_manifest
│ └── manifest
└── share
└── lua
└── 5.1
└── re.lua
I happen to be using a version of LuaRocks compiled for Lua 5.1 in this example, but this technique will work for any version. Just make sure the paths you create have the correct version
For this example I chose lpeg
because it contains both a .lua module: re, and a native .so module:
lpeg. From this we can already see how we might structure our Lua path and
cpath.
path would be: lua_modules/share/lua/5.1/?.luacpath would be: lua_modules/lib/lua/5.1/?.soThere’s one more entry we'd like to add to the path. A common idiom is to use
an init.lua file as the entry point for a package, located in the directory
of that package. We'll amend the path:
path would be: lua_modules/share/lua/5.1/?.lua;lua_modules/share/lua/5.1/?/init.luacpath would be lua_modules/lib/lua/5.1/?.so
;is used to provide two places to look in the path
As discussed above there are a few ways to enable these paths. From command line you could prepend the environment variables in front of your command:
LUA_PATH='lua_modules/share/lua/5.1/?.lua;lua_modules/share/lua/5.1/?/init.lua;;' LUA_CPATH='lua_modules/lib/lua/5.1/?.so' lua my_script.lua
That’s a mouthful though, so lets use an alternate approach. The lua command
line executable can take an -l flag to specify a module to load before
executing the script.
Lets create a new file in the current directory, set_paths.lua:
-- set_paths.lua
local version = _VERSION:match("%d+%.%d+")
package.path = 'lua_modules/share/lua/' .. version .. '/?.lua;lua_modules/share/lua/' .. version .. '/?/init.lua;' .. package.path
package.cpath = 'lua_modules/lib/lua/' .. version .. '/?.so;' .. package.cpath
Now to run a script with the modules installed in that directory:
lua -l set_paths my_script.lua
This requires that the script be run from the same directory that
set_paths.luaandlua_modules/is located
You might be tempted to put require("set_paths") in your code’s entry point
to avoid the additional argument, but it’s a bad idea.
A module should run on any machine it is installed to regardless of the package
path configuration. The set_paths script is only to facilitate development
and execution in the current directory.
By configuring paths on script execution, you avoid embedding any assumptions
about the package path in your code. If this additional step is too much to
type, consider a Makefile that includes some of your common commands.
Want the full explanation? Scroll up.
luarocks install --tree lua_modules lpeg
Create file set_paths.lua:
-- set_paths.lua
local version = _VERSION:match("%d+%.%d+")
package.path = 'lua_modules/share/lua/' .. version .. '/?.lua;lua_modules/share/lua/' .. version .. '/?/init.lua;' .. package.path
package.cpath = 'lua_modules/lib/lua/' .. version .. '/?.so;' .. package.cpath
Execute scripts:
lua -l set_paths my_script.lua
Running tests with busted:
busted --helper=set_paths
Do not include require("set_paths") in your code, scroll up to see why.
Installing packages to the local tree, or the home directory, requires the
--local flag to be passed to the luarocks install install command. This is
the recommended way to install packages that are generally available because it
does not require root access to perform the installation.
$ luarocks install --local moonscript
The LUA_PATH and LUA_CPATH should be configured. This can be done with the
luarocks path command as discussed above.
print(require("moonscript"))
Installing packages in the system tree requires root access. Prefixing the
luarocks command with sudo is a common way to install global packages:
$ sudo luarocks install moonscript
Installing globally is not recommended since it requires root access. Use the local tree to install packages and make them available for all your scripts.
1: The distinction isn’t always clear, but a package is synonymous
with a library, and a module is an individual thing (.lua file, shred
library) you can include from that package. I tend to use them interchangeably.
A community LuaRocks hosting repository
leafo.net · Generated Sun Oct 8 13:02:35 2023 by Sitegen mastodon.social/@leafo