The Challenge of Cross-Language Interoperability
CowboyRobot writes "David Chisnall of the University of Cambridge describes how interfacing between languages is increasingly important. You can no longer expect a nontrivial application to be written in a single language. High-level languages typically call code written in lower-level languages as part of their standard libraries (for example, GUI rendering), but adding calls can be difficult. In particular, interfaces between two languages that are not C are often difficult to construct. Even relatively simple examples, such as bridging between C++ and Java, are not typically handled automatically and require a C interface. The problem of interfacing between languages is going to become increasingly important to compiler writers over the coming years."
As someone who's done a fair bit of the reverse, and has recently needed to write C bindings for a few other languages (go, ruby), I thought this shouldn't be nearly so hard as you describe. Here's what I've come up with:
Example.cpp: Implements a class and C bindings for that class (The bindings could obviously be in a different file)
#include "ExampleCBindings.h"
#include
class Example {
public:
Example(int v) { value = v; std::cout << "New Example(" << v << ")\n"; }
~Example() { std::cout << "Deleting Example(" << value << ")\n"; }
int getValue() { return value; }
private:
int value;
};
extern "C" {
Example_class* newExample(int value) { return (Example_class*) new Example(value); }
void deleteExample(Example_class* example) { delete (Example*) example; }
int ExampleGetValue(Example_class* example) { return ((Example*) example).getValue(); };
}
ExampleCBindings.h: Public C bindings // what I love most is that Example_t never exists ;)
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Example_t Example_class;
Example_class* newExample(int value);
void deleteExample(Example_class* example);
int ExampleGetValue(Example_class* example);
#ifdef __cplusplus
}
#endif
main.c: Simple C driver program that uses the api
#include "ExampleCBindings.h"
int main() {
Example_class * ex1 = newExample(5);
Example_class * ex2 = newExample(ExampleGetValue(ex1) + 2);
deleteExample(ex1);
deleteExample(ex2);
return 0;
}
Limitations include:
* Does not support objects existing on the stack. You're in C, this is the norm for opaque data structures.
* Need to individually wrap every function. Would need to create separate wrappers for overloaded functions, or write a variadic function that doesn't enforce types (Sigh, neither language supports reflection)
However, if you only wish to implement public functions, writing a script that autogenerates a wrapper like this would be fairly easy (I've done similar for a mocking framework for C code - now that's actually painful (not the script, inserting stubbed functions into a binary)). A little googling came up with a more formal attempt here.