C interop lib (JNA wrapper)

1,145 views
Skip to first unread message

mac

unread,
Jan 8, 2010, 11:08:13 AM1/8/10
to Clojure
Hello all.
I've started work on a clojure library for interoperating with C. It's
always been a pain to do in Java but recently JNA (java native access)
has taken away most of that pain.
When using clojure however, it's nice to be able to stay in clojure
and not drop to java (or C *shudder*).
It's possible to use JNA from dynamic jvm languages already but those
interfaces are slower and less type safe than the "direct mapping" way
of doing things.
Since I wanted this to be as fast and safe as possible but still
clojure code only I have resorted to all kinds of voodoo, including
bytecode generation and eval usage (oh the horror) so be warned :)
Currently it is very rough but it can already handle all primitive
types and also typed pointer arguments as nio buffers. I have included
jna type support for structs, unions and callbacks (c function
pointers) but that's completely untested yet.

Here it is:
http://github.com/bagucode/clj-native

Rob Wolfe

unread,
Jan 8, 2010, 2:53:34 PM1/8/10
to clo...@googlegroups.com
mac <markus.g...@gmail.com> writes:

Yes, there is a lot of voodoo. ;)
Have you seen this library: http://github.com/Chouser/clojure-jna ?
I'm using this one right now (it is really simple) and I'm wondering
what will be the advantage of using your implementation?

Br,
Rob

mac

unread,
Jan 8, 2010, 3:38:58 PM1/8/10
to Clojure

On Jan 8, 8:53 pm, Rob Wolfe <r...@smsnet.pl> wrote:

Yes I have seen that library and I've used it as well.
The benefits of using my version are speed and safety.
I'm using the direct mapping technique described on the JNA front page
which is supposedly almost as fast as making custom JNI bindings. An
additional (and perhaps more important) benefit of my approach is that
it gives some measure of type and arity safety since the arguments
must be of the correct type and the correct number of arguments on the
java side for a call to succeed. It's very easy to crash the jvm if
you mess up the arguments to a C function.
This library is something I started because I had a need to wrap a
rather large C library with many small functions so I wanted the call
overhead to be small (hence the direct mapping) and errors to be
comprehensible when I made a mistake instead of just getting a
segfault.
But interface-wise on the clojure side I guess my lib and clojure-jna
are kind of similar so if clojure-jna good enough there is no reason
to switch to my lib. I was certainly inspired by clojure-jna since I
had used it before :)

Chouser

unread,
Jan 8, 2010, 4:01:11 PM1/8/10
to clo...@googlegroups.com
On Fri, Jan 8, 2010 at 3:38 PM, mac <markus.g...@gmail.com> wrote:
>
> But interface-wise on the clojure side I guess my lib and clojure-jna
> are kind of similar so if clojure-jna good enough there is no reason
> to switch to my lib. I was certainly inspired by clojure-jna since I
> had used it before :)

If clojure-jna serves as nothing but a gateway drug to
clj-native, I'll be entirely content. :-)

I look forward to trying out http://github.com/bagucode/clj-native

--Chouser
--
-- I funded Clojure 2010, did you?

mac

unread,
Jan 9, 2010, 7:39:55 AM1/9/10
to Clojure
I've gotten rid of the automatic loading of the library and
replacement of stub functions upon their first call.
While this seemed convenient I didn't like that the stub versions of
the functions could be passed around as objects without the user
knowing that it was not the "real" version being used. And while it
would have no functional impact, those versions would keep replacing
their var root every time they were called which felt very icky.
Instead there is now an additional function generated besides the
mapped C functions which is called loadlib-libname (libname is the
name of the C lib) which must be called (at runtime) before any of the
library functions. The library functions still have stubs so that it's
possible to link other clojure functions against them at compile time
but the stubs now throw an exception telling the user to run the
loadlib function first.

xster

unread,
Jan 10, 2010, 2:43:45 AM1/10/10
to Clojure

On Jan 8, 8:08 am, mac <markus.gustavs...@gmail.com> wrote:
> Hello all.
> I've started work on a clojure library for interoperating with C. It's

> always been a pain to do in Java but recentlyJNA(java native access)


> has taken away most of that pain.


This is great. I think it'll be very valuable to call out to a bunch
of useful C library functions. Can this approach also provide a bridge
to Objective-C?

I'm very interested in using Cocoa to design GUIs for the Mac. I'd
really like to be able to have all the business logic encapsulated in
clojure though. Would this approach be able to glue together Cocoa NIB
files and Objective-C code to clojure?

mac

unread,
Jan 10, 2010, 4:47:56 PM1/10/10
to Clojure
> This is great. I think it'll be very valuable to call out to a bunch
> of useful C library functions.

Thank you

> Can this approach also provide a bridge
> to Objective-C?
>
> I'm very interested in using Cocoa to design GUIs for the Mac.  I'd
> really like to be able to have all the business logic encapsulated in
> clojure though. Would this approach be able to glue together Cocoa NIB
> files and Objective-C code to clojure?

I'm not very familiar with what compiled Objective-C code looks like.
But I do know of this project:
https://rococoa.dev.java.net/
And it seems to be using JNA as it's backend so I guess it's possible.
It's probably a matter of decoding Obj-C's name mangling scheme.
It would probably be easier to just wrap rococoa though.
I haven't planned on supporting more languages than C but maybe if I
manage to make my code generic enough (it's currently very messy)
parts of it could be used for other language wrappers via JNA.
But I want to finish at least version 1.0 of clj-native before I even
think of something like that ;)

