h2xs -A --skip-exporter -nMyModule
-A -- no AUTOLOAD--skip-exporter -- no use Exporter-nMyModule -- name MyModuleh2xs -L/opt/local/lib -lmylib
package MyModule;
use 5.014001;
use strict;
use warnings;
our @ISA = qw();
our $VERSION = '0.01';
require XSLoader;
XSLoader::load('MyModule', $VERSION);
# Preloaded methods go here.
1;
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" MODULE = MyModule PACKAGE = MyModule
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
# typemap MyClass * O_OBJECT
MyClass * O_MYCLASS
OUTPUT
O_MYCLASS
sv_setref_pv( $arg, CLASS, (void*)$var );
INPUT
O_MYCLASS
if ( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) {
$var = ($type)SvIV((SV*)SvRV( $arg ));
}
else {
warn( \"${Package}::$func_name() -- \
$var not a blessed SV reference\" );
XSRETURN_UNDEF;
}
CLASS created by XS new()$arg replaced by Perl SV$var replaced by C/C++ variable
use 5.014001;
use ExtUtils::MakeMaker;
WriteMakefile(
NAME => 'MyModule',
VERSION_FROM => 'lib/MyModule.pm', # finds $VERSION
PREREQ_PM => {}, # e.g., Module::Name => 1.1
($] >= 5.005 ? ## Add these new keywords supported since 5.005
(ABSTRACT_FROM => 'lib/MyModule.pm', # retrieve abstract from module
AUTHOR => 'Doug <madcityzen@gmail.com>') : ()),
LIBS => [''], # e.g., '-lm'
DEFINE => '', # e.g., '-DHAVE_SOMETHING'
INC => '-I.', # e.g., '-I. -I/usr/include/other'
# Un-comment this if you add C files to link with later:
# OBJECT => '$(O_FILES)', # link all the C files too
### Add these for C++ support
CC => 'g++', # Override from Config
LD => 'g++', # Override from Config
XSOPT => '-C++',
TYPEMAPS => ['perlobject.map'],
);
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
class Card {
int value_;
enum t_suit { SPADES, CLUBS, HEARTS, DIAMONDS } suit_;
public:
Card( int value, t_suit suit ) {
value_ = value;
suit_ = suit;
}
~Card() { }
int value() { return value_; }
int suit() { return suit_; }
void set_value( int value ) {
value_ = value;
}
void set_suit( t_suit suit ) {
suit_ = t_suit;
}
};
MODULE = Card PACKAGE = Card Card * Card::new( int suit, int value ) void Card::DESTROY() int Card::value() int Card::suit() void Card::set_value( int value ) void Card::set_suit( int suit )
Card * O_OBJECT
Card::new() gives us CLASS automaticallyCard::* knows it gets a Card * and calls it THISXSOPTS => '-C++',$ perl Makefile.PL && make test
#include <vector>
class Deck {
std::vector<Card> cards_;
public:
Deck() { }
~Deck() { }
void add_card( Card card ) {
cards_.push_back( card );
}
std::vector cards() {
return cards_;
}
};
MODULE = Card PACKAGE = Deck Deck * Deck::new() void Deck::DESTROY()
package Deck;
void
Deck::add_card( suit, value )
int suit
int value
CODE:
Card card( suit, value );
THIS->add_card( card );
AV *
Deck::cards()
CODE:
std::vector<Card> cards( THIS->cards() );
std::vector<Card>::iterator iter( cards.begin() );
RETVAL = newAV(); // create an array
sv_2mortal( (SV*)RETVAL ); // "mortalize"
for ( ; iter != cards.end(); iter++ ) {
SV* card_sv( newSV(0) ); // create a scalar
sv_setref_pv( card_sv, "Card", (void*)&*iter ); // bless
av_push( RETVAL, card_sv );
}
OUTPUT:
RETVAL
my @cards = $deck->cards;sv_setref_pv - Set SV to be Reference to Pointer Value
/** Default constructor needed for STL containers */
shared_sv() : p_(0), sv_(0) {};
/** Useful constructor */
shared_sv( void* p, std::string package )
: p_(p), sv_( newSV(0) ) // Created with refcnt 1
{
if ( sv_ == 0 ) return;
sv_ = sv_setref_pv( sv_, package.c_str(), p_ );
}
shared_sv( const shared_sv& that )
: p_(that.p_), sv_(that.sv_)
{
if ( sv_ == 0 ) return; // Don't do empty SVs
// We can increment the refcount faster if we
// don't care about return value (void)
SvREFCNT_inc_void( sv_ );
}
shared_sv& operator=( const shared_sv& that ) {
if ( this == &that ) return *this; // Mandatory
p_ = that.p_;
if ( sv_ != 0 )
SvREFCNT_dec( sv_ ); // Lose our SV
sv_ = that.sv();
if ( sv_ == 0 ) return *this;
SvREFCNT_inc_void( sv_ ); // Gain their SV
return *this;
}
vector[i] = new shared_sv(...);
~shared_sv() {
if ( sv_ == 0 ) return;
SvREFCNT_dec( sv_ );
}
delete THIS
shared_sv make_card( ) {
// Card* card = new Card(); <- bad
shared_sv ssv( new Card(), "Card" ); // <- good
// We return a copy
return ssv;
// Copy means refcount incremented
}
std::vector<shared_sv> cxx_array(); // Card* card = new Card(); <- bad shared_sv ssv( new Card(), "Card" ); // <- good cxx_array.push_back( ssv ); // cxx_array keeps a copy, refcount incremented
Slides are licensed under a CC-BY-SA 3.0 license.
Code is licensed under the Artistic License or GNU GPL v1.0 or later (the same terms as Perl itself).