2012-02-26

Lowering the (re)bar

Although the Erlang programming language has been on my radar for many years now, I never quite grasped the concept of how to put things together such that a bundle of functionality might be properly deployed to and run on a target system. The target system would of course be Linux :)

Fortunately, in the last couple of years an effort has emerged that promises to make things easier. It's a tool called rebar, and its canonical use seems to serve as the build system for a database application by the name riak. Some of the participant's names on the rebar mailing list ring familiar, so it seems possible that it may even be adopted into OTP at some point.

There are quite a number of "getting started" tutorials around for rebar, one right inside the rebar github wiki, and also this one being still quite recent early in 2012. rebar is (or at least has been) a moving target, and some tutorials you may find are badly outdated.

However even following the supposedly applicable instructions, I invariably ran into this error at the generate stage:
$ ./rebar generate
==> rel (generate)
{"init terminating in do_boot","Release exemplar uses non existing application exemplar"}

Crash dump was written to: erl_crash.dump
init terminating in do_boot (Release exemplar uses non existing application exemplar)

It took me quite a while to get past this problem, and the key here is that the Erlang runtime needs to accept your working directory as an application, which requires two things to be true:
  1. The directory that contains the src and ebin directories, as well as rebar.config (not rebar.conf btw!) needs to have exactly the same name as the Erlang application you are creating.
  2. The directory which comprises that application directory needs to be part of Erlang's lib_dirs (an extension searchpath for /usr/lib/erlang/lib) so it will be considered by the runtime when it is looking for applications.
What is left out by all the tutorials I found is that for #2 to become true, one needs to manually edit the reltool.config file that is created by the rebar create-node step and edit the lib_dirs assignment to include that parent directory (can be an absolute path, or given relative from the rel directory).

So if you are trying this out in /tmp/exemplar like
/tmp/exemplar
|-- deps
|   `-- exemplar
|       |-- ebin
|       `-- src
|           |-- exemplar_app.erl
|           |-- exemplar.app.src
|           `-- exemplar_sup.erl
|-- rebar.config
`-- rel
    |-- exemplar
[...]
    |-- files
    |   |-- erl
    |   |-- exemplar
    |   |-- exemplar.cmd
    |   |-- nodetool
    |   |-- start_erl.cmd
    |   |-- sys.config
    |   `-- vm.args
    `-- reltool.config
then your /tmp/exemplar/rel/reltool.config file should be changed to start like
{sys, [
       {lib_dirs, ["/tmp/exemplar/deps"]},
[...]
At first I was wondering whether this manual edit is really the right thing to do since this file is generated, but checking out the riak rel directory, the reltool.config file there is checked into git and also contains a manual lib_dirs assignment.

Another mistake to avoid is naming your node (rebar create-node nodeid=<name>) anything different from your main application, which will result in an obscure error message

Command 'generate' not understood or not applicable