trader • programmer • spiritual teacher • patriot • hero • enlightened master

Using ØMQ / ZeroMQ with Vagrant and VirtualBox

Install a Vagrant virtual machine.

The documentation of Vagrant is excellent. You can create a small Ubuntu VM to play with in just a few minutes. On OS X it installs from a standard .dmg / .pkg combination via the GUI.

Once you have your Vagrant installation, typing

vagrant init precise32 http://files.vagrantup.com/precise32.box

in a test directory initializes a new VM from a basic configuration provided by the Vagrant team.

The command vagrant up will boot your VM, and vagrant ssh will SSH to your VM. Note that these commands need to be typed in the directory where your Vagrantfile (config file) is located.

(Also note that you need to have VirtualBox installed in order to operate your VMs. Vagrant scripts VirtualBox command-line tools in order to control its VMs.)

Build and install a current version of ZeroMQ.

ZeroMQ is easy to build from source. The install process is very typical. Download the tarball, unpack it, and then perform the usual invocation:

sudo make install

Compile the ZeroMQ test client and server

By default, the header files and zmq libraries are installed to /usr/local

cc hwclient.c -o hwclient -I/usr/local/include/ -lzmq -L/usr/local/lib/
cc hwserver.c -o hwserver -I/usr/local/include/ -lzmq -L/usr/local/lib/

For anything more complex than this a Makefile is recommended but these toy examples are so simple that it doesn’t matter in this case.

If you compile one of these within in the VM and one in your host OS, then you can communicate between VM and host OS via ZeroMQ.

Gotchas and things to remember

  • need to run ‘ldconfig’ to configure new dynamically linked libraries after building ZeroMQ
  • remember to include path to the header files and shared libraries in /usr/local (see above)
  • don’t forget to pass the actual library to the linker via -lzmq

Running the server in a Vagrant VM, you can communicate between client and server across the virtual machine boundary. However, you will need to enable port forwarding in your Vagrantfile in order to make this possible. ZeroMQ defaults to port 5555, so forwarding 5555 in the guest OS to 5555 in the host OS makes this work transparently, as though it were operating within a single instance.

From this basic starting point, you can explore all sorts of interesting messaging configurations between “different” machines.

Building Lua modules on OS X

This is a useful note from Luiz Henrique de Figueiredo about building Lua modules on OS X:

If you’re running Mac OS X, then you’ll need to edit the Makefile and change -shared to -bundle -undefined dynamic_lookup.

He’s referring specifically to modules on his site, but the general advice is very useful.

As a nice example to play with, the latest version of LuaSocket can be found here.

Dynamic linking makes sure that you don’t get the “Multiple Lua VMs detected” error. It happens when you’ve linked multiple copies of liblua.a.

In some cases cryptic library import errors were solved by exiting and restarting the shell. This is most likely associated with the environment variables defining paths to installed libraries.

Using -std=c99 if you can is useful, as it opens up the conveniences of the C99 standard.

There seems to be some back-and-forth between luaL_register(L, "stack", Map); and luaL_openlib(L, "stack", Map, 0);. They do the same thing, and one is defined through a macro to be equivalent to the other, but using the wrong one seems to cause problems. Also, don’t mistake luaL_openlib for luaL_openlibs – the latter is a function called to enable access to all standard libraries from your C code.

Other things that will bite you on the ass:

You need to use luaL_Reg instead of luaL_reg. Case matters (and you say, duh it’s C. So, yeah.)

The same thing happens with luaL_register, and luaL_openlib. The former is supposed to map to the latter with a macro but it doesn’t seem to work perfectly.

luaL_register(L, "modulename", Map); // old and busted
luaL_openlib(L, "modulenamestr", Map, 0); // new hotness

This is defined in lauxlib.h, where the relevant definitions look like:

LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))