Skip to content

Integrating distro modules with LuaRocks

Hisham Muhammad edited this page Mar 21, 2016 · 2 revisions

This is documentation on strategies to integrate OS-installed modules (e.g. packages such as luafilesystem and lpeg provided by Linux distros) with existing versions of LuaRocks.

This page will list two approaches: the minimal one, and a more complete one that extends the first one.

Assumptions

  • The examples below use Lua 5.3 — just change "5.3" to "5.1" or "5.2" and the same applies.
  • Distro-installed modules live at standard Lua locations under /usr, such as /usr/lib/lua/5.3/lfs.so

The bare minimum approach

This is the minimum that should be added to distro module packages so that they visible as dependencies by LuaRocks:

The main manifest file

For LuaRocks to be able to find any OS-installed modules, there needs to be an index file called manifest at /usr/lib/luarocks/rocks-5.3/.

This file should be generated running:

luarocks-admin make-manifest --local-tree --tree=/usr

This should be run as a post-install action after installing any module via the distro. This file is the LuaRocks "index" and should be kept up-to-date or else LuaRocks doesn't know about the installed modules.

Rock metadata necessary to build the main manifest

For the above command to work, there has to be a directory tree for each rock and version, containing, at the bare minimum, a rock_manifest file. The structure looks like this:

/usr/lib/luarocks/rocks-$LUA_VERSION/$ROCK_NAME/$ROCK_VERSION-$ROCK_REVISION/

  • $LUA_VERSION with with a dot: "5.3"

  • $ROCK_NAME should match the name used in the luarocks.org repository — in other words, luafilesystem has to be called luafilesystem, not lfs. LuaRocks checks dependencies by rock name, not by individual module name.

  • $ROCK_VERSION usually matches upstream, so that's not an issue.

  • $ROCK_REVISION can always be 0 for our purposes here.

Examples:

  • /usr/lib/luarocks/rocks-5.3/lpeg/1.0.0-0/
  • /usr/lib/luarocks/rocks-5.3/luafilesystem/1.6.0-0/
  • /usr/lib/luarocks/rocks-5.3/lua-cjson/2.1.0-0/

The rock_manifest file

Inside the version directory for a rock there must be a rock_manifest file. The minimal contents of rock_manifest to make luarocks-admin not fail is simply:

rock_manifest = {}

This means that in the above examples, we'd have several identical one-liner files:

  • /usr/lib/luarocks/rocks-5.3/lpeg/1.0.0-0/rock_manifest
  • /usr/lib/luarocks/rocks-5.3/luafilesystem/1.6.0-0/rock_manifest
  • /usr/lib/luarocks/rocks-5.3/lua-cjson/2.1.0-0/rock_manifest

Necessary LuaRocks configuration

With those empty manifests, the post-install operation mentioned above works and a later luarocks install will the existence of the "rocks" in /usr, given the following configuration in /etc/luarocks/config-5.3.lua:

rocks_trees = {
   { name = "user", root = home.."/.luarocks" },
   { name = "distro-modules", root = "/usr" },
   { name = "system", root = "/usr/local" },
}
deps_mode = "all"

It's important that the "system" tree is the last entry: it is the one used for system-wide installation of rocks using LuaRocks (when sudo luarocks is used). The "distro-modules" tree should never be used directly by the user.

For more info on the deps_mode flag, see the Dependency modes documentation.

Caveats

  • Error messages: Running with such bare minimum setup will resolve dependencies, but running the post-install operation above will output error messages when running, such as...
Tree inconsistency detected: luafilesystem 1.6.0-0 has no rockspec. Could not load rockspec file /usr/lib/luarocks/rocks-5.3/luafilesystem/1.6.0-0/luafilesystem-1.6.0-0.rockspec (/usr/lib/luarocks/rocks-5.3/luafilesystem/1.6.0-0/luafilesystem-1.6.0-0.rockspec: No such file or directory)"

...for each entry under /usr/lib/luarocks/rocks-5.3 (for our purposes, these can be simply ignored and silenced away with &> /dev/null).

  • Failed commands: this minimal tree will work for solving dependencies, but not for much else. In particular, luarocks list --tree=/usr will work, but luarocks show lpeg --tree=/user will not, complaining that it can't find a rockspec.

A more complete approach

A more complete approach to make commands such as luarocks show to work would entail two steps: adding proper contents to rock_manifest and including a rockspec file for each module.

A complete rock_manifest

A workable version of rock_manifest with contents would look like this:

rock_manifest = {
   lib = {
      ["lpeg.so"] = "136a74c6e472c36a65449184e1820a31"
   },
   ["lpeg-1.0.0-0.rockspec"] = "4933a611af43404761002ee139c393e8",
   lua = {
      ["re.lua"] = "5f09bb0129b09b6a8e8c1db1b206b1ca"
   }
}

The entries under lib are the files installed by the package at /usr/lib/5.3. The entries under lua are the files installed by the package at /usr/share/5.3. The rockspec key is the rockspec file to be stored alongside the rock_manifest file. The values to these entries are MD5 sums to the files in question.

Including a rockspec file

For luarocks show to display metadata properly, a rockspec file must exist. It should be named according to the pattern $ROCK_NAME-$ROCK_VERSION-$ROCK_REVISION.rockspec (in all lowercase). Continuing the examples above:

  • /usr/lib/luarocks/rocks-5.3/lpeg/1.0.0-0/lpeg-1.0.0-0.rockspec
  • /usr/lib/luarocks/rocks-5.3/luafilesystem/1.6.0-0/luafilesystem-1.6.0-0.rockspec
  • /usr/lib/luarocks/rocks-5.3/lua-cjson/2.1.0-0/lua-cjson-2.1.0-0.rockspec

For simplicity, I would recommend just copying over the appropriate rockspec file from luarocks.org and bundling them in the package metadata. For completeness, this is how the one for LPeg 1.0 looks like:

package = "LPeg"
version = "1.0.0-1"
source = {
   url = "http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.0.tar.gz",
   md5 = "0aec64ccd13996202ad0c099e2877ece",
}
description = {
   summary = "Parsing Expression Grammars For Lua",
   detailed = [[
      LPeg is a new pattern-matching library for Lua, based on Parsing
      Expression Grammars (PEGs). The nice thing about PEGs is that it
      has a formal basis (instead of being an ad-hoc set of features),
      allows an efficient and simple implementation, and does most things
      we expect from a pattern-matching library (and more, as we can
      define entire grammars).
   ]],
   homepage = "http://www.inf.puc-rio.br/~roberto/lpeg.html",
   maintainer = "Gary V. Vaughan <gary@vaughan.pe>",
   license = "MIT/X11"
}
dependencies = {
   "lua >= 5.1"
}
build = {
   type = "builtin",
   modules = {
      lpeg = {
         "lpcap.c", "lpcode.c", "lpprint.c", "lptree.c", "lpvm.c"
      },
      re = "re.lua"
   }
}
Clone this wiki locally