RabbitMQ is an Erlang application. The language moves fast and every new release has performance optimizations. This is good until you try to install the RabbitMQ DEB package in your Debian-like server and you see that the package manager installed an old version of Erlang.

For Debian Squeeze, the package erlang-nox comes with Erlang R14A (released in June’s 2010). The backports package comes with Erlang R15B01 (released in April’s 2012). For the current Ubuntu LTS (Precise), erlang-nox comes with Erlang R14B04 (released in October’s 2011) while the latest Raring package - like Debian Squeeze backports - comes with Erlang R15B01.

This post shows how to compile the latest Erlang release (R16B) in Debian Squeeze and how to satisfy the erlang-nox dependency of the RabbitMQ DEB package.

Compiling Erlang

The compilation process is very straightforward, we’ll basically follow the steps available in the official Erlang’s documentation. First, install some of its dependencies:

$ sudo aptitude install -y build-essential libssl-dev ncurses-dev m4

Explaining the dependencies:

  • build-essential: list of packages considered essential to build Debian packages. Some of these packages are needed to compile Erlang like gcc and make
  • libssl-dev: needed for SSL support
  • ncurses-dev: for improved terminal support
  • m4: needed to compile with HiPE support (High Performance Erlang)

Then download and compile Erlang:

$ sudo mkdir -p /opt/src/erlang /opt/erlang
$ cd /opt/src/erlang
$ sudo curl -O http://www.erlang.org/download/otp_src_R16B.tar.gz
$ sudo tar xzvf otp_src_R16B.tar.gz
$ sudo mv otp_src_R16B r16b
$ cd r16b
$ sudo ./configure --prefix=/opt/erlang/r16b --enable-hipe --with-ssl
$ sudo make
$ sudo make install

Finally, symlink the Erlang binaries (if you don’t want to use symbolic links, you can run configure with the --bindir=/usr/bin option):

$ sudo ln -s /opt/erlang/r16b/bin/dialyzer /usr/bin
$ sudo ln -s /opt/erlang/r16b/bin/epmd /usr/bin
$ sudo ln -s /opt/erlang/r16b/bin/erl /usr/bin
$ sudo ln -s /opt/erlang/r16b/bin/erlc /usr/bin
$ sudo ln -s /opt/erlang/r16b/bin/run_erl /usr/bin
$ sudo ln -s /opt/erlang/r16b/bin/run_test /usr/bin
$ sudo ln -s /opt/erlang/r16b/bin/typer /usr/bin

Installing RabbitMQ

Download the RabbitMQ DEB package available on the project’s website:

$ cd /tmp && curl -O http://www.rabbitmq.com/releases/rabbitmq-server/v3.1.0/rabbitmq-server_3.1.0-1_all.deb

As we already discussed, this package depends on the erlang-nox package:

$ dpkg -I rabbitmq-server_3.1.0-1_all.deb
 Package: rabbitmq-server
 Version: 3.1.0-1
 Architecture: all
 Maintainer: RabbitMQ Team <packaging@rabbitmq.com>
 Installed-Size: 4460
 Depends: erlang-nox (>= 1:12.b.3) | esl-erlang, adduser, logrotate
 Section: net
 Priority: extra
 Homepage: http://www.rabbitmq.com/
 Description: AMQP server written in Erlang
  RabbitMQ is an implementation of AMQP, the emerging standard for high
  performance enterprise messaging. The RabbitMQ server is a robust and
  scalable implementation of an AMQP broker.

If you try to install the package using aptitude, the package manager will install an old version of Erlang. The easiest way to prevent this is to use dpkg with the --ignore-depends option:

