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

InlineX Cookbook

=head1 BASIC EXAMPLE

As of version 0.13 of this module, it's possible to provide the C/CPP
code to InlineX::C2XS/InlineX::CPP2XS by supplying either the CODE or
SRC_LOCATION arguments as key/value pairs in the hashref that forms the
the final argument given to c2xs()/cpp2xs(). This documentation was
first written prior to version 0.13 - I'll leave the first parts of it
as is, but bear in mind that the CPP source can now be stored anywhere
in any file and you just provide the name and location (either fully
qualified or relative) of that file using the
SRC_LOCATION=>'./location/file.ext' key/value pair ... or you can just
store the code as one big string in a variable (say, $code) in which
case you supply the code using the CODE=>$code key/value pair. For a
demo of these capabilities that became available in 0.13, see the
section "UPDATE for 0.13 and later" at the end of this document.

For even more recent additions, see the section "UPDATE for 0.20 and
later".

Create a separate directory to work through this demo (let's call it
'test' - though you can call it whatever you like), then 'cd' to the
newly created 'test' directory, and create 2 folders in it - 'src' and
'My-Mod-0.01'. The 'src' folder is where the CPP code gets placed (and
the folder must be named 'src'). The 'My-Mod-0.01' folder is where the
various files that InlineX can create will be written. (That folder does
not have to be named 'My-Mod-0.01' - call it whatever you want. For the
purpose of this exercise, I'm assuming you *have* named it'My-Mod-0.01').

In the 'src' folder place a CPP file named Mod.cpp that contains:


    int plus (int x, int y) {
        return x + y;
    }
    int minus (int x, int y) {
        return x - y;
    }


Since the module we are building in this particular exercise is named
My::Mod, the CPP file must be named 'Mod.cpp'. That is, the .cpp file must
have a '.cpp' extension, and it must have the same name as the .pm file.

To create Mod.xs, place the following file (which I've named 'create.pl')
in the 'test' directory:


    use warnings;
    use strict;
    use InlineX::CPP2XS qw(cpp2xs);
    my $mod = 'My::Mod';
    my $pkg = $mod;
    my $build_dir = './My-Mod-0.01';
    cpp2xs($mod, $pkg, $build_dir);


Then run create.pl.

You should now find Mod.xs in test/My-Mod-0.01. We've taken care of
one of the files that we'll need to build My::Mod. Note that INLINE.h
was not created. That's because the CPP code in Mod.cpp does not need
INLINE.h. Let's change that by adding the following to the bottom of
Mod.cpp:


    void plus_minus(int x, int y) {
         Inline_Stack_Vars;
         Inline_Stack_Reset;
         Inline_Stack_Push(sv_2mortal(newSViv(x + y)));
         Inline_Stack_Push(sv_2mortal(newSViv(x - y)));
         Inline_Stack_Done;
         Inline_Stack_Return(2);
    }


Again run create.pl

This time INLINE.h is needed and you should find it, along with Mod.xs,
in test/My-Mod-0.01.

But, of course, to build the My::Mod module, you'll also need a 
Makefile.PL and a Mod.pm. So let's autogenerate them, too. It's just
a matter of providing an extra argument to cpp2xs(). Amend create.pl to:


    use warnings;
    use strict;
    use InlineX::CPP2XS qw(cpp2xs);
    my $mod = 'My::Mod';
    my $pkg = $mod;
    my $build_dir = './My-Mod-0.01';
    my $hashref = {VERSION =>0.01,
                   WRITE_MAKEFILE_PL => 1,
                   WRITE_PM => 1};
    cpp2xs($mod, $pkg, $build_dir, $hashref);


Now when you run create.pl you'll find that Makefile.PL and Mod.pm
are also created in test/My-Mod-0.01.(Mod.pm doesn't contain any pod
documentation - and the Makefile.PL might contain some
machine-specific specifications that should be cleaned up before
sending the files off to CPAN. But that's all fairly basic and
straightforward stuff.)
If you want all of the XSubs except those starting with a single
underscore (but not multiple underscores) to be placed into Mod.pm's
@EXPORT then set EXPORT_ALL=>1 in $hashref. Otherwise
@My::Mod::EXPORT will be empty.
If you want all of the XSubs except those starting with a single
underscore (but not multiple underscores) to be placed into Mod.pm's
@EXPORT_OK then set EXPORT_OK_ALL=>1 in $hashref. Otherwise
@My::Mod::EXPORT_OK will be empty.
And if you want to create an export tag (named, eg 'all') that includes
all of the XSubs except those starting with a single underscore (but
not multiple underscores) then set EXPORT_TAGS_ALL=>'all' in 
$hashref.

You may also want to provide a test script, a README, a MANIFEST and
whatever other files you like. These additional files cannot be
autogenerated by InlineX. For a test script that works with the
autogenerated Mod.pm, just create a file named 'test.t' in 
test/My-Mod-0.01/t (you'll need to manually create that 't'
directory). Assuming that we haven't set either EXPORT_OK_ALL or
EXPORT_ALL (see above), 'test.t' could look like this:

    use warnings;
    use strict;
    use My::Mod;
    print "1..1\n";
    my $x = 16;
    my $y = 12;
    my @z = My::Mod::plus_minus($x, $y);
    my $ok = '';
    if(My::Mod::plus($x, $y) == 28) {$ok .= 'a'}
    if(My::Mod::minus($x, $y) == 4) {$ok .= 'b'}
    if($z[0] == 28 && $z[1] == 4)   {$ok .= 'c'}
    if($ok eq 'abc') {print "ok 1\n"}
    else {print "not ok 1 $ok\n"}

If we have set EXPORT_OK_ALL, then 'test.t' could look like this:

    use warnings;
    use strict;
    use My::Mod qw(plus minus plus_minus);
    print "1..1\n";
    my $x = 16;
    my $y = 12;
    my @z = plus_minus($x, $y);
    my $ok = '';
    if(plus($x, $y) == 28) {$ok .= 'a'}
    if(minus($x, $y) == 4) {$ok .= 'b'}
    if($z[0] == 28 && $z[1] == 4)   {$ok .= 'c'}
    if($ok eq 'abc') {print "ok 1\n"}
    else {print "not ok 1 $ok\n"}

And if we have instead set EXPORT_ALL, then in 'test.t' we
could replace "use My::Mod qw(plus minus plus_minus);" with
simply "use My::Mod;"

Now you can build My::Mod in the usual way (in the
test/My-Mod-0.01 folder) by running:

    perl Makefile.PL
    make test

You could even install it by running 'make install' if you want.

There are other examples to be found in the demos folder of the
InlineX-C2XS and InlineX-CPP2XS source distributions from CPAN.

Some other build options are given below. (For a complete list, see
the InlineX-C2XS/InlineX-CPP2xs documentation.) In each case it's just
a matter of adding a key/value pair to $hashref in create.pl. No other
changes to create.pl are necessary.

**********************************************************************

=head1 AUTO_INCLUDE

You may need to include additional headers into the XS file. Do so by
inserting the following key/value assignment into create.pl's $hashref:

    AUTO_INCLUDE => "#include <x.h>\n#include \"y.h\"",

Also, if the AUTOWRAP feature needs to parse and use these headers, 
then AUTO_INCLUDE is the way to satisfy that requirement. 

**********************************************************************

=head1 BUILD_NOISY

You'll note that during the running of create.pl there's some progress
reports being generated by Inline::CPP. If you don't want to see those
reports, insert the following key/value assignment into create.pl's
$hashfef:

    BUILD_NOISY => 0,

**********************************************************************

=head1 USING 

Specify an alternative parser to parse the CPP code. There are
currently no alternative parsers available to Inline::CPP.

   USING => ['ParseRegExp'], # fails on Inline::CPP & InlineX::CPP2XS

**********************************************************************

=head1 TYPEMAPS

Let's do another demo here, based upon the "Object Oriented Inline"
example in the (excellent) Inline::C-Cookbook - to demonstrate the
use of typemaps as much as anything else. Back in the 'test' folder,
create another folder named '/My-Soldier-1.02' ... so we've now got
folders named test/src, test/My-Mod-0.01 and test/My-Soldier-1.02.

Create a file named 'Soldier.cpp' as follows (and place it in test/src):

  typedef struct {
    char* name;
    char* rank;
    long  serial;
  } Soldier;
  
  Soldier * new(char* class, char* name, char* rank, long serial) {
      Soldier* soldier;
      New(42, soldier, 1, Soldier);

      soldier->name = savepv(name);
      soldier->rank = savepv(rank);
      soldier->serial = serial;

      return soldier;
  }
   
  char* get_name(Soldier * obj) {
        return obj->name;
  }
    
  char* get_rank(Soldier * obj) {
        return obj->rank;
  }
    
  long get_serial(Soldier * obj) {
       return obj->serial;
  }

  void DESTROY(Soldier* obj) {
       Safefree(obj->name);
       Safefree(obj->rank);
       Safefree(obj);
  }


Note that new() returns a Soldier*. Perl doesn't know anything about
the Soldier* type ... so we need to provide a typemap with an 'OUTPUT'
section that tells perl how to deal with this type.
Note also that the other functions take (as their argument) a Soldier*.
Again, since perl doesn't know anything about the Soldier* type, we 
need to provide a typemap with an 'INPUT' section that tells perl 
what to do. Here's one such typemap that satisfies both requirements:


 Soldier *    SOLDIER

 INPUT
 SOLDIER
 	$var = INT2PTR($type, SvIV(SvRV($arg)))

 OUTPUT
 SOLDIER
 	$arg     = newSViv(0);
 	$arg     = newSViv(0);
	sv_setiv(newSVrv($arg, \"Soldier\"), (IV)$var);
	SvREADONLY_on(SvRV($arg));
	$arg;


Save that file as test/My-Soldier-1.02/typemap and place a copy of it
in 'test'. Note that, in addition to our typemap being needed when we
compile the My::Soldier module, the cpp2xs function also needs it in
order to write a correct XS file. That's why we've placed a copy of
the typemap in both 'test' and 'test/My-Soldier-1.02' - so that both
processes will be able to find it. A better solution is to have the
TYPEMAPS entry in $hashref provide a fully qualified (absolute) path
to the file, rather than a relative path. (Unfortunately, I don't
know what that absolute path will be on your machine.)

I guess we'll also need a test file to test our new Soldier module.
So save the following as test/My-Soldier-1.02/t/test.t:

    use warnings;
    use strict;
    use My::Soldier;
    print "1..1'\n";
    my $obj1 = My::Soldier->new('Benjamin', 'Private', 11111);
    my $obj2 = My::Soldier->new('Sanders', 'Colonel', 22222);
    my $obj3 = My::Soldier->new('Matt', 'Sergeant', 33333);
    my $ok = '';
    if($obj1->My::Soldier::get_name() eq 'Benjamin') {$ok .= 'a'}
    if($obj2->My::Soldier::get_name() eq 'Sanders') {$ok .= 'b'}
    if($obj3->My::Soldier::get_name() eq 'Matt') {$ok .= 'c'}
    if($obj1->My::Soldier::get_rank() eq 'Private') {$ok .= 'd'}
    if($obj2->My::Soldier::get_rank() eq 'Colonel') {$ok .= 'e'}
    if($obj3->My::Soldier::get_rank() eq 'Sergeant') {$ok .= 'f'}
    if($obj1->My::Soldier::get_serial() == 11111) {$ok .= 'g'}
    if($obj2->My::Soldier::get_serial() == 22222) {$ok .= 'h'}
    if($obj3->My::Soldier::get_serial() == 33333) {$ok .= 'i'}
    if($ok eq 'abcdefghi') {print "ok 1\n"}
    else {print "not ok 1 $ok\n"}

Now we just need to rewrite test/create.pl appropriately:

    use warnings;
    use strict;
    use InlineX::CPP2XS qw(cpp2xs);
    my $mod = 'My::Soldier';
    my $pkg = $mod;
    my $build_dir = './My-Soldier-1.02';
    my $hashref = {VERSION =>1.02,
                   WRITE_MAKEFILE_PL => 1,
                   TYPEMAPS => ['./typemap'],
                   WRITE_PM => 1};
    cpp2xs($mod, $pkg, $build_dir, $hashref);

So now ... it's just a matter of running create.pl - then 'cd' to
test/My-Soldier-1.02 and run:

  perl Makefile.PL
  make test

(and 'make install' if you actually want to install this module.)

**********************************************************************

=head1 UPDATE for 0.13 and later

Returning to the first example code we used at the beginning of this
cookbook, with version 0.13 or later, we don't need to have the source
in ./src/Mod.cpp. (We can still do it that way, but we don't *have*
to.)

We could, for example, put the code that was written into './src/Mod.cpp'
into '/home/me/file.ext' instead. Then, in order to create Mod.xs,
Mod.pm, and Makefile.PL in './My-Mod-0.01', we need 'create.pl' to 
look like this:


    use warnings;
    use strict;
    use InlineX::CPP2XS qw(cpp2xs);
    my $mod = 'My::Mod';
    my $pkg = $mod;
    my $build_dir = './My-Mod-0.01';
    my $hashref = {VERSION =>0.01,
                   WRITE_MAKEFILE_PL => 1,
                   WRITE_PM => 1,
                   SRC_LOCATION => '/home/me/file.ext'};
    cpp2xs($mod, $pkg, $build_dir, $hashref);


Another alternative is to put the code in a variable - in which
case 'create.pl' is as follows:


    use warnings;
    use strict;
    use InlineX::CPP2XS qw(cpp2xs);
    my $mod = 'My::Mod';
    my $pkg = $mod;
    my $build_dir = './My-Mod-0.01';
    my $code = "
    int plus (int x, int y) {
        return x + y;
    }
    int minus (int x, int y) {
        return x - y;
    }

    void plus_minus(int x, int y) {
         Inline_Stack_Vars;
         Inline_Stack_Reset;
         Inline_Stack_Push(sv_2mortal(newSViv(x + y)));
         Inline_Stack_Push(sv_2mortal(newSViv(x - y)));
         Inline_Stack_Done;
         Inline_Stack_Return(2);
    }
    ";
    my $hashref = {VERSION =>0.01,
                   WRITE_MAKEFILE_PL => 1,
                   WRITE_PM => 1,
                   CODE => $code};
    cpp2xs($mod, $pkg, $build_dir, $hashref);


**********************************************************************

=head1 "UPDATE for 0.20 and later"

With version 0.20, a 'cpp2xs' utility was provided - it provides a less
cumbersome method of accessing the cpp2xs functionality. 
(See 'cpp2xs --help')

Version 0.21 adds the capability of writing a portable Makefile.PL (and
xs file) via the config option WRITE_MAKEFILE_PL=>'p'.

And, in the source distro, there's now a nice demo featuring proper C++
code from David Oswald's Math::Prime::FastSieve module(as opposed to the
C code that populates this cookbook). See demos/cpp2xs_utility/README in
the 0.21 (and later) source distro. 


**********************************************************************

=cut