Discussion:
XS C++ return class pointers
(too old to reply)
James Shirley
2011-04-09 06:25:05 UTC
Permalink
--20cf3071cf6c40d4cb04a07667df
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

Hi, I'm trying to write a XS routine to return a point to a c++ class to be
accessible from perl..

I'm new to XS, so i've been following:

http://www.johnkeiser.com/perl-xs-c++.html

and

http://search.cpan.org/~dmr/CookBookB-19960430/

However when I try make the xs generated code, i get the following compiler
error:

g++ -c -I. -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe
-fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=3D64 -O2 -g -DVERSION=3D\"0.01\" -DXS_VERSION=3D\"0.0=
1\"
-fPIC "-I/usr/lib/perl/5.10/CORE" MyPackage.c
MyPackage.c: In function =91void XS_MyPackage_child(PerlInterpreter*, CV*)=
=92:
MyPackage.c:168: error: =91CLASS=92 was not declared in this scope
make: *** [MyPackage.o] Error 1

I assume I'm doing something wrong in the child method, however i lifted
this code out of one of the CookBookB examples..

MyClass *
MyClass::child()
CODE:
RETVAL =3D (MyClass *)safemalloc( sizeof(MyClass) );
*RETVAL =3D THIS->child();

OUTPUT:
RETVAL

CLEANUP:
safefree(RETVAL);

Any help would be much appreciated.

I have the following code:

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"

#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif

#undef list

#include <iostream>

class MyClass;

class MyClass {
private:
int _id;

public:
MyClass(int id) {
_id =3D id;
}

~MyClass() { }

void operator =3D(const MyClass &other) {
_id =3D other._id;
}

int id() {
return _id;
}

MyClass child() {
return MyClass(5);
}
};

MODULE =3D MyPackage PACKAGE =3D MyPackage

MyClass *
MyClass::new(int id)

void
MyClass::DESTROY()

MyClass *
MyClass::child()
CODE:
RETVAL =3D (MyClass *)safemalloc( sizeof(MyClass) );
*RETVAL =3D THIS->child();

OUTPUT:
RETVAL

CLEANUP:
safefree(RETVAL);

With the Makefile.PL:

use 5.010001;
use ExtUtils::MakeMaker;

$CC =3D 'g++';
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
NAME =3D> 'MyPackage',
VERSION_FROM =3D> 'lib/MyPackage.pm', # finds $VERSION
PREREQ_PM =3D> {}, # e.g., Module::Name =3D> 1.1
($] >=3D 5.005 ? ## Add these new keywords supported since 5.005
(ABSTRACT_FROM =3D> 'lib/MyPackage.pm', # retrieve abstract from mod=
ule
AUTHOR =3D> 'James <james@>') : ()),
LIBS =3D> [''], # e.g., '-lm'
DEFINE =3D> '', # e.g., '-DHAVE_SOMETHING'
INC =3D> '-I.', # e.g., '-I. -I/usr/include/other'
CC =3D> $CC,
LD =3D> '$(CC)',
XSOPT =3D> '-C++',
TYPEMAPS =3D> ['perlobject.map' ],
# Un-comment this if you add C files to link with later:
# OBJECT =3D> '$(O_FILES)', # link all the C files too
);

and the typemap:

TYPEMAP
MyClass * O_OBJECT


Cheers James

--20cf3071cf6c40d4cb04a07667df
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

