NAME

   FFI::Platypus::Lang::CPP - Documentation and tools for using Platypus
   with the C++ programming language

SYNOPSIS

   NOTE: The original author of this module considered the techniques used
   by and documented by this module to be somewhate experimental even back
   in 2015 when he wrote it. The original author now thinks that it is
   probably safer to write a C API layer between your C++ library and Perl
   rather than try to call C++ directly as advocated by this module. While
   the original author has not yet deprecated this module, users of this
   module should consider its limitations before using it.

   C++:

    // on Linux compile with: g++ --shared -o basic.so basic.cpp
    // elsewhere, consult your C++ compiler documentation

    class Foo {

    public:

      // note you should avoid inlining functions
      // for classes you intend to use with FFI
      // as the compiler may not emit code/symbols
      // for those functions.
      Foo();
      ~Foo();

      int get_bar();
      void set_bar(int);

      int _size();

    private:

      int bar;

    };

    Foo::Foo()
    {
      bar = 0;
    }

    Foo::~Foo()
    {
    }

    int
    Foo::get_bar()
    {
      return bar;
    }

    void
    Foo::set_bar(int value)
    {
      bar = value;
    }

    int
    Foo::_size()
    {
      return sizeof(Foo);
    }

   Perl:

    package Foo;

    use FFI::Platypus 1.00;
    use FFI::Platypus::Memory qw( malloc free );

    my $ffi = FFI::Platypus->new( api => 1 )
    $ffi->lang('CPP');
    $ffi->lib('./basic.so');

    $ffi->custom_type( Foo => {
      native_type => 'opaque',
      perl_to_native => sub { ${ $_[0] } },
      native_to_perl => sub { bless \$_[0], 'Foo' },
    });

    $ffi->attach( [ 'Foo::Foo()'     => '_new'     ] => ['Foo']  => 'void' );
    $ffi->attach( [ 'Foo::~Foo()'    => '_DESTROY' ] => ['Foo']  => 'void' );
    $ffi->attach( [ 'Foo::get_bar()' => 'get_bar'  ] => ['Foo']  => 'int'  );
    $ffi->attach( [ 'Foo::set_bar(int)'
                                     => 'set_bar'  ] => ['Foo','int']
                                                                 => 'void' );

    my $size = $ffi->function('Foo::_size()' => [] => 'int')->call;

    sub new
    {
      my($class) = @_;
      my $ptr = malloc $size;
      my $self = bless \$ptr, $class;
      _new($self);
      $self;
    }

    sub DESTROY
    {
      my($self) = @_;
      _DESTROY($self);
      free($$self);
    }

    package main;

    my $foo = Foo->new;

    print $foo->get_bar, "\n";  # 0
    $foo->set_bar(22);
    print $foo->get_bar. "\n";  # 22

DESCRIPTION

   This module provides some hooks for Platypus so that C++ names can be
   mangled for you. It uses the same primitive types as C. This document
   also documents issues and caveats that I have discovered in my attempts
   to work with C++ and FFI.

   This module is somewhat experimental. It is also available for adoption
   for anyone either sufficiently knowledgable about C++ or eager enough
   to learn enough about C++. If you are interested, please send me a pull
   request or two on the project's GitHub.

   There are numerous difficulties and caveats involved in using C++
   libraries from Perl via FFI. This document is intended to enlighten on
   that subject.

   Note that in addition to using pre-compiled C++ libraries you can
   bundle C++ code with your Perl distribution using FFI::Build. For a
   complete example, which attempts to address the caveats listed below
   you can take a look at this sample distro on GitHub:

   https://github.com/plicease/Color-FFI

CAVEATS

   In general I have done my research of FFI and C++ using the Gnu C++
   compiler. I have done some testing with clang as well.

name mangling

   C++ names are "mangled" to handle features such as function overloading
   and the fact that some characters in the C++ names are illegal machine
   code symbol names. What this means is that the C++ member function
   Foo::get_bar looks like _ZN3Foo7get_barEv to FFI::Platypus. What makes
   this even trickier is that different C++ compilers provide different
   mangling formats. When you use the FFI::Platypus#lang method to tell
   Platypus that you are intending to use it with C++, like this:

    $ffi->lang('CPP');

   it will mangle the names that you give it. That saves you having to
   figure out the "real" name for Foo::get_bar.

   The current implementation uses the c++filt command or
   FFI::Platypus::Lang::CPP::Demangle::XS if it is installed. If c++filt
   cannot be found at install time, then
   FFI::Platypus::Lang::CPP::Demangle::XS will be made a prerequsite, so
   you can have some confidence that this feature will work even if your
   platform does not provide c++filt. The XS module is not a prerequsite
   when c++filt IS found because using c++filt does not require invoking
   the compiler and may be more reliable.

   If the approach to mangling C++ names described above does not work for
   you, or if it makes you feel slightly queasy, then you can also write C
   wrapper functions around each C++ method that you want to call from
   Perl. You can write these wrapper functions right in your C++ code
   using the extern "C" trick:

    class Foo {
      public:
        int bar() { return 1; }
    }

    extern "C" int
    my_bar(Class *foo)
    {
      return foo->bar();
    }

   Then instead of attaching Foo::bar() attach my_bar.

    $ffi->attach( my_bar => [ 'Foo' ] => 'int' );