$ sudo dpkg -i --ignore-depends=erlang-nox
(Reading database ... 42128 files and directories currently installed.)
Preparing to replace rabbitmq-server 3.1.0-1 (using rabbitmq-server_3.1.0-1_all.deb) ...
Unpacking replacement rabbitmq-server ...
Setting up rabbitmq-server (3.1.0-1) ...
Adding group `rabbitmq' (GID 107) ...
Done.
Adding system user `rabbitmq' (UID 105) ...
Adding new user `rabbitmq' (UID 105) with group `rabbitmq' ...
Not creating home directory `/var/lib/rabbitmq'.
Starting message broker: rabbitmq-server.
Processing triggers for man-db ...

You can check that RabbitMQ is running using the rabbitmqctl command:

$ sudo rabbitmqctl status
Status of node rabbit@squeeze64 ...
[{pid,1776},
 {running_applications,[{rabbit,"RabbitMQ","3.1.0"},
                        {mnesia,"MNESIA  CXC 138 12","4.8"},
                        {os_mon,"CPO  CXC 138 46","2.2.11"},
                        {xmerl,"XML parser","1.3.3"},
                        {sasl,"SASL  CXC 138 11","2.3.1"},
                        {stdlib,"ERTS  CXC 138 10","1.19.1"},
                        {kernel,"ERTS  CXC 138 10","2.16.1"}]},
...

Resolving the dependency

What we did when installing RabbitMQ was to simply ask dpkg to ignore the dependency during the installation transaction. The problem is that for the package manager, the dependency is still unfulfilled. If you try to install or upgrade a package, the package manager will suggest to remove the rabbitmq-server package because of its unmet dependency:

$ sudo aptitude install tree
The following NEW packages will be installed:
  tree
0 packages upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 32.4 kB of archives. After unpacking 98.3 kB will be used.
The following packages have unmet dependencies:
  rabbitmq-server: Depends: erlang-nox (>= 1:12.b.3) but it is not going to be installed. or
                            esl-erlang which is a virtual package.
The following actions will resolve these dependencies:

     Remove the following packages:
1)     rabbitmq-server

Accept this solution? [Y/n/q/?]

If you don’t accept the solution, aptitude will suggest the installation of a lot of Erlang-related packages. This is not what we want, we want to have RabbitMQ installed with the Erlang version that we’ve compiled. To resolve this dependency, we’ll create a dummy package using equivs. From the equivs-build documentantion: “equivs-build is a program that creates Debian packages which can be used to inform dpkg about locally installed packages and their dependencies. Also empty packages that just require other packages can be created with equivs. These can be used as “profile” packages which just mark other ones for installation.”

Before installing equivs, uninstall RabbitMQ:

$ sudo aptitude purge -y rabbitmq-server

Then install equivs:

$ sudo aptitude install -y equivs

Create a file with the following contents:

Section: interpreters
Priority: optional
Standards-Version: 3.6.2

Package: erlang-nox
Version: 1:12.b.3
Maintainer: The Maintainer <maintainer@example.com>
Description: Dummy Erlang package.
  This package provides a dummy package for erlang-nox, a dependency of the rabbitmq-server package.

Or just copy and paste the following commands:

$ erlang_nox="Section: interpreters
Priority: optional
Standards-Version: 3.6.2

Package: erlang-nox
Version: 1:12.b.3
Maintainer: The Maintainer <maintainer@example.com>
Description: Dummy Erlang package.
  This package provides a dummy package for erlang-nox, a dependency of rabbitmq-server package from RabbitMQ."
$ IFS='%'; echo $erlang_nox > erlang-nox; unset IFS

Then run the equivs-build command to create the DEB package:

$ equivs-build erlang-nox
...
dpkg-deb: building package `erlang-nox' in `../erlang-nox_12.b.3_all.deb'.

The package has been created.
Attention, the package has been created in the current directory,
not in ".." as indicated by the message above!

Now, install the created DEB package and the RabbitMQ DEB package:

$ sudo dpkg -i erlang-nox_12.b.3_all.deb rabbitmq-server_3.1.0-1_all.deb

You can check that the dummy package was installed:

$ aptitude show erlang-nox
Package: erlang-nox
State: installed
Automatically installed: no
Version: 1:12.b.3
Priority: optional
Section: interpreters
Maintainer: The Maintainer <maintainer@example.com>
Uncompressed Size: 36.9 k
Description: Dummy Erlang package.
 This package provides a dummy package for erlang-nox, a dependency of rabbitmq-server package from RabbitMQ.

Now you don’t need to worry about aptitude complaining about the unmet dependency of the rabbitmq-server package. At least not while trying to install new packages. Hold on…

Marking the package as held

Everything is fine until you try to upgrade the packages from your system and you see something like this:

$ sudo aptitude safe-upgrade
Resolving dependencies...
The following NEW packages will be installed:
  erlang-asn1{a} erlang-base{a} erlang-corba{a} erlang-crypto{a} erlang-docbuilder{a} erlang-edoc{a} erlang-erl-docgen{a} erlang-eunit{a}
  erlang-ic{a} erlang-inets{a} erlang-inviso{a} erlang-mnesia{a} erlang-odbc{a} erlang-os-mon{a} erlang-parsetools{a} erlang-percept{a}
  erlang-public-key{a} erlang-runtime-tools{a} erlang-snmp{a} erlang-ssh{a} erlang-ssl{a} erlang-syntax-tools{a} erlang-tools{a} erlang-webtool{a}
  erlang-xmerl{a} libltdl7{a} libsctp1{a} lksctp-tools{a} odbcinst{a} odbcinst1debian2{a} unixodbc{a}
The following packages will be upgraded:
  erlang-nox
1 packages upgraded, 31 newly installed, 0 to remove and 0 not upgraded.
Need to get 20.8 MB of archives. After unpacking 36.5 MB will be used.
Do you want to continue? [Y/n/?]

Look at the erlang-nox file we created before. It declares it version as 1:12.b.3 while the Debian Squeeze erlang-nox package version is 1:14.a-dfsg-3squeeze1. If we created the dummy package declaring a most recent version, we’d have the same problem if a new version was released.

To resolve this, just mark the package as held with aptitude:

$ sudo aptitude hold erlang-nox

aptitude show will show the package as installed and held:

$ aptitude show erlang-nox
Package: erlang-nox
State: installed [held]
...

Now you are free from the package constraints and use the desired Erlang version for running not just RabbitMQ but any Erlang application!