By the way, clj-native now has support for callbacks so that C code
can call into clojure!
I made a little example here:
http://github.com/bagucode/clj-native/tree/master/src/examples/

I didn't upload the binary for the C lib since that's very platform
specific.
If you are on a mac just do something like
gcc -c c_lib.c
ld -dylib -o libc_lib.dylib c_lib.o
and don't forget to System/setProperty java.library.path or
jna.library.path to include the dir where libc_lib.dylib is.
(for some reason the system properties must be set before the very
first attempt to load a native lib, they will not be re-read if you
change them and try again)

mac

unread,
Jan 12, 2010, 10:49:57 AM1/12/10
to Clojure
I had apparently forgotten to commit and push the last changes.
Sorry for any trouble if anyone is trying to use the library.
The callbacks should work now.

Mark Allerton

unread,
Jan 18, 2010, 2:40:47 AM1/18/10
to clo...@googlegroups.com
Hi all, first time caller here.

Came back to check in on this thread due to some interest in the library that Mac has been working on - and the discussion about Objective-C/Cocoa interfacing has prompted me to break cover with something I've been hacking around on for the past few weeks. 

Basically I've been working on a bridge between Clojure and Objective-C/Cocoa. While my bridge does at its heart use JNA, I've taken a somewhat different approach from the one Mac is recommending. I'd describe the current state of it as "demo" quality - it works for the demo code, but try anything else and you're on your own.

More details can be found at http://github.com/allertonm/Couverjure

Cheers

..Mark..

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

mac

unread,
Jan 24, 2010, 11:54:47 AM1/24/10
to Clojure
A little progress update.

I havent had much time to work on this since my initial effort. But
this weekend I have gotten structures to work.
The reason that special support for structures is needed is to support
C api's that pass them by value.
Most of the effort to make this work went into how I handle types. I
want the type definitions in the clojure DSL to look sort of like C so
that it's easy to copy a C header file and get it right.
Since I had to support user specified types to support structures, as
an added safety bonus the callbacks are now typed as well.
Usage examples are here:
http://github.com/bagucode/clj-native/tree/master/src/examples/

enjoy!
/Markus

Mark Allerton

unread,
Jan 25, 2010, 5:10:07 PM1/25/10
to clo...@googlegroups.com
Hi Markus,

This looks pretty nice - one question though: is there an API provided
that would let me build callbacks and structs programmatically - as
opposed to the declarative style of defclib?

Being able to create callbacks programmatically would be one way of
working around the problem I describe here:
https://jna.dev.java.net/servlets/ReadMsg?list=dev&msgNo=808

(I realize that this would basically be the "generate callback classes
OTF solution" that I said I'd rather not do, but if the code for this
already exists I could be persuaded otherwise.)

Cheers

..Mark..

mac

unread,
Jan 26, 2010, 1:50:19 AM1/26/10
to Clojure
> This looks pretty nice - one question though: is there an API provided
> that would let me build callbacks and structs programmatically - as
> opposed to the declarative style of defclib?

Not currently but it's definetly doable. I already use clojure.asm to
generate classes on the fly.

I have thought about this a bit actually and I will try to make my
code more modular for my own sake as well (it's very messy and
monolithic at the moment) so I could probably expose some of the class
generation functions once that is done.

Some random info about my implementation:
All my interface code is generated at runtime because I wanted to use
the direct mapping feature of jna which requires exotic things like
static initializers and inner classes.
So defclib just parses it's body and creates a "library specification"
which can be used at runtime (by calling loadlib) to generate and load
proper jna classes.
The reason it's done at runtime are
1. Native longs are different sizes on different platforms and this
way they user doesn't have to care about it because the size will be
known at runtime so only one type of long is required.
2. Since I needed to generate classes I would have to build in support
for AOT compilation if class generation would be done before runtime
and I didn't feel like spending energy on that ;)

/Markus

Mark Allerton

unread,
Jan 26, 2010, 1:21:53 PM1/26/10
to clo...@googlegroups.com
Well, just to encourage you a bit more...

While programmatic generation of JNA callbacks might not be the best
answer to my current problems, one area where I see programmatic
generation of native interfaces and structures to be really, really
useful would be dynamic loading of OSX "BridgeSupport" files.

These are XML files that describe (non-Objective-C) native interfaces
in a way that can be easily read by language bridges like those for
Python and Ruby. So essentially these describe calls in a way that
code can build libffi invocations on the fly (since these languages
bridges are all built with libffi, and in fact Apple ships libffi with
the OS.)

So it should be possible to read these files and generate classes that
can be used by JNA to build libffi calls. The most obvious way to do
this would be to generate java classes "ahead of time" but I'd like to
get to something that works without forcing AOT steps.

The "right" solution would probably be to remove the middleman (i.e
JNA) and implement a lower level mechanism for building libffi calls -
but this will not be trivial work, and it seems like the code you're
building would provide a means of achieving the dynamic loading parts
while still taking advantage of all of JNA's plumbing.

Cheers

..Mark..

Reply all
Reply to author
Forward
0 new messages