Hack 96. Use Shared Libraries Without XS


Call C code from Perl without needing a compiler.

One of the few ways in which installing Perl modules is painful is when they link to shared libraries written in other languages. The first pain is that someone has to write XS or Inline::C or Swig bindings for the shared library. The second is that installing such modules usually requires a working C development environmentand not every machine nor user has such a luxury.

For simple tasks that merely wrap a shared library, there's no reason you need that much; with a little clever coding you can use just about any shared library written in C with an idea backported from Perl 6 to Perl 5.

The Hack

Consider how Perl passes arguments to functions: in @_, on a stack. As far as the calling conventions work, any function that takes a string, an array reference, and a hash reference looks the same for the purposes of calling the function.

Consider how C passes arguments to functions: much the same way. Any function that takes two integers and returns a double looks the same, again as far as the calling conventions go.

Similarly, any XS code that converts between a Perl function that passes two integers (well, scalars containing integers) to a C function and expects a double (well, a scalar containing a numeric value) is the same. The only difference is the name of the function as Perl sees it and the actual C function it calls. Those are actually very easy to vary.

The P5NCI module builds up its own library of thunk functions (the glue between Perl and C) and allows you to bind thunks to functions in shared libraries.

Running the Hack

Suppose you want to use a good, fast library for determining the cube root of any given number. The libm shared library in the C standard library provides a nice function cbrt that takes a double and returns a double and does it fairly quicklyat least more quickly than you could do it in Perl (and certainly more easily than you could write XS code to do it).

Loading the library and creating the wrapper around cbrt is easy, once you know the name of the shared library and the function signature:

use P5NCI::Library; my $lib = P5NCI::Library->new( library => 'm' ); $lib->install_function( 'cbrt', 'dd' ); print cbrt( 27 ), "\\n"; print cbrt( 31 ), "\\n";

Note that, if you have P5NCI installed, you don't need a compiler to do this, nor do you even need math.h installed for this to work! Just create a new P5NCI::Library object, passing the name of the library without any platform-specific prefix or suffix.[7] Then, call install_function( ) on that object, passing the name of the function within the shared library to wrap as well as the signature, where the first letter is the type of the returned variable and the remaining letters are the types of the arguments to the function. You probably need to read the header or at least the documentation for the shared library to find out the signature, but you don't have to have the development package or tools installed when you deploy your code.

[7] On a Unix system, the file is actually libm.so. On a Windows system, it's probably math.dll. Mac OS X likely refers to it as libm.dylib.

Then call the function as if it were a normal Perl functionas far as the code cares, it is.

See the module's documentation for other call signatures.

Hacking the Hack

One drawback of the NCI approach as described here is that it requires a shared library containing the thunking layer between Perl's and C's calling conventions. Even with a few possible data types and signatures no longer than four characters, there are still many, many possible necessary thunking functions. If your project only needs a few types of signatures, building your own thunking library can be useful. If you want to distribute this thunking layer, you must compile it for the destination machines. Fortunately, you only have to compile it once.

For general use, wrapping a library such as libffi may be a better approachit can generate the thunks on its own as needed, requiring only that you have the FFI library installed. Look for updates to P5NCI on the CPAN that do this.

It's possible to handle pointers to structures passed to and from the shared library as well. Marcus Holland-Moritz's Convert::Binary::C is a likely candidate for giving access to struct members.



Perl Hacks
Perl Hacks: Tips & Tools for Programming, Debugging, and Surviving
ISBN: 0596526741
EAN: 2147483647
Year: 2004
Pages: 141

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net