Skip to content

Commit 95a623b

Browse files
committed
perlxs.pod: update "Using XS With C++" section
Rewrite this section: =head2 Using XS With C++ Disclaimer: I've never written a proper C++ program. I had to (literally) dust off my 34-year old copy of Stroustrup(*) and also do some Googling. Hopefully what I've written is sane. (*) This was bought back in the days when people used to to learn things by buying books, and when I thought that I ought to know something about this newfangled C++ thing. I never got round to reading all of it: I discovered Perl around the same time, which looked to be a lot more fun.
1 parent 35fc3f0 commit 95a623b

File tree

2 files changed

+218
-79
lines changed

2 files changed

+218
-79
lines changed

dist/ExtUtils-ParseXS/lib/perlxs.pod

Lines changed: 217 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -4289,112 +4289,250 @@ entry will be used instead.
42894289

42904290
=head2 Using XS With C++
42914291

4292-
If an XSUB name contains C<::>, it is considered to be a C++ method.
4293-
The generated Perl function will assume that
4294-
its first argument is an object pointer. The object pointer
4295-
will be stored in a variable called THIS. The object should
4296-
have been created by C++ with the new() function and should
4297-
be blessed by Perl with the sv_setref_pv() macro. The
4298-
blessing of the object by Perl can be handled by a typemap. An example
4299-
typemap is shown at the end of this section.
4300-
4301-
If the return type of the XSUB includes C<static>, the method is considered
4302-
to be a static method. It will call the C++
4303-
function using the class::method() syntax. If the method is not static
4304-
the function will be called using the THIS-E<gt>method() syntax.
4305-
4306-
The next examples will use the following C++ class.
4307-
4308-
class color {
4309-
public:
4310-
color();
4311-
~color();
4312-
int blue();
4313-
void set_blue(int);
4292+
MODULE = Foo::Bar PACKAGE = Foo::Bar
43144293

4315-
private:
4316-
int c_blue;
4317-
};
4294+
# Class methods
43184295

4319-
The XSUBs for the blue() and set_blue() methods are defined with the class
4320-
name but the parameter for the object (THIS, or "self") is implicit and is
4321-
not listed.
4296+
int
4297+
X::Y::new(int i)
4298+
4299+
static int
4300+
X::Y::foo(int i)
4301+
4302+
# Object methods
4303+
4304+
int
4305+
X::Y::bar(int i)
43224306

43234307
int
4324-
color::blue()
4308+
X::Y::bar2(int i) const
43254309

