This weekend I’ve added some rudimentary support for C++ to JNAerator (also in this version : merged latest fixes from Anarres JCPP and fixed a few Objective-C generation bugs).

There are two issues when trying to access C++ from Java with JNA :

  • Each C++ compiler has its own way of creating unique function signatures in its dynamic libraries. This process is called *name mangling*.

    The way JNA operates to bridge the Java and C languages, it needs the exact mangled name of each function that is to be bound to in the dynamic libraries of interest. It then takes some Java definitions and arguments and figures out a way to call the C functions correctly.

  • There are different specific calling conventions to respect (__thiscall, __fastcall), their choice depending on whether a method is static, has varargs…

I chose to start with a small scope and careful limitations :

  • Implemented name manglers for GCC4 & Microsoft Visual C++ 9 (express edition) only, just because they’re simply most likely the most common ones (I’ll try Intel’s compiler as soon as I can).
  • Only handle mangled functions and static methods (hence no issue of calling conventions yet)

After looking at the various parameters that influence name mangling, I came to the conclusion it would much easier to precompute mangled names for all known compilers during the sources generation pass (in JNAerator) rather than at the function binding time (in JNA).

Indeed, while the latter approach seems cleaner and more powerful (updating JNA with a new mangling scheme would enable all JNA libraries for use with a new C++ compiler instantly), it turns out it would require tons of annotations and/or generic types to convey the meta-data necessary to the mangling process. With the upcoming JSR 308, the code could look like :

`This weekend I’ve added some rudimentary support for C++ to JNAerator (also in this version : merged latest fixes from Anarres JCPP and fixed a few Objective-C generation bugs).

There are two issues when trying to access C++ from Java with JNA :

  • Each C++ compiler has its own way of creating unique function signatures in its dynamic libraries. This process is called *name mangling*.

    The way JNA operates to bridge the Java and C languages, it needs the exact mangled name of each function that is to be bound to in the dynamic libraries of interest. It then takes some Java definitions and arguments and figures out a way to call the C functions correctly.

  • There are different specific calling conventions to respect (__thiscall, __fastcall), their choice depending on whether a method is static, has varargs…

I chose to start with a small scope and careful limitations :

  • Implemented name manglers for GCC4 & Microsoft Visual C++ 9 (express edition) only, just because they’re simply most likely the most common ones (I’ll try Intel’s compiler as soon as I can).
  • Only handle mangled functions and static methods (hence no issue of calling conventions yet)

After looking at the various parameters that influence name mangling, I came to the conclusion it would much easier to precompute mangled names for all known compilers during the sources generation pass (in JNAerator) rather than at the function binding time (in JNA).

Indeed, while the latter approach seems cleaner and more powerful (updating JNA with a new mangling scheme would enable all JNA libraries for use with a new C++ compiler instantly), it turns out it would require tons of annotations and/or generic types to convey the meta-data necessary to the mangling process. With the upcoming JSR 308, the code could look like :

/// void __cdecl f(const unsigned*** pppi);
@CDecl
void f(Pointer<Pointer<Pointer<@Const @Unsigned Integer>>> pppi);

That’s not too ugly for a simple example, but then you have to create annotations for all of the calling conventions, for storage modifiers (const, volatile, static…), for primitive signs (signed, unsigned, default), you ask people to install the JSR 308 compiler (or find a way not to use annotations, with tagging interfaces akin to ByReference & ByValue, for instance), and things get a bit messier.

Instead, JNAerator takes care of everything during the JNAeration of the Java interfaces and produces a single annotation per-function that contains a list of possible mangled names (one for each known compiler) :

/**
 * Original signature : void f(const char*)
 */
@Mangling({"_Z1fPKc", "?f@@YAXQBD@Z"})
void f(java.lang.String str1);

This is still very experimental and it’s very certainly full of bugs, but pretty simple functions should just work fine (tested quickly on GCC4.0 (Mac OS X 10.5) & Microsoft Visual Studio Express 2009).

Try it for yourself (Web Start link), and please leave comments !