constructors, destructors and methods

   Constructors and destructors are essentially just functions that do not
   return a value that need to be called when the object is created and
   when it is no longer needed (respectively). They take a pointer to the
   object (this) as their first argument. Constructors can take additional
   arguments, as you might expect they just come after the object itself.
   Destructors take no arguments other than the object itself (this).

   You need to alloate the memory needed for the object before you call
   the constructor and free it after calling the destructor. The tricky
   bit is figuring out how much memory to allocate. If you have access to
   the header file that describes the class and a compiler you can compute
   the size from within C++ and hand it off to Perl using a static method
   as I did in the "SYNOPSIS" above.

   Regular methods also take the object pointer as their first argument.
   Additional arguments follow, and they may or may not return a value.

inline functions

   C++ compilers typically do not emit symbols for inlined functions. If
   you get a message like this:

    unable to find Foo::get_bar() at basic line 21

   even though you are sure that class has that method, this is probably
   the problem that you are having. The Gnu C++ compiler, g++ has an
   option to force it to emit the symbols, even for inlined functions:

    -fkeep-inline-functions     # use this

   Clang has an option to do the opposite of this:

    -fvisibility-inlines-hidden # do not use this

   but unhelpfully not a way to keep inlined functions. This appears to be
   a deliberate design decision made by the clang developers and it makes
   sense for C++, since inline functions are typically defined in C++
   header files (.h) so it is difficult to determine in which object file
   the uninlined inlined functions should go.

   If you have the source of the C++ and you can recompile it you can also
   optionally change it to not use inlined functions. In addition to
   removing any inline keywords from the source, you need to move the
   implementations of any methods outside of the class body. That is, do
   not do this:

    class Foo {
      public:
        int bar() { return 1; } # WRONG
    }

   Do this:

    class Foo {
      public:
        int bar();              # RIGHT
    }

    int
    Foo::bar()                  # RIGHT
    {
      return 1;
    }

the standard C++ library

   If you are getting errors like this:

    unable to find Foo::Foo()

   that can't be explained by the issues described above, set the
   environment variable FFI_PLATYPUS_DLERROR to a true value and try
   again. If you see a warning like this:

    error loading Foo.so: Foo.so: undefined symbol: __gxx_personality_v0

   then you probably need to explicitly link with the standard C++
   library. The most portable way to deal with this is by using
   ExtUtils::CppGuess.

METHODS

   Generally you will not use this class directly, instead interacting
   with the FFI::Platypus instance. However, the public methods used by
   Platypus are documented here.

native_type_map

    my $hashref = FFI::Platypus::Lang::CPP->native_type_map;

   This returns a hash reference containing the native aliases for the C++
   programming languages. That is the keys are native C++ types and the
   values are libffi native types.

mangler

    my $mangler = FFI::Platypus::Lang::CPP->mangler($ffi->libs);
    # prints _ZN9MyInteger7int_sumEii
    print $mangler->("MyInteger::int_sum(int, int)");

   Returns a subroutine reference that will "mangle" C++ names.

EXAMPLES

Using a C++ class without writing bundling any C/C++ code

   The example in the "SYNOPSIS" shows how you can use a C++ class without
   writing any wrapper code, though you will have to guess or determine
   the instance size of the class.

Using a C++ class with a wrapper

   (For the full source for this example, see examples/wrapper.{pl,cpp}
   that came with this distribution)

   Sometimes it is easier to write wrapper functions around your new and
   delete operations. Consider if you add these functions to the C++
   source to the example in the "SYNOPSIS".

    // These could also be class methods
    extern "C" Foo*
    Foo_new()
    {
      return new Foo();
    }

    extern "C" void
    Foo_delete(Foo *foo)
    {
      delete foo;
    }

   Now we can use this class without having to know in the perl code what
   the size of the class is. We declare the constructor and destructor in
   Perl space like this:

    $ffi->attach( [ 'Foo_new'        => 'new'      ] => []       => 'Foo' );
    $ffi->attach( [ 'Foo_delete'     => 'DESTROY'  ] => ['Foo']  => 'void' );

   We've also removed the Perl new and DESTROY wrappers as they are
   unnecessary now, and so the the C++ functions are attached directly to
   their intended names.