43264310
void
4327-
color::set_blue(val)
4328-
int val
4311+
X::Y::DESTROY()
4312+
4313+
# C-linkage function
4314+
4315+
extern "C" int
4316+
baz(int i)
4317+
4318+
XS provides limited support for generating C++ (as opposed to C) output
4319+
files. Any XSUB whose name includes C<::> is treated as a C++ method. This
4320+
triggers two main changes in the way the XSUB's code is generated:
4321+
4322+
=over
4323+
4324+
=item *
4325+
4326+
An implicit first argument is added. For class methods, this will be
4327+
called C<CLASS> and will be of type C<char *>. For object methods, it will
4328+
be called C<THIS> and be of type C<X::Y *> (where C<X::Y::> is the prefix
4329+
of the XSUB's name). XSUBs are treated as class methods if their name is
4330+
C<new> or their return type has the C<static> prefix.
4331+
4332+
=item *
43294333

4330-
Both Perl functions will expect an object as the first parameter. In the
4331-
generated C++ code the object is called C<THIS>, and the method call will
4332-
be performed on this object. So in the C++ code the blue() and set_blue()
4333-
methods will be called as this:
4334+
Any autocall will generate an appropriate C++ method call rather then a C
4335+
function call. In particular, based on the examples above:
43344336

4335-
RETVAL = THIS->blue();
4337+
new: RETVAL = new X::Y(i);
4338+
static foo: RETVAL = X::Y::foo(i);
4339+
bar (and bar2): RETVAL = THIS->bar(i);
4340+
DESTROY: delete THIS;
43364341

4337-
THIS->set_blue(val);
4342+
=item *
4343+
4344+
In addition, if the XSUB declaration has a trailing C<const>, then the
4345+
type of C<THIS> will be declared as C<const X::Y *>.
43384346

4339-
You could also write a single get/set method using an optional argument:
4347+
=back
4348+
4349+
This is mostly just syntactic sugar. The C<bar> XSUB declaration above
4350+
could be written longhand as:
43404351

43414352
int
4342-
color::blue(val = NO_INIT)
4343-
int val
4344-
PROTOTYPE $;$
4345-
CODE:
4346-
if (items > 1)
4347-
THIS->set_blue(val);
4348-
RETVAL = THIS->blue();
4349-
OUTPUT:
4350-
RETVAL
4353+
bar(X::Y* THIS, int i)
4354+
CODE:
4355+
RETVAL = THIS->foo(i);
4356+
OUTPUT:
4357+
RETVAL
43514358

4352-
If the function's name is B<DESTROY> then the C++ C<delete> function will be
4353-
called and C<THIS> will be given as its parameter. The generated C++ code for
4359+
Note that the type of C<THIS> (and, since Perl 5.42, C<CLASS>) can be
4360+
overridden with a line in an C<INPUT> section:
43544361

4355-
void
4356-
color::DESTROY()
4362+
int
4363+
X::Y::bar(int i)
4364+
X::Y::Z *THIS
43574365

4358-
will look like this:
4366+
Finally, a plain C XSUB declaration can be prefixed with C<extern "C"> to
4367+
give that XSUB C linkage.
43594368

4360-
color *THIS = ...; // Initialized as in typemap
4369+
Some of the methods above might be called from Perl using code like this:
43614370

4362-
delete THIS;
4371+
{
4372+
my $obj = Foo::Bar->new(1);
4373+
$obj->bar(2);
4374+
# implicit $obj->DESTROY();
4375+
}
43634376

4364-
If the function's name is B<new> then the C++ C<new> function will be called
4365-
to create a dynamic C++ object. The XSUB will expect the class name, which
4366-
will be kept in a variable called C<CLASS>, to be given as the first
4367-
argument.
4377+
This example uses C<Foo::Bar> rather than C<X::Y> to emphasise that the
4378+
name of the C++ class needn't follow the Perl package name.
43684379

4369-
color *
4370-
color::new()
4380+
The call to C<new()> will pass the string C<"Foo::Bar"> as the first
4381+
argument, which can be used to allow multiple Perl classes to share the
4382+
same C<new()> method. In the simple worked example below, the package name
4383+
is hard-coded and that parameter is unused. The C<new()> method is
4384+
expected to return a Perl object which in some way has a pointer to the
4385+
underlying C++ object embedded within it. This is similar to the
4386+
L</T_PTROBJ and opaque handles> example of wrapping a C library which
4387+
uses a handle, although with a subtle difference, as explained below.
43714388

4372-
The generated C++ code will call C<new>.
4389+
Calling C<bar()> passes this Perl object as the first argument, which the
4390+
typemap will use to extract the C++ object pointer and assign to the
4391+
C<THIS> auto variable.
43734392

4374-
RETVAL = new color();
4393+
=head3 A complete C++ example
43754394

4376-
The following is an example of a typemap that could be used for this C++
4377-
example.
4395+
First, you need to tell MakeMaker or similar that the generated file
4396+
should be compiled using a C++ compiler. For basic experimentation you may
4397+
be able to get by with just adding these two lines to the
4398+
C<WriteMakefile()> method call in F<Makefile.PL>:
43784399

4379-
TYPEMAP
4380-
color * O_OBJECT
4400+
CC => 'c++',
4401+
LD => '$(CC)',
43814402

4382-
OUTPUT
4383-
# The Perl object is blessed into 'CLASS', which should be a
4384-
# char* having the name of the package for the blessing.
4385-
O_OBJECT
4386-
sv_setref_pv($arg, CLASS, (void*)$var);
4403+
but for portability in production use, you may want to use something like
4404+
L<ExtUtils::CppGuess> to automatically generate the correct options for
4405+
L<ExtUtils::MakeMaker> or L<Module::Build> based on which C++ compiler
4406+
is available.
4407+
4408+
Then create a C<.xs> file like this:
4409+
4410+
#define PERL_NO_GET_CONTEXT
4411+
4412+
#include "EXTERN.h"
4413+
#include "perl.h"
4414+
#include "XSUB.h"
4415+
#include "ppport.h"
4416+
4417+
namespace Paint {
4418+
class color {
4419+
int c_R;
4420+
int c_G;
4421+
int c_B;
4422+
public:
4423+
color(int r, int g, int b) { c_R = r; c_G = g; c_B = b; }
4424+
~color() { printf("destructor called\n"); }
4425+
int blue() { return c_B; }
4426+
void set_blue(int b) { c_B = b; };
4427+
// and similar for red, green
4428+
};
4429+
}
4430+
4431+
typedef Paint::color Paint__color;
4432+
4433+
MODULE = Foo::Bar PACKAGE = Foo::Bar
4434+
4435+
PROTOTYPES: DISABLE
4436+
4437+
TYPEMAP: <<EOF
4438+
Paint::color * T_PKG_OBJ
43874439

43884440
INPUT
4389-
O_OBJECT
4390-
if (sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG))
4391-
$var = ($type)SvIV((SV*)SvRV($arg));
4392-
else {
4393-
warn(\"${Package}::$func_name() -- \"
4394-
\"$var is not a blessed SV reference\");
4395-
XSRETURN_UNDEF;
4396-
}
4441+
T_PKG_OBJ
4442+
SvGETMAGIC($arg);
4443+
if (SvROK($arg) && sv_derived_from($arg, "$Package")) {
4444+
IV tmp = SvIV((SV*)SvRV($arg));
4445+
$var = INT2PTR($type,tmp);
4446+
}
4447+
else {
4448+
const char* refstr = SvROK($arg)
4449+
? "" : SvOK($arg) ? "scalar " : "undef";
4450+
Perl_croak_nocontext(
4451+
"%s: Expected %s to be of type %s; got %s%"
4452+
SVf " instead",
4453+
${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq["$pname"]},
4454+
"$var", "$Package",
4455+
refstr, $arg
4456+
);
4457+
}
4458+
4459+
T_PKG_REF
4460+
SvGETMAGIC($arg);
4461+
if (SvROK($arg)) {
4462+
IV tmp = SvIV((SV*)SvRV($arg));
4463+
$var = INT2PTR($type,tmp);
4464+
}
4465+
else
4466+
Perl_croak_nocontext("%s: %s is not a reference",
4467+
${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq["$pname"]},
4468+
"$var")
4469+
4470+
OUTPUT
4471+
T_PKG_OBJ
4472+
sv_setref_pv($arg, "$Package", (void*)$var);
4473+
4474+
EOF
4475+
4476+
Paint::color *
4477+
Paint::color::new(int r, int g, int b)
4478+
4479+
int
4480+
Paint::color::blue()
4481+
4482+
void
4483+
Paint::color::set_blue(int b)
4484+
4485+
void
4486+
Paint::color::DESTROY()
4487+
4488+
In the C part of the XS file (or this case, the C++ part), a trivial
4489+
example C++ class is defined. This would more typically be a pre-existing
4490+
library with just the appropriate C<#include>. The example includes a
4491+
namespace to make it clearer when something is a namespace, class name or
4492+
Perl package. The Perl package is called C<Foo::Bar> rather than
4493+
C<Paint::color> to again distinguish it. You could however call the Perl
4494+
package C<Paint::color> if you desired.
4495+
4496+
A single typedef follows to allow for XS-mangled class names, as explained
4497+
in L</Fully-qualified type names and Perl objects>.
4498+
4499+
Then the C<MODULE> line starts the XS part of the file.
4500+
4501+
Then there follows a full definition of a new typemap called C<T_PKG_OBJ>.
4502+
This is actually a direct copy of the C<T_PTROBJ> typemap found in the
4503+
system typemap file, except that all occurrences of C<$ntype> have been
4504+
replaced with C<$Package>. It serves the same basic purpose as
4505+
C<T_PTROBJ>: embedding a pointer within a new blessed Perl object,
4506+
and later, retrieving that pointer from the object. The difference is in
4507+
terms of what package the object is blessed into. C<T_PTROBJ> expects the
4508+
type name (C<Paint::color>) to already be a pointer type, but with a C++
4509+
XSUB, the implicit C<THIS> argument is automatically declared to be of
4510+
type C<Paint::color *> (so C<Paint::color> itself isn't necessarily a
4511+
pointer type). In addition, when the Perl and C++ class names differ we
4512+
want the object to be blessed using the Perl package name, not the C++
4513+
class name. In this example, the actual values of the two variables when
4514+
the typemap template is being evalled, are:
4515+
4516+
$ntype = "Paint::colorPtr";
4517+
$Package = "Foo::Bar";
4518+
4519+
The typemap also includes an INPUT definition for C<T_PKG_REF>, which is
4520+
an I<exact> copy of C<T_PTRREF>. This is needed because, as an
4521+
optimisation, the XS parser automatically renames an INPUT typemap using
4522+
C<s/OBJ$/REF/> if the name of the XSUB is C<DESTROY>, on the grounds that
4523+
it's not necessary to to check that the object is the right class.
4524+
4525+
Finally the XS file includes a few XSUBs which are wrappers around the
4526+
class's methods.
4527+
4528+
This class might be used like this:
4529+
4530+
use Foo::Bar;
43974531

4532+
my $color = Foo::Bar->new(0x10, 0x20, 0xff);
4533+
printf "blue=%d\n", $color->blue(); # prints 255
4534+
$color->set_blue(0x80);
4535+
printf "blue=%d\n", $color->blue(); # prints 128
43984536

43994537
=head2 Safely Storing Static Data in XS
44004538

t/porting/known_pod_issues.dat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ exit(3)
123123
Expect
124124
Exporter::Easy
125125
ExtUtils::Constant::ProxySubs
126+
ExtUtils::CppGuess
126127
fchdir(2)
127128
fchmod(2)
128129
fchown(2)

0 commit comments

Comments
 (0)