The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

InlineX::XS - Auto-convert Inline::C based modules to XS

SYNOPSIS

  package Your::Module;

  # Make sure your $VERSION is accessible at compile time for XSLoader:
  # (yes, this is strict-safe)
  our $VERSION = '0.01';
  BEGIN {$VERSION = '0.01'}

  # Replace the use of Inline::C:
  # use Inline C => <<'CODE';
  # becomes:

  use InlineX::XS <<'CODE';
     ... C code ...
  CODE

  # Perl code, more C, more Perl...
  
  # Replace the final '1;' of your module with:
  use InlineX::XS 'END';

DESCRIPTION

Make sure to read the CAVEATS section below before using this. This is experimental software.

Introduction

Extending Perl with C was made much easier by the introduction of Ingy's Inline or rather Inline::C module. It is possible to create CPAN distributions which use Inline::C, but traditionally, writing XS, the C-to-Perl glue language, by hand has been considered superior in that regard because Inline::C writes its compiled shared libraries to cache areas whereas the libraries compiled from XS are properly installed. (I know, technically, Inline::C generates XS on the fly.)

This module is intended to enable developers to use Inline::C and have the C code converted to (static) XS code before they make a release.

How it works

Mostly, you replace any invocation of Inline::C with InlineX::XS as follows:

  use Inline C => <<'CODE';
     ... C code ...
  CODE

becomes

  use InlineX::XS <<'CODE';
     ... C code ...
  CODE

Note that most advanced usage of Inline::C is currently ignored by InlineX::XS during packaging. Also, InlineX::XS cannot read from the __DATA__ section of your module.

There are some other changes you need to make to your code, but the above is the main difference. The other changes are shown in the SYNOPSIS above.

InlineX::XS will take the plain C code and first look for a loadable shared object file which was compiled from XS and if that wasn't found, fall back to passing the code to Inline::C.

Packaging

By forcing InlineX::XS into the packaging mode and compiling your .pm file with perl -c, you can make it extract the C code from your .pm file into the src/ subdirectory. From there, InlineX::C2XS will be used to generate a .xs file in the current directory.

You may do so explicitly from the main distribution directory with the following command:

  perl -c -MInlineX::XS=PACKAGE lib/Your/Module.pm

You should now have a shiny new XS file Module.XS. Add it to the distributions MANIFEST file and you are good to go. But read on:

Easier packaging

More conveniently, you can just slightly modify your Makefile.PL if you are using ExtUtils::MakeMaker and not the newer Module::Build or Module::Install. It should be straightforward to do with those as well, but I haven't explored that. Please contact me if you would like to give a hand concerning support for other build systems.

In the Makefile.PL, there is a call to WriteMakefile. Add a key/value pair to the argument list of this call:

  dist => {
    PREOP => 'perl -MInlineX::XS::MM=$(DISTNAME)-$(VERSION) -c lib/Your/Module.pm'
  }

Of course, you need to add a dependency on InlineX::XS. You do not need a dependency on Inline::C. On the user's machine, the generated XS code will be compiled and installed. Inline::C will not be used unless the user removes the XS code before compilation.

Given this modified Makefile.PL, you can issue the following usual commands to create a release-ready package of your module:

  perl Makefile.PL
  make dist

InlineX::XS::MM will take care of generating the XS and modifying your MANIFEST. Expect similar utility modules for Module::Build and Module::Install in the future. (Help welcome, though.)

An example distribution Foo::Bar can be found in the examples/ subdirectory.

CAVEATS

InlineX::XS isn't a drop-in replacement for Inline::C in some cases. For example, it doesn't support reading from arbitrary files or getting the code from code references.

When passing the arguments through to Inline::C because no loadable object was found, some of the various advanced Inline::C features work alright. Once extracted as XS and compiled, those won't be available any more.

The configuration options are only partially supported. Additionally, there is one major discrepancy in behaviour: Any configuration settings (i.e. use Inline C = 'Config'...> or use Inline C = '...code...', cfg1=>'value1'...>) are applied to all Inlined code in the package! In ordinary Inline::C code, these are built up as the various inlined code sections are parsed and compiled.

Multiple modules which use InlineX::XS in the same distribution are problematic. This isn't really an InlineX::XS problem but rather a general issue with distributions that contain XS. It's possible, but I haven't explored it fully.

Naturally, if you use the bind function from Inline to load C routines at run-time, InlineX::XS can't interfere.

Do not think you can use InlineX::XS like a random Inline language module because it isn't one of those.

  # Cannot work and should not work:
  use Inline XS => 'code';

We can't declare our prerequisites in the Makefile.PL because they're not needed by users who use modules which have been compiled to XS.

PREREQUISITES

Depending on the mode of operation, this module may required various other modules. For end-users who use modules which make use of InlineX::XS, there are currently no prerequisites at all.

Developers who use InlineX::XS in conjunction with Inline::C need to install Inline::C.

Those who generate distributions with XS code from the Inline::C (or rather InlineX::XS) code need an installed InlineX::C2XS and thus an installed Inline::C. In particular, version 0.08 or higher of InlineX::C2XS is required for packaging (only).

CLASS METHODS

debug

Get or set the debugging flag. Defaults to false.

import

Automatically called via use InlineX::XS.

SEE ALSO

The obvious place to learn how to use Inline::C (and thus InlineX::XS) is Inline::C.

This class implements the ExtUtils::MakeMaker packager: InlineX::XS::MM, see also: ExtUtils::MakeMaker,

The XS is generated from the C code using InlineX::C2XS.

The shared objects that are compiled from the generated XS code are loaded using XSLoader.

The concept was originally proposed here: http://perlmonks.org/index.pl?node_id=584125

AUTHOR

Steffen Mueller, <smueller@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2006 by Steffen Mueller

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.6 or, at your option, any later version of Perl 5 you may have available.