Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Erlang C++ Interface
C++ Shell
Tag: v1.0

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.


eixx - Erlang C++ Interface Library

This library provides a set of classes for convenient marshaling
of Erlang terms between processes as well as connecting to other
distributed Erlang nodes from a C++ application.

The marshaling classes are built on top of ei library included in
{@link erl_interface}.
It is largely inspired by the {@link epi}
project, but is a complete rewrite with many new features and 
optimization enhancements.

This library adds on the following features:
  - Use of reference-counted smart pointers for complex terms and
    by-value copied simple terms (e.i. integers, doubles, bool, atoms).
  - Ability to provide custom memory allocators.
  - Encoding/decoding of nested terms using a single function call
    (eterm::encode() and eterm::eterm() constructor).
  - Global atom table for fast manipulation of atoms.

The library consists of two separate parts:
  - Term marshaling (included by marshal.hpp or eixx.hpp)
  - Distributed node connectivity (included by connect.hpp or eixx.hpp)

The connectivity library implements a richer set of features than
what's available in erl_interface - it fully supports process
linking and monitoring.  The library is fully asynchronous and allows
handling many connections and mailboxes in one OS thread.

Ths library is dependend on {@link BOOST}
project and erl_interface, which is a part of the 
{@link Erlang} distribution.

    Repository location:

    $ git clone

    Make sure that you have autoconf-archive package installed:

    $ ./bootstrap
    $ ./configure --with-boost="/path/to/boost" [--with-erlang="/path/to/erlang"] \
    $ make
    $ make install      # Default install path is ./install

    Serge Aleynikov <saleyn at gmail dot com>

    GNU Lesser General Public License


Here's an example use of the eixx library:

    void on_message(otp_mailbox& a_mbox, boost::system::error_code& ec) {
        // On timeout ec == boost::asio::error::timeout
        if (ec == boost::asio::error::timeout) {
            std::cout << "Mailbox " << a_mbox.self() << " timeout: "
                      << ec.message() << std::endl;
        } else {
            // The mailbox has a queue of transport messages.
            // Dequeue next message from the mailbox.
            boost::scoped_ptr<transport_msg> dist_msg;

            while (dist_msg.reset(a_mbox.receive())) {
                std::cout << "Main mailbox got a distributed transport message:\n  "
                          << *p << std::endl;

                // Use the following pattern for a pattern match on the message.
                static const eterm s_pattern = eterm::format("{From, {command, Cmd}}");

                varbind binding;

                if (s_pattern.match(dist_msg->msg(), &binding)) {
                    const eterm* cmd = binding->find("Cmd");
                    std::cout << "Got a command " << *cmd << std::endl;
                    // Process command, e.g.:
                    // process_command(binding["From"]->to_pid(), *cmd);
        // Schedule next async receive of a message (can also provide a timeout).

    void on_connect(otp_connection* a_con, const std::string& a_error) {
        if (!a_error.empty()) {
            std::cout << a_error << std::endl;

        // Illustrate creation of Erlang terms.
        eterm t1 = eterm::format("{ok, ~i}", 10);
        eterm t2 = tuple::make(10, 1.0, atom("test"), "abc");
        eterm t3("This is a string");
        eterm t4(tuple::make(t1, t2, t3));

        otp_node*    node = a_con->node();
        otp_mailbox* mbox = node->get_mailbox("main");

        // Send a message: {{ok, 10}, {10, 1.0, 'test', "abc"}, "This is a string"}
        // to an Erlang process named 'test' running
        // on node "abc@myhost"

        node->send(mbox.self(), a_con->remote_node(), atom("test"), t4);

    int main() {
        use namespace eixx;

        otp_node node("abc");

        otp_mailbox* mbox = node.create_mailbox("main");

        node.connect(&on_connect, "abc@myhost");

        // Asynchronously receive a message with a deadline of 10s:
        mbox->async_receive(&on_message, 10000);;

Testing distributed transport

$ make

Run tests:

    $ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./test_eterm

Test distributed transport:

    $ cd src

    # In this example we assume the host name of "fc12".

    [Shell A]$ erl -sname abc
    (abc@fc12)1> register(test, self()).

    [Shell B]$ ./test_node -n a@fc12 -r abc@fc12
    Connected to node: abc@fc12
    I/O server got a message:
                    {put_chars,<<"This is a test string">>}}}

The message above is a result of the on_connect() handler in test_node.cpp
issuing an rpc call to the abc@fc12 node of `io:put_chars("This is a test 
string")'. This the call selects a locally registered process called 
'io_server' as the group leader for this rpc call, the I/O output is sent 
to that mailbox.

Now you can try to send a message from Erlang to the 'main' mailbox
registered on the C++ node:

    [Shell A]
    (abc@fc12)2> {main, a@fc12} ! "This is a test!".

    [Shell B]
    Main mailbox got a message:
            msg="This is a test!"}

Something went wrong with that request. Please try again.