malware/APT detection, silicon valley, entrepreneur, CTO, start-up operation, team build, Nanjing/Beijing, if you want to do creative things, join the adventure.
全部博文(47)
分类:
2009-05-30 02:10:22
MyPackage
directory.Create a MyPackage/typemap
file with the following text:
TYPEMAP
MyClass * O_OBJECT
Add C++ directives to MyPackage/Makefile.PL
, like so:
use ExtUtils::MakeMaker;
$CC = 'g++';
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
'NAME' => 'MyPackage',
'VERSION_FROM' => 'MyPackage.pm', # finds $VERSION
'PREREQ_PM' => {}, # e.g., Module::Name => 1.1
($] >= 5.005 ? ## Add these new keywords supported since 5.005
(ABSTRACT_FROM => 'MyPackage.pm', # retrieve abstract from module
AUTHOR => 'John Keiser') : ()),
'LIBS' => [], # e.g., '-lm'
'DEFINE' => '', # e.g., '-DHAVE_SOMETHING'
'CC' => $CC,
'LD' => '$(CC)',
# Insert -I. if you add *.h files later:
'INC' => "", # e.g., '-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
'XSOPT' => '-C++',
'TYPEMAPS' => ['perlobject.map' ],
);
That's all you have to do, basically. You might have a problem if you use the C++ standard library "list" class, so see below if you have that.
What this procedure does: Step 1 creates the actual package. Step 2 makes the Perl headers compile and link correctly. Step 3 adds the type mapping necessary to get object pointers to map to Perl objects. Step 4 causes MakeMaker (and consequently make) to use C++ to compile and link the program.
To run the program, just do:
perl Makefile.PL
make test
The examples in the next section are best placed into test.pl
, which will automatically run when
you do make test
. It sets the variables and paths and such correctly. You will have to do
make install
before you can properly do use MyPackage;
in Perl.
Once you have the files set up (the hard part) you get to do the programming, which is pretty easy. I am not going to go over XS programming here; it's covered acceptably (though not as thoroughly as one would like) in the references below.
The typemap you copied into the directory handles mapping between Perl scalars and MyType *. In other words, the Perl object now represents a pointer to your object, without you having to do anything special to make it happen except declare new()! (And you don't have to do any work in new either, XS handles that.
First, you should know that anything you put before that MODULE=... line will be compiled as straight C++. XS will not do any special processing to it, it will go straight up to the C++ compiler the way it is.
You might put a custom class definition here (or you can use a C++ class definition already in a header file). You might put some custom functions here. You might put some global variables here. You might ignore me and skip to the next section on constructors.
XS won't define your class for you. It is expecting a class to already be there. Either include the header file with the class in it or make a class definition in the straight C++ section.
This seems like a scary subject until you actually just put MyClass::new() and MyClass::DESTROY() functions into the file. XS does the mapping automatically. It even supports constructor args. Yay!
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
#include
class MyClass {
public:
MyClass(char * my_favorite_argument) {
cout << "I'm constructin' my bad self ... " << my_favorite_argument << "\n";
}
~MyClass() { cout << "Destruction is a way of life for me.\n"; }
};
MODULE = MyPackage PACKAGE = MyPackage
MyClass *
MyClass::new(char * my_favorite_argument)
void
MyClass::DESTROY()
Note here how MyClass and MyPackage don't have to have the same name. You can name the Perl package anything you want. XS will map the C++ functions to Perl functions based on the names you give the functions and the most recent PACKAGE directive.
Put this into test.pl at the bottom:
my $x = new MyPackage("Hi.");
This test will output:
I'm constructin' my bad self ... Hi.
Destruction is a way of life for me.
If you have simple non-list, non-hash return values and arguments, you can write the code for your
member function as a member of the class, and just add
after the MODULE= line. XS will automagically
hook the Perl function up to the class member function and return its return value.
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
#include
class MyClass {
public:
MyClass(char * my_favorite_argument) {
cout << "I'm constructin' my bad self ... " << my_favorite_argument << "\n";
}
~MyClass() { cout << "Destruction is a way of life for me.\n"; }
int wow() { return 12 / 3; }
};
MODULE = MyPackage PACKAGE = MyPackage
MyClass *
MyClass::new(char * my_favorite_argument)
void
MyClass::DESTROY()
int
MyClass::wow()
Put this into test.pl at the bottom (remove the previous test):
my $x = new MyPackage("Hi.");
print $x->wow, " is the magic number.\n";
This test will output:
I'm constructin' my bad self ... Hi.
4 is the magic number.
Destruction is a way of life for me.
If you have to return a list or hash or accept a list or hash argument, or do other funky Perl stuff,
you should use PPCODE. See the references below to learn how to code these. The only special thing that
happens when you create a C++ member function is you get a MyClass *
named THIS
.
So you can call functions like this: THIS->memberFunc()
.
Note that when you create a member function with PPCODE you do not have to have a corresponding class member function (though you can if you want, it just won't be called automatically). The PPCODE is the function.
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
#include
class MyClass {
public:
MyClass(char * my_favorite_argument) {
cout << "I'm constructin' my bad self ... " << my_favorite_argument << "\n";
}
~MyClass() { cout << "Destruction is a way of life for me.\n"; }
int wow() { return 12 / 3; }
};
MODULE = MyPackage PACKAGE = MyPackage
MyClass *
MyClass::new(char * my_favorite_argument)
void
MyClass::DESTROY()
int
MyClass::wow()
void
MyClass::wow2()
PPCODE:
for(int i=1;i<=10;i++) {
XPUSHs(sv_2mortal(newSVnv(i * THIS->wow())));
}
Put this into test.pl at the bottom (remove the previous test):
my $x = new MyPackage("Hi.");
print "Multiples of 4: ", join(", ", $x->wow2()), "\n";
This test will output:
I'm constructin' my bad self ... Hi.
Multiples of 4: 4, 8, 12, 16, 20, 24, 28, 32, 36, 40
Destruction is a way of life for me.
You'd think you could access member variables from Perl like a hash, right? Not recommended. Only functions are supported, though if you wanted you could create a hash and tie it to the class. Use and shadow classing if you want to access fields in a hash.
list.h
Perl has a conflict with the C++ standard library: they both define the "list" structure. There are
two ways of solving this, depending on whether you are actually interested in using the list structure or
not. If you don't need the list (like if just the headers need it) or you need Perl's list structure for
some reason, you should just include your header files (and/or stdlib) before the standard Perl include
files. For example, if you have a header file
that includes
, do this:
#include
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
If you want to use the C++ stdlib list object in the Perl file itself, you need to #undef list and
then include your files after the standard Perl headers (including
if your
header files do not include list).
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
#undef list
#include
#include
If one method doesn't work, try the other. If you need both in one file, you may be able to use the first
method, put your functions that require the C++ list last in the file, and then do #undef list
and #include
just before you . This is untested though, and really not recommended
because it's ugly. Thanks to
Tye McQueen for the info that
led to this section.
XS is pretty cool, and actually fairly simple once you understand it. The tutorial and manpage for XS give you some decent basic information, but they won't tell you everything you need to know to get an XS package off the ground. Here are all the pointers I found (in order of their usefulness to me in figuring stuff out):