Skip to content

Creating a Makefile that plays nice with LuaRocks

gz@tset.de edited this page Jan 8, 2021 · 3 revisions

The page about Recommended practices for Makefiles mentions what you should do in order to create a Makefile that LuaRocks can work with. What it does not do is to explain how to interact between your rockspec and the Makefile so that your rock will install in a way such that LuaRocks knows everything it needs to know to handle everything after the installation (like, for example, removal).

LuaRocks creates a few very important variables for you, that you can pass to your Makefile. They come in 2 varieties, one set for building the module and another set for installing it. The variables are:

For building:

  • CFLAGS - flags for the C compiler
  • LIBFLAG - the flags needed for the linker to create shared libraries
  • LUA_LIBDIR - where to find the lua libraries
  • LUA_BINDIR - where to find the lua binary
  • LUA_INCDIR - where to find the lua headers
  • LUALIB - the name of the lua library. This is not available nor needed on all platforms.
  • LUA - the name of the lua interpreter
For installing:
  • PREFIX - basic installation prefix for the module
  • BINDIR - where to put user callable programs or scripts
  • LIBDIR - where to put the shared libraries
  • LUADIR - where to put the lua files
  • CONFDIR - where to put your modules configuration
Most of these variables point immediately where you'd expect them to, but BINDIR, LIBDIR and LUADIR are special. These point to a location where you need to put the files in order for LuaRocks to move them to their final destination. If you install your stuff here, then LuaRocks will know what files your module installed and can later remove them.

These variables are not readily available in the Makefile, you need to tell LuaRocks to pass them to make. A simple rockspec that will do this looks like this:

   package = "lrtest"
   version = "1.0-1"
   source = {
      url = "http://..."
   }
   build = {
      type = "make",
      build_variables = {
         CFLAGS="$(CFLAGS)",
         LIBFLAG="$(LIBFLAG)",
         LUA_LIBDIR="$(LUA_LIBDIR)",
         LUA_BINDIR="$(LUA_BINDIR)",
         LUA_INCDIR="$(LUA_INCDIR)",
         LUA="$(LUA)",
      },
      install_variables = {
         INST_PREFIX="$(PREFIX)",
         INST_BINDIR="$(BINDIR)",
         INST_LIBDIR="$(LIBDIR)",
         INST_LUADIR="$(LUADIR)",
         INST_CONFDIR="$(CONFDIR)",
      },
   }

The corresponding Makefile looks like this:

   install:
   	@echo --- install
   	@echo INST_PREFIX: $(INST_PREFIX)
   	@echo INST_BINDIR: $(INST_BINDIR)
   	@echo INST_LIBDIR: $(INST_LIBDIR)
   	@echo INST_LUADIR: $(INST_LUADIR)
   	@echo INST_CONFDIR: $(INST_CONFDIR)

Now, if you call luarocks make, the output will look something like this:

   --- build
   CFLAGS: -O2 -fPIC
   LIBFLAG: -shared
   LUA_LIBDIR: /usr/local/lib
   LUA_BINDIR: /usr/local/bin
   LUA_INCDIR: /usr/local/include
   --- install
   INST_PREFIX: /usr/local/lib/luarocks/rocks/lrtest/1.0-1
   INST_BINDIR: /usr/local/lib/luarocks/rocks/lrtest/1.0-1/bin
   INST_LIBDIR: /usr/local/lib/luarocks/rocks/lrtest/1.0-1/lib
   INST_LUADIR: /usr/local/lib/luarocks/rocks/lrtest/1.0-1/lua
   INST_CONFDIR: /usr/local/lib/luarocks/rocks/lrtest/1.0-1/conf

You will notice that the aforementioned special variables do not point to the location you'd expect them to. LuaRocks will move files you put there to their final destination for you, and in the process keep track of what was installed.

The CONFDIR and PREFIX variables point to locations where you can store configuration or other data for your module. Your code must be made aware of these paths in order to use them. If you use the copy_directories entry in the build section of your rockspec, then what is mentioned there is copied to $(PREFIX) (i.e. a directory doc will be available unter $(PREFIX)/doc). If you copy directories in your install Makefile rule, you should do the same.

Now, if your Makefile is meant to be used standalone as well, which it probably is, you would also want to define these variables inside of your Makefile, but in such a way that it will not hinder LuaRocks. Luckily variables passed on the command line to make override those defined in the Makefile.

With this, a Makefile that is usable both from LuaRocks and standalone might look like this:

   INST_PREFIX = /usr/local
   INST_BINDIR = $(INST_PREFIX)/bin
   INST_LIBDIR = $(INST_PREFIX)/lib/lua/5.2
   INST_LUADIR = $(INST_PREFIX)/share/lua/5.2
   INST_CONFDIR = $(INST_PREFIX)/etc
   
   all:
   	@echo --- build
   	@echo CFLAGS: $(CFLAGS)
   	@echo LIBFLAG: $(LIBFLAG)
   	@echo LUA_LIBDIR: $(LUA_LIBDIR)
   	@echo LUA_BINDIR: $(LUA_BINDIR)
   	@echo LUA_INCDIR: $(LUA_INCDIR)
   
   install:
   	@echo --- install
   	@echo INST_PREFIX: $(INST_PREFIX)
   	@echo INST_BINDIR: $(INST_BINDIR)
   	@echo INST_LIBDIR: $(INST_LIBDIR)
   	@echo INST_LUADIR: $(INST_LUADIR)
   	@echo INST_CONFDIR: $(INST_CONFDIR)

You probably don't just want to echo stuff, so here's how to use the variables when actually building or installing something:

   all: lrtest.so
   
   lrtest.so: lrtest.o
   	$(CC) $(LIBFLAG) -o $@ -L$(LUA_LIBDIR) $<
   
   lrtest.o: lrtest.c
   	$(CC) -c $(CFLAGS) -I$(LUA_INCDIR) $< -o $@
   
   install: lrtest.so lrtest.lua
   	cp lrtest.so $(INST_LIBDIR)
   	cp lrtest.lua $(INST_LUADIR)

There is of course a lot more to a proper Makefile and rockspec, this is only to show how to take advantage of LuaRocks' builtin helpers for this sort of thing. Also, keep in mind that for additional external dependencies, more variables are created by LuaRocks, which have to be passed to the Makefile in the same way. Check the other documentation, especially Rockspec format and Recommended practices for Makefiles, for details.