Exceptions

   (For the full source of this example, see examples/exception.{pl,cpp}
   that came with this distribution)

   If your library throws an exception and you do not catch it in C++ it
   is going to kill your program. As an example, suppose set_bar in the
   example above throws an exception:

    void
    Foo::set_bar(int value)
    {
      if(value > 512)
        throw new FooException("too hot");
      if(value < 0)
        throw new FooException("too cold");
       bar = value;
    }

   Now if you try to use set_bar with a bad value like this from Perl:

    $foo->set_bar(-2);

   it will crash your Perl program.

    terminate called after throwing an instance of 'FooException'
    Abort

   To handle this, you need to write a wrapper around the set_bar method.

    static FooException *last_exception = NULL;

    extern "C" FooException *
    Foo_get_exception()
    {
      return last_exception;
    }

    extern "C" void
    Foo_reset_exception()
    {
      if(last_exception != NULL)
        delete last_exception;
      last_exception = NULL;
    }

    extern "C" void
    Foo_set_bar(Foo *foo, int value)
    {
      try
      {
        Foo_reset_exception();
        foo->set_bar(value);
      }
      catch(FooException *e)
      {
        last_exception = e;
      }
    }

   Next we will write an interface to the FooException class in Perl:

    package FooException;

    use overload '""' => sub { "exception: " . $_[0]->message . "\n" };

    $ffi->custom_type( FooException => {
      native_type => 'opaque',
      perl_to_native => sub { ${ $_[0] } },
      native_to_perl => sub {
        defined $_[0]
        ? (bless \$_[0], 'FooException')
        : ();
      },
    });

    $ffi->attach(
      [ 'Foo_get_exception' => 'get_exception' ] => [] => 'FooException'
    );

    $ffi->attach(
      [ 'FooException::message()' => 'message' ] => ['FooException'] => 'string'
    );

   And finally we write a wrapper for the Perl set_bar method.

    $ffi->attach( [ 'Foo_set_bar'    => '_set_bar' ] => ['Foo','int']
                                                                 => 'void' );
    sub set_bar
    {
      my($self, $value) = @_;
      $self->_set_bar($value);
      my $error = FooException->get_exception;
      die $error if $error;
    }

   And now when we give set_bar a bogus value we get a Perl exception
   instead of an application crash:

    exception: too cold

   So we can easily wrap the call to set_bar in a Perl eval if we want to
   catch the exception and handle it.

SUPPORT

   If something does not work as advertised, or the way that you think it
   should, or if you have a feature request, please open an issue on this
   project's GitHub issue tracker:

   https://github.com/PerlFFI/FFI-Platypus-Lang-CPP/issues

CONTRIBUTING

   If you have implemented a new feature or fixed a bug then you may make
   a pull reequest on this project's GitHub repository:

   https://github.com/PerlFFI/FFI-Platypus-Lang-CPP/issues

   Caution: if you do this too frequently I may nominate you as the new
   maintainer. Extreme caution: if you like that sort of thing.

   This project's GitHub issue tracker listed above is not Write-Only. If
   you want to contribute then feel free to browse through the existing
   issues and see if there is something you feel you might be good at and
   take a whack at the problem. I frequently open issues myself that I
   hope will be accomplished by someone in the future but do not have time
   to immediately implement myself.

   Another good area to help out in is documentation. I try to make sure
   that there is good document coverage, that is there should be
   documentation describing all the public features and warnings about
   common pitfalls, but an outsider's or alternate view point on such
   things would be welcome; if you see something confusing or lacks
   sufficient detail I encourage documentation only pull requests to
   improve things.

SEE ALSO

   FFI::Platypus

     The Core Platypus documentation.

   FFI::Build + FFI::Build::File::CXX

     Bundle C or C++ with your FFI / Perl extension.

   ExtUtils::CppGuess

     Guess the appropriate C++ compiler / linker flags for your C compiler
     platform combination.

AUTHOR

   Graham Ollis <[email protected]>

COPYRIGHT AND LICENSE

   This software is copyright (c) 2015 by Graham Ollis.

   This is free software; you can redistribute it and/or modify it under
   the same terms as the Perl 5 programming language system itself.