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++ variableuse 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 THIS
XSOPTS => '-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).