|There's more than one way to do things|
Making Inline::C modules fit for CPANby tsee (Curate)
|on Nov 15, 2006 at 08:53 UTC||Need Help??|
Update: I have since release InlineX::XS to CPAN which is a more robust implementation of the ideas outlined below.
There are a couple of modules on CPAN that use Inline::C. If you don't know what Inline does, you should go read up on it now because for the programmer, it is by far the simplest and most convenient way to write fast C extensions to your Perl code.
In order to hide as much of the compilation process from the user, Inline::C automatically generates XS from the inlined code, compiles it, and links it into the running perl. It will use a dedicated cache area for that and recompile whenever the code was changed. Unfortunately, this means that unless you ship the cache alongside your module or application, every user requires a full C development environment and the perl headers. Of course, for building the application or module in the first place, you need that anyway, but there is a specific, very important example where users don't have that: They install modules using PPM or PAR. PPM and PAR packages are binaries created from CPAN modules. In case of ordinary XS modules, these packages can install all required dll's/so's. This is a hassle with Inline::C-using modules.
Some authors convert their modules from using Inline::C to ordinary XS for this reason. There is even a utility module on CPAN which helps with this: Inline::C2XS can write an XS file from the (plain) C code of an Inline::C-using module. But this conversion is manual and as such, a maintenance nightmare.
I'm now going to propose a possible way out of this dilemma. We want to let the module author have the comfort of using Inline::C for his module and the user should be able to install the module as an XS extension. Additionally, the author should not have to manually extract the C code from his module in order to make a release.
Here's the concept: Say, we're dealing with a module Foo::Bar which contains inlined C code. The trick is to auto-generate an XS file from this C code during the make dist phase and subsequently ship that XS file with the module. During the make phase on the user's machine, the XS file is compiled to an ordinary XS extension. If the associated DLL/so is present, Foo::Bar will not use Inline to compile the inlined C code, but it will use XSLoader to load the existing DLL. This way, the author can use Inline::C for development and when ready, ship the module as an ordinary XS module. Enter the hypothetical Module::Inline::C.
Now, this whole scheme should sound reasonably scary to you or else you're just plain sick. That's why I wrote some proof of concept code to show how this might work:
There are various issues with the code as it stands, but the general idea seems reasonably sound: Let the author write maintainable inlined code and let the user have ordinary XS extensions. I'm just going to point out one prominent omission: Module::Inline::C (bad name, I know) doesn't keep track of multiple packages using it at the same time. But that's just a bit of house keeping!
What do you think? If I hacked this up to a reasonably stable state and put it on CPAN, would you consider using it for your C extensions?
PS: Yes, I actually ran this. It works for me.