Hi, I&#39;m trying to write a XS routine to return a point to a c++ class t=
o be accessible from perl..<br><br>I&#39;m new to XS, so i&#39;ve been foll=
owing:<br><br><a href=3D"http://www.johnkeiser.com/perl-xs-c++.html">http:/=
/www.johnkeiser.com/perl-xs-c++.html</a><br>
<br>and<br><br><a href=3D"http://search.cpan.org/~dmr/CookBookB-19960430/">=
http://search.cpan.org/~dmr/CookBookB-19960430/</a><br><br>However when I t=
ry make the xs generated code, i get the following compiler error:<br><br>
g++ -c=A0 -I. -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pip=
e -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET=
_BITS=3D64 -O2 -g=A0=A0 -DVERSION=3D\&quot;0.01\&quot; -DXS_VERSION=3D\&quo=
t;0.01\&quot; -fPIC &quot;-I/usr/lib/perl/5.10/CORE&quot;=A0=A0 MyPackage.c=
<br>
MyPackage.c: In function =91void XS_MyPackage_child(PerlInterpreter*, CV*)=
=92:<br>MyPackage.c:168: error: =91CLASS=92 was not declared in this scope<=
br>make: *** [MyPackage.o] Error 1<br><br>I assume I&#39;m doing something =
wrong in the child method, however i lifted this code out of one of the Coo=
kBookB examples..<br>
<br>MyClass *<br>
MyClass::child()<br>
=A0 CODE:<br>
=A0=A0=A0 RETVAL =3D (MyClass *)safemalloc( sizeof(MyClass) );<br>
=A0=A0=A0 *RETVAL =3D THIS-&gt;child();<br>
<br>
=A0 OUTPUT:<br>
=A0=A0=A0 RETVAL<br>
<br>
=A0 CLEANUP:<br>
=A0=A0=A0 safefree(RETVAL);<br><br>Any help would be much appreciated.<br><=
br>I have the following code:<br><br>#include &quot;EXTERN.h&quot;<br>#incl=
ude &quot;perl.h&quot;<br>#include &quot;XSUB.h&quot;<br><br>#include &quot=
;ppport.h&quot;<br>
<br>#ifdef __cplusplus<br>=A0 extern &quot;C&quot; {<br>#endif<br>=A0=A0=A0=
#include &quot;EXTERN.h&quot;<br>=A0=A0=A0 #include &quot;perl.h&quot;<br>=
=A0=A0=A0 #include &quot;XSUB.h&quot;<br>#ifdef __cplusplus<br>=A0 }<br>#en=
dif<br><br>#undef list<br> <br>#include &lt;iostream&gt;<br><br>class MyClass;<br><br>class MyClass {<=
br>=A0 private:<br>=A0=A0=A0 int _id;<br><br>=A0 public:<br>=A0=A0=A0 MyCla=
ss(int id) {<br>=A0=A0=A0=A0=A0 _id =3D id;<br>=A0=A0=A0 }<br>=A0=A0=A0 <br=
=A0=A0=A0 ~MyClass() { }<br><br>=A0=A0=A0 void operator =3D(const MyClass =
&amp;other) {<br>
=A0=A0=A0=A0=A0 _id =3D other._id;<br>=A0=A0=A0 }<br><br>=A0=A0=A0 int id()=
{<br>=A0=A0=A0=A0=A0 return _id;<br>=A0=A0=A0 }<br><br>=A0=A0=A0 MyClass c=
hild() {<br>=A0=A0=A0=A0=A0 return MyClass(5);<br>=A0=A0=A0 }<br>};<br><br>=
MODULE =3D MyPackage=A0=A0=A0 PACKAGE =3D MyPackage<br><br>MyClass *<br>
MyClass::new(int id)<br><br>void<br>MyClass::DESTROY()<br><br>MyClass *<br>=
MyClass::child()<br>=A0 CODE:<br>=A0=A0=A0 RETVAL =3D (MyClass *)safemalloc=
( sizeof(MyClass) );<br>=A0=A0=A0 *RETVAL =3D THIS-&gt;child();<br><br>=A0 =
OUTPUT:<br>=A0=A0=A0 RETVAL<br>
<br>=A0 CLEANUP:<br>=A0=A0=A0 safefree(RETVAL);<br><br>With the Makefile.PL=
:<br><br>use 5.010001;<br>use ExtUtils::MakeMaker;<br><br>$CC =3D &#39;g++&=
#39;;<br># See lib/ExtUtils/MakeMaker.pm for details of how to influence<br=
# the contents of the Makefile that is written.<br>
WriteMakefile(<br>=A0=A0=A0 NAME=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D=
&gt; &#39;MyPackage&#39;,<br>=A0=A0=A0 VERSION_FROM=A0=A0=A0=A0=A0 =3D&gt; =
&#39;lib/MyPackage.pm&#39;, # finds $VERSION<br>=A0=A0=A0 PREREQ_PM=A0=A0=
=A0=A0=A0=A0=A0=A0 =3D&gt; {}, # e.g., Module::Name =3D&gt; 1.1<br>=A0=A0=
=A0 ($] &gt;=3D 5.005 ?=A0=A0=A0=A0 ## Add these new keywords supported sin=
ce 5.005<br>
=A0=A0=A0=A0=A0 (ABSTRACT_FROM=A0 =3D&gt; &#39;lib/MyPackage.pm&#39;, # ret=
rieve abstract from module<br>=A0=A0=A0=A0=A0=A0 AUTHOR=A0=A0=A0=A0=A0=A0=
=A0=A0 =3D&gt; &#39;James &lt;james@&gt;&#39;) : ()),<br>=A0=A0=A0 LIBS=A0=
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt; [&#39;&#39;], # e.g., &#39;-lm=
&#39;<br>
=A0=A0=A0 DEFINE=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt; &#39;&#39;, # e.g=
., &#39;-DHAVE_SOMETHING&#39;<br>=A0=A0=A0 INC=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0=A0=A0=A0 =3D&gt; &#39;-I.&#39;, # e.g., &#39;-I. -I/usr/include/othe=
r&#39;<br>=A0=A0=A0 CC=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt;=
$CC,<br>=A0=A0=A0 LD=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt; =
&#39;$(CC)&#39;,<br>
=A0=A0=A0 XSOPT=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt; &#39;-C++&#39;,= <br>=A0=A0=A0 TYPEMAPS=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt; [&#39;perlobject.=
map&#39; ],<br>=A0 # Un-comment this if you add C files to link with later:= <br>=A0=A0=A0 # OBJECT=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt; &#39;$(O_FI=
LES)&#39;, # link all the C files too<br>
);<br><br>and the typemap:<br><br>TYPEMAP<br>MyClass *=A0=A0=A0=A0=A0=A0=A0=
=A0 O_OBJECT<br><br><br>Cheers James<br>
James Shirley
2011-04-10 02:08:50 UTC
Permalink
Steffen,

Thanks, I've tried your ExtUtils::XSpp, however I seem to be having the same
problem. I've modified the included Object-WithIntAndString example to
include a child method, below is the patch:

diff -Naur
../../../a/ExtUtils-XSpp-0.1601/examples/Object-WithIntAndString/IntAndString.cc
./IntAndString.cc
---
../../../a/ExtUtils-XSpp-0.1601/examples/Object-WithIntAndString/IntAndString.cc
2011-03-12 17:26:28.000000000 +0800
+++ ./IntAndString.cc 2011-04-10 10:04:00.292399419 +0800
@@ -28,3 +28,7 @@
fString = string(arg);
}

