Byzantine Reality

Searching for Byzantine failures in the world around us

C, SWIG, and Java

As promised, today we’re going to look at SWIG. The basic idea of SWIG can be summarized as follows:

Got code in C or C++ that you want to use with your favorite language? Well then look no further! SWIG is the thing for you!

This is essentially the Wrapper Facade from POSA 2 in three sentences instead of many pages (although much less convincing than POSA 2 did it). We’ve been rambling about how they could only use C++ to make C code object-oriented, but that it’s not entirely their fault since they wrote the book in the year 2000. Last time we mentioned the ctypes library as an easy way for Python programmers to use C code, but the downside was you could only do this in Python.

SWIG aims to do what ctypes does for Python but for many other languages. It boasts that it can take C code and make it accessible to C#, Common Lisp, Ruby, and many others. 

As I’ve always wanted to wrap my C code in Java code, we’ll be looking at using SWIG to “automatically” generate Java Native Interface (JNI) code that we can then use to solve the same problem from last time. This is particularly appealing to me since I have no experience with writing JNI code and have heard that it is particularly unpleasant.

That being said, a quick recap is in order, especially if you missed our last post. We want to take some Ccode that sends and receives data blocks to and from a server and wrap it in some Java code to make it thread-safe. We are aware of the fact that C can trivially do this (e.g., pthreads) but want to use Java to illustrate that in case we want to add object-oriented functionality or other wonderful things that the POSA 2 book describes in better detail. So to reiterate, here is our C code (like last time, note that the spaces in < stdio.h > need to be removed and were only there because of weird formatting issues):


#include < stdio.h >


int* get_data(int block_number) {
   
// do some input validation here
    printf
("Retrieving block %d\n", block_number);
   
int* dummy_data;
   
return dummy_data;
}

void send_data(int block_number, int* data) {
   
// do some input validation here
    printf
("Committing block %d\n", block_number);
}

So once you’ve installed the SWIG package, you need to make a template version of your C code (analogous to a .h file for your .c file). Having looked over the tutorial, ours looks like this:

/* ccode.i */
%module ccode
%{
extern int* get_data(int block_number);
extern void send_data(int block_number, int* data);
%}

extern int* get_data(int block_number);
extern void send_data(int block_number, int* data);

Note that we follow their tutorial’s example and put a copy of the method signatures outside the %s (although it’s not particularly obvious why this is needed). Now we can just run each of these commands to generate the “glue” code that our Java code will use:


swig
-java ccode.i
gcc
-c ccode.c ccode_wrap.c -I(location of jni.h)
ld
-bundle -flat_namespace -undefined suppress -o libccode.dylib ccode.o ccode_wrap.o

The idea is that although this process is mucky (and presumably it is for non-trivially sized C code), we now can generate glue code for (almost) any language. Some things to make a note of here before we go much further. So the first line takes your interface file (here, ccode.i) and produces the wrapper (ccode_wrap.c). Last time I named my ccode.c file as c-code.c, but SWIG doesn’t care very much for the dash and the error message doesn’t help much. The more interesting thing to note is that we have to generate the .i file ourselves. It seems that since it just has the method signatures that a C parser or regex program could easily accomplish this, but alas none is available yet.

So on the second line, note that we have to include some header files based on our output language (here Java), so you’ll need to do a “locate jni.h” to find the right directory to include. Most importantly is the last line. Our dynamic library must be named lib(original name).dylib if you’re on a Mac (or presumably .so.1 if you’re on Linux). This is completely NOT documented and had to find it on a random message board, so I’ll say it again where the formatting ensures you will see it:


The dynamic library for ccode.c MUST be named libccode.dylib on Mac OS X (try out .so.1 on Linux)

This is a lot of bullshit to go through if you didn’t have this guide to help you out (since the SWIG tutorial is ‘meh’ at best). Presuming you got through all that nonsense alright, you’re in the clear. SWIG generates tons of fun glue for you and you can end the day with this very simple Java code:

class RealWrapper {
   
private static boolean libLoaded = false;

   
public RealWrapper() {
       
if (libLoaded == false) {
           
System.loadLibrary("ccode");
            libLoaded
= true;
           
System.out.printf("C library loaded successfully.\n");
       
}
   
}

   
public synchronized SWIGTYPE_p_int getData(int blockNumber) {
       
return ccode.get_data(blockNumber);
   
}

   
public synchronized void sendData(int blockNumber, SWIGTYPE_p_int data) {
        ccode
.send_data(blockNumber, data);
   
}
}

Java solves our problem easier than Python did (no need to break encapsulation here since we’ve got static variables) although there is some ugliness from having to see the weird SWIG object types, but presumably there is some function that can convert these to familiar versions of the same object. Now, let’s wrap this up with our main method:

public class main {
   
public static void main(String argv[]) {
     
RealWrapper rw = new RealWrapper();
     
SWIGTYPE_p_int data = rw.getData(10);
     rw
.sendData(10, data);
   
}
 
}

So now we have an alternative to Python’s ctypes library that we can use for many of the “mainstream” programming languages. Since most languages also provide some way to talk to C code, these methods combined with SWIG provide a way to make a Wrapper Facade ala POSA 2 to give your C code new life as objects and all the fun stuff that goes along with that.

We could do many more posts about other technologies that are alternatives to this (for example, JNA is promising for Java, JRuby, and Jython), but I feel like I’ve beat the point into the ground that the POSA 2 guys now have reasonable alternatives to using only C++ to wrap C code in. Next time though I’ll give a solution to another gripe I had about one of their other patterns.

This brings up another good point. Why even care about this? Why gripe about a book that seems to be riddled with problems? It’s because the book has so much potential! The patterns for concurrency and networked objects are great! But it’s completely unreasonable to assume that we will only use C++ to do this. It may have been fine eight years ago, but not now. There are new, better ways to do this, so I see this as a way to give back. This is more of a “it’s a great book but this is what it really needs to be great and live up to its promises” kind of thing. (And on a purely selfish note, it helps me become better familiar with these technologies.)