Tuesday, March 13, 2007

Building w32 JNI DLLs with gcc

After a bit of trial and error, I got JNA's native shared library to build (and run, and run tests) using gcc. Unfortunately the available documentation didn't quite work for me (might be a problem with my cygwin installation, but I wasn't the only one with an issue).

gcc-mingw is a version of cygwin gcc that can compile directly to the w32 api, without any of the cygwin emulation layer.

% gcc -dumpspecs | sed s%dllcrt2%/lib/mingw/dllcrt2%g > specs.new
% gcc -mno-cygwin -D_REENTRANT -D_GNU_SOURCE \
-D__int64="long long" -D_JNI_IMPLEMENTATION \
-shared -Wl,--kill-at -specs specs.new -L /lib/mingw

The -mno-cygwin flag tells the compiler to run in mingw mode, i.e. omit all the cygwin unix compatibility layer and compile directly against the w32 api.

GCC's built-in 64-bit type is long long, so we map the type used in the JNI headers, __int64, to that type. Defining _JNI_IMPLEMENTATION ensures the JNI implementation exports its native method declarations.

Defining _REENTRANT and _GNU_SOURCE cause certain additional declarations of C library functions to be included. If you've never heard of them, most likely you don't need them.

The --kill-at flag to the linker ensures all symbols are exported undecorated, i.e. _my_func instead of _my_func@NN, which is the default when a function is declared as __stdcall. You could also use --add-stdcall-alias, which includes both versions of the symbol.

The GCC specs need tweaking or gcc-mingw doesn't find its initialization code for dlls, dllcrt2.o. We also have to nudge gcc-mingw to find the mingw libraries. Normally this is taken care of automatically by gcc, but for some reason my installation of cygwin gcc wouldn't find them, and no amount of -L or explicit object linkage would fix it.

Anyhow, with that out of the way, you don't have to have Microsoft's tools to build JNA or any other JNI library on w32.

I have noted that GCC apparently handles floating point a little differently, since the JNA tests that use FP return values/arguments are failing with the GCC-build dll.


F. Wang said...

thank you for your blog. I successfully built C dll
and used it with JNA. But I prefer using C++ so I changed from gcc to g++. dll is still generated but
JNA cannot find the procedure defined in dll.

technomage said...

C++ by default mangles the exported function names. You need to place 'extern "C"' before any function you which to export without name mangling.

Anonymous said...

excellent information. The linker option "-Wl,--kill-at" is essential to avoid the UnsatisfiedLinkError Java exception because the built dll does not have the undecorated name of your C routine. That's a week of development time wasted finding THAT one. gl

Anonymous said...

Thank you. This was a very helpful article that saved me a lot of time!