OCaml bindings for Coherence with SWIG

Way back in the day, I did some work programming in C++. But to be honest, I never really learnt C++; I learnt MFC and enough ATL to do COM. And then I decided to focus on Oracle and left it there. Nonetheless, I know enough about C++ to use it as a basis for OCaml bindings for Oracle Coherence, via SWIG. As ever, the code is on GitHub. This includes scripts for starting Coherence correctly for this project (in server/), and for testing that it is basically operational (in cpptest/).

I had hoped that the interface file declaring the C++ methods that we need for a very simple get/put on the Coherence grid would be as simple as the includes for cpptest.cpp:

%module cohml
%{
#include "coherence/lang.ns"
#include "coherence/net/CacheFactory.hpp"
#include "coherence/net/NamedCache.hpp"
#include <iostream> 
%}

%include "coherence/lang.ns"
%include "coherence/net/CacheFactory.hpp"
%include "coherence/net/NamedCache.hpp"

But it turned out not to be that straightforward. Trying various permutations of -importall and -I, I couldn’t find a way to get a clean SWIG compile, so I adopted a workaround of using a shared object as a proxy between SWIG and Coherence. Starting with a header file:

#ifndef COHML_H
#define COHML_H

#include "coherence/lang.ns"
#include "coherence/net/CacheFactory.hpp"
#include "coherence/net/NamedCache.hpp"
#include <iostream>

using namespace coherence::lang;
using coherence::net::CacheFactory;
using coherence::net::NamedCache;

class Cohml {
private:
  NamedCache::Handle hCache;
  String::View vsRet; // to keep the C string in scope
public:
  Cohml(char* cn);
  void put(char* k, char* v);
  const char* getCString(char* k);
  ~Cohml();
};

#endif

And the actual implementation:

#include "coherence/lang.ns"
#include "coherence/net/CacheFactory.hpp"
#include "coherence/net/NamedCache.hpp"
#include <iostream>
#include "cohml.hpp"

using namespace coherence::lang;
using coherence::net::CacheFactory;
using coherence::net::NamedCache;

Cohml::Cohml(char* cn) {
  String::View vsCacheName = cn;
  hCache = CacheFactory::getCache(vsCacheName);
}

void Cohml::put(char* k, char* v) {
  String::View vsKey = k; String::View vsVal = v;
  hCache->put(vsKey, vsVal);
}
  
const char* Cohml::getCString(char* k) {
  String::View vsKey = k;
  vsRet = cast<String::View>(hCache->get(vsKey));
  return vsRet->getCString();
}

Cohml::~Cohml() {
  CacheFactory::shutdown();
}

Now using a new SWIG interface, which is an annotated version of the header:

%module cohml
%{
#include "cohml.hpp"
%}

class Cohml {
 public:
  Cohml(char* cn);
  void put(char* k, char* v);
  const char* getCString(char* k);
  ~Cohml();
};

Next we use a rather elaborate Makefile for such a small amount of code (also suppressing unnecessary warnings for the sake of this example):

COHERENCE_HOME_CPP=/opt/coherence-cpp
CPP_INCL=-I$(COHERENCE_HOME_CPP)/include
CPP_LIB=-L$(COHERENCE_HOME_CPP)/lib

cohml:	cohml.o cohml_wrap.cxx.o swig.cmo cohml.cmo
	ocamlmktop -custom -ccopt $(CPP_LIB) -ccopt -lcoherence cohml.o cohml_wrap.cxx.o swig.cmo cohml.cmo -o $@

cohml.cmo:	cohml.cmi
	ocamlc -w -11 -c cohml.ml

cohml.cmi:	cohml_wrap.cxx.o
	ocamlc -c cohml.mli

cohml_wrap.cxx.o: cohml_wrap
	ocamlc -c -ccopt -xc++ -ccopt $(CPP_INCL) -ccopt -w cohml_wrap.cxx.c

swig.cmi:	swig.mli
	ocamlc -c $<

swig.cmo:	swig.cmi swig.ml
	ocamlc -w -20 -c swig.ml

cohml_wrap:	cohml.i
	swig -c++ -ocaml cohml.i
	cp cohml_wrap.cxx cohml_wrap.cxx.c

swig.mli:
	swig -ocaml -co $@

swig.ml:
	swig -ocaml -co $@

cohml.o:	cohml.cpp
	g++ -g3 -fPIC -c $(CPP_INCL) -I. $(CPP_LIB) -lcoherence $<

clean:
	rm -f *.o *.cmo *.cmi *.cxx.c *.ml* *_wrap.cxx cohml


Finally running it in a custom OCaml toplevel:

I wanted to try SWIG for this, as I had never used it before, and I am unlikely to use it again! I suppose unless confronted with an absolute mountain of pre-existing C++. The generated OCaml interface, once I finally managed† to get one, is horrible, e.g. new_Cohml, rather than behaving like a normal object, method calls as strings and the additional import of the Swig module, not to mention the convoluted build process. At this level of complexity it’s entirely feasible to do it all by hand using OCaml’s C interface with which I am already quite familiar, in fact it would have been quicker and easier.

This is not actually very useful yet for “real work” (well, what I want to do anyway), until I can also do MapListener (change notification) or Continuous Query – I would like to build these “on the fly” on the OCaml side, like I do for object types in AQ. Otherwise it will need a new C++ stub for every different data type/query predicate‡. Having said that, I do advocate freely mixing languages where it makes sense, and it’s possible that the C++ could be automagically generated in many cases. Maybe with SWIG, but I’d prefer not to.

Before pressing on I will completely rewrite this in style similar to OCI*ML… Nevertheless, this is sufficient to prove that OCaml can get a foothold in a Coherence grid. Hopefully this post will also serve as a warning to anyone following in my footsteps!

† To be fair, Coherence is probably pretty exotic, even as C++ goes, and SWIG is designed for languages like Tcl/Tk rather than OCaml
‡ In which case I will go back and learn it properly!

About Gaius

Jus' a good ol' boy, never meanin' no harm
This entry was posted in C++, Coherence, COHML, Ocaml, Operation Foothold, Oracle. Bookmark the permalink.

3 Responses to OCaml bindings for Coherence with SWIG

  1. Pingback: OCaml bindings for Coherence (2) | So I decided to take my work back underground

  2. Pingback: Putting it all together: PubSub for OCaml with Coherence | So I decided to take my work back underground

  3. Pingback: Real World OCaml | So I decided to take my work back underground

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s