+IntAndString *IntAndString::child() {
+ return new IntAndString("chidl", 5);
+}
+
diff -Naur
../../../a/ExtUtils-XSpp-0.1601/examples/Object-WithIntAndString/IntAndString.h
./IntAndString.h
---
../../../a/ExtUtils-XSpp-0.1601/examples/Object-WithIntAndString/IntAndString.h
2011-03-12 17:26:28.000000000 +0800
+++ ./IntAndString.h 2011-04-10 09:57:51.300387585 +0800
@@ -3,6 +3,8 @@

#include <string>

+class IntAndString;
+
class IntAndString {
public:
IntAndString();
@@ -15,6 +17,8 @@
void SetValue(int arg);
void SetValue(const char* arg);

+ IntAndString *child();
+

private:
std::string fString;
diff -Naur
../../../a/ExtUtils-XSpp-0.1601/examples/Object-WithIntAndString/Object-WithIntAndString.xsp
./Object-WithIntAndString.xsp
---
../../../a/ExtUtils-XSpp-0.1601/examples/Object-WithIntAndString/Object-WithIntAndString.xsp
2011-03-12 17:26:28.000000000 +0800
+++ ./Object-WithIntAndString.xsp 2011-04-10 09:59:33.685003371 +0800
@@ -19,6 +19,8 @@
int GetInt();
const char* GetString ();

+ IntAndString *child();
+
// SetValue is polymorphic. We want separate methods in Perl
%name{SetString} void SetValue( const char* arg = NULL );
%name{SetInt} void SetValue( int arg );

When I compile, I get the same error:

WithIntAndString.c: In function ‘void
XS_Object__WithIntAndString_child(PerlInterpreter*, CV*)’:
WithIntAndString.c:292: error: ‘CLASS’ was not declared in this scope
make: *** [WithIntAndString.o] Error 1

It seems I will need to spend some time to understand XS and perl guts. I
was just hoping to add a perl interface without spending to much time..

Cheers

James
Hi James,
while I have a fair amount of experience with wrapping C++ using XS, it's
one of those things I have to relearn almost every time I use it.
Post by James Shirley
Hi, I'm trying to write a XS routine to return a point to a c++ class to
be accessible from perl..
http://www.johnkeiser.com/perl-xs-c++.html
and
http://search.cpan.org/~dmr/CookBookB-19960430/
If you're interested in a different approach, have a look at ExtUtils::XSpp
(and possibly Module::Build::With::WithXSpp) and the slides from my talk at
YAPC::EU in Pisa, 2010: http://steffen-mueller.net/talks/xspp/
ExtUtils::XSpp generates XS for wrapping C++. That means you can even look
at the generated XS to steal from it.
However when I try make the xs generated code, i get the following
Post by James Shirley
g++ -c -I. -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing
-pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64 -O2 -g -DVERSION=\"0.01\" -DXS_VERSION=\"0.01\"
-fPIC "-I/usr/lib/perl/5.10/CORE" MyPackage.c
MyPackage.c:168: error: ‘CLASS’ was not declared in this scope
make: *** [MyPackage.o] Error 1
I assume I'm doing something wrong in the child method, however i lifted
this code out of one of the CookBookB examples..
MyClass *
MyClass::child()
RETVAL = (MyClass *)safemalloc( sizeof(MyClass) );
*RETVAL = THIS->child();
Hmm. Generally, look at the C(++) code that is generated by xsubpp. In a
lot of cases, it is more instructive for debugging than XS.
In this case, I bet that your typemap for O_OBJECT uses the CLASS (C)
variable for finding the Perl class name to bless the new object into. The
code for setting CLASS is generated by xsubpp/ExtUtils::ParseXS.
Unfortunately, there's some special case logic for new() methods. Quoting
my $arg0 = ((defined($static) or $func_name eq 'new')
? "CLASS" : "THIS");
Yikes. A better solution for the preprocessor would be to have an XS
attribute/decorator that indicates "this requires CLASS to be set" and/or
"this is a constructor" or whatever. Hmm, it's actually something that
should be part of the typemap. "Please set CLASS for this typemap". One can
dream. But I'll certainly push this on top of the stack of things to look
into wrt. rethinking how typemaps work at the upcoming QA hackathon. Any
input would be welcome on this.
Getting back to your problem: You could work around this by creating a new
Perl object manually in your XS wrapper (with the known class name) and
pushing it on the stack manually, too. In that case, set the return type of
your XSUB to void. This is what your typemap normally does for you, so you
can take the code from there. It probably involves at least the XPUSHs macro
and likely either sv_bless or sv_setref_iv or another sv_setref_* macro. See
perlapi.pod.
Best regards,
Steffen
Steffen Mueller
2011-04-10 07:51:53 UTC
Permalink
Hi James,
Post by James Shirley
It seems I will need to spend some time to understand XS and perl guts.
I was just hoping to add a perl interface without spending to much time..
I think you should read the rest of my previous message more carefully.
Quite likely, it explains what your problem is and how to work around it.

--Steffen
James Shirley
2011-04-17 03:53:16 UTC
Permalink
Steffen,

Thankyou. I've resolved my problems quite simply by specifying the CLASS
variable, after reading the generated c code..

So instead of:


MyClass *
MyClass::child()
CODE:
RETVAL = (MyClass *)safemalloc( sizeof(MyClass) );
*RETVAL = THIS->child();

OUTPUT:
RETVAL

CLEANUP:
safefree(RETVAL);

I used:

MyClass *
MyClass::child()
CODE:
const char *CLASS = "MyPackage";
RETVAL = new MyClass(THIS->child());

OUTPUT:
RETVAL


Cheers

James
Hi James,
Post by James Shirley
It seems I will need to spend some time to understand XS and perl guts.
I was just hoping to add a perl interface without spending to much time..
I think you should read the rest of my previous message more carefully.
Quite likely, it explains what your problem is and how to work around it.
--Steffen
Steffen Mueller
2011-04-09 17:08:11 UTC
Permalink
Hi James,

while I have a fair amount of experience with wrapping C++ using XS,
it's one of those things I have to relearn almost every time I use it.
Post by James Shirley
Hi, I'm trying to write a XS routine to return a point to a c++ class to
be accessible from perl..
http://www.johnkeiser.com/perl-xs-c++.html
and
http://search.cpan.org/~dmr/CookBookB-19960430/
If you're interested in a different approach, have a look at
ExtUtils::XSpp (and possibly Module::Build::With::WithXSpp) and the
slides from my talk at YAPC::EU in Pisa, 2010:
http://steffen-mueller.net/talks/xspp/

ExtUtils::XSpp generates XS for wrapping C++. That means you can even
look at the generated XS to steal from it.
Post by James Shirley
However when I try make the xs generated code, i get the following
g++ -c -I. -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing
-pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64 -O2 -g -DVERSION=\"0.01\" -DXS_VERSION=\"0.01\"
-fPIC "-I/usr/lib/perl/5.10/CORE" MyPackage.c
MyPackage.c:168: error: ‘CLASS’ was not declared in this scope
make: *** [MyPackage.o] Error 1
I assume I'm doing something wrong in the child method, however i lifted
this code out of one of the CookBookB examples..
MyClass *
MyClass::child()
RETVAL = (MyClass *)safemalloc( sizeof(MyClass) );
*RETVAL = THIS->child();
Hmm. Generally, look at the C(++) code that is generated by xsubpp. In a
lot of cases, it is more instructive for debugging than XS.

In this case, I bet that your typemap for O_OBJECT uses the CLASS (C)
variable for finding the Perl class name to bless the new object into.
The code for setting CLASS is generated by xsubpp/ExtUtils::ParseXS.
Unfortunately, there's some special case logic for new() methods.
Quoting from the newest EU::ParseXS:

my $arg0 = ((defined($static) or $func_name eq 'new')
? "CLASS" : "THIS");

Yikes. A better solution for the preprocessor would be to have an XS
attribute/decorator that indicates "this requires CLASS to be set"
and/or "this is a constructor" or whatever. Hmm, it's actually something
that should be part of the typemap. "Please set CLASS for this typemap".
One can dream. But I'll certainly push this on top of the stack of
things to look into wrt. rethinking how typemaps work at the upcoming QA
hackathon. Any input would be welcome on this.

Getting back to your problem: You could work around this by creating a
new Perl object manually in your XS wrapper (with the known class name)
and pushing it on the stack manually, too. In that case, set the return
type of your XSUB to void. This is what your typemap normally does for
you, so you can take the code from there. It probably involves at least
the XPUSHs macro and likely either sv_bless or sv_setref_iv or another
sv_setref_* macro. See perlapi.pod.

Best regards,
Steffen
Loading...