P
PerlNovice
Below is the message from Tassilo that shows how to work the XS
module. I did exactly what he said and it is not working for me.
When I run: perl Makefile.PL && make; I get an error:
Writing Makefile for Hello::World
make: Error -- rem: The system cannot find the file specified.
make: Error code -1
I have no idea what this means and why it occurs.
I also tried Inline C and I get the following error:
Undefined subroutine &main::hello called at ./test_inline.pl line 4.
Can someone please help!
Tassilo's posting:
Another alternative way is using pure XS. Inline::C/C++ are just
wrappers around XS. They look simpler but they aren't really. XS has
the
advantage that development happens in a more standard way: You work on
the .xs file and use another console to do a 'make'. Errors are thus
appearing on your console and not dumped in files in a hidden
directory
(as Inline does it).
When working with XS, you usually have the overhead of creating a real
module. But that's not really a bad thing. You start with h2xs:
ethan@ethan:~/Projects$ h2xs -c -b 5.5.3 -n Hello::World
Writing Hello/World/ppport.h
Writing Hello/World/World.pm
Writing Hello/World/World.xs
Writing Hello/World/Makefile.PL
Writing Hello/World/README
Writing Hello/World/t/1.t
Writing Hello/World/Changes
Writing Hello/World/MANIFEST
This creates a skeletal module with all required files. The -b switch
adds a compatibility layer to your module so that the newer portions
of
the PerlAPI will be made compatible with at least 5.00503 (for this
case).
After that, you add the functionality to Hello/World/World.xs. Right
now
it only contains:
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
MODULE = Hello::World PACKAGE = Hello::World
Adding an XS function that prints its argument as string looks like:
void
hello(string)
SV *string;
PPCODE:
printf("hello, %s\n", SvPV_nolen(string));
You put this below the 'MODULE =' line. Now you go to the other
console
and do a 'perl Makefile.PL && make':
ethan@ethan:~/Projects/Hello/World$ perl Makefile.PL && make
Checking if your kit is complete...
Looks good
Writing Makefile for Hello::World
cp World.pm blib/lib/Hello/World.pm
AutoSplitting blib/lib/Hello/World.pm (blib/lib/auto/Hello/World)
/usr/bin/perl /usr/lib/perl5/5.8.0/ExtUtils/xsubpp -typemap
/usr/lib/perl5/5.8.0/ExtUtils/typemap World.xs > World.xsc && mv
World.xsc World.c
Please specify prototyping behavior for World.xs (see perlxs manual)
cc -c -I. -O3 -march=athlon -fno-strict-aliasing -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64 -O2 -DVERSION=\"0.01\" -DXS_VERSION=\"0.01\"
-fpic "-I/usr/lib/perl5/5.8.0/i686-linux/CORE" World.c
Running Mkbootstrap for Hello::World ()
chmod 644 World.bs
rm -f blib/arch/auto/Hello/World/World.so
LD_RUN_PATH="" cc -shared -L/usr/local/lib World.o -o
blib/arch/auto/Hello/World/World.so
chmod 755 blib/arch/auto/Hello/World/World.so
cp World.bs blib/arch/auto/Hello/World/World.bs
chmod 644 blib/arch/auto/Hello/World/World.bs
Manifying blib/man3/Hello::World.3
And now, you can already call your function without installing the
module:
ethan@ethan:~/Projects/Hello/World$ perl -Mblib -MHello::World
Hello::World::hello("world");
__END__
hello, world
ethan@ethan:~/Projects/Hello/World$
If you do a 'make install' you have this module properly installed
system-wide.
Since it's a proper module, you have a file Hello/World/World.pm, too.
This is an ordinary Perl module file. If you want your function to be
exported automatically, you do it there:
@EXPORT = qw(hello);
After doing 'make' again (whenever you change something, do a 'make'),
you call it thusly:
ethan@ethan:~/Projects/Hello/World$ perl -Mblib -MHello::World
hello("world");
__END__
hello, world
ethan@ethan:~/Projects/Hello/World$
In the above command-lines, -Mblib tells perl to use the blib/
directory
as location of the module. blib/ holds the compiled but not yet
installed module.
XS does the same conversions as Inline::C, so the function hello()
could
also be written as:
void
hello(string)
char *string;
PPCODE:
printf("hello, %s\n", string);
Returning values from a function isn't hard either:
char *
hello_concat(string)
char *string;
PREINIT:
char *retstring;
int len;
CODE:
len = strlen(string) + 8;
New(0, retstring, len, char);
memcpy(retstring, "hello, ", 7);
memcpy(retstring + 7, string, strlen(string));
retstring[len] = 0;
RETVAL = retstring;
OUTPUT:
RETVAL
Just as you can pass in Perl types and do the conversion yourself, you
can use the Perl stack explicitely to return a SV. That way, you can
return lists of values by XPUSH()ing them and then telling perl how
many
values you pushed with XSRETURN(num_of_values):
void
hello_stack(string)
char *string;
PREINIT:
SV *retval;
PPCODE:
retval = newSVpv("hello, ", 7);
SvGROW(retval, strlen(string));
sv_catpv(retval, (const char*)string);
/* sv_2mortal() makes the SV mortal:
* that is, it will auto-destroy itself when it goes
* out of scope */
XPUSHs(sv_2mortal(retval));
XSRETURN(1);
I can't much comment on SWIG. From the XS/Inline/SWIG trio I'd say it
is
the worst choice since it's not Perl specific. It may make the first
steps of wrapping a library into a Perl module easier, but you have
better control over what happens when using Inline or XS. If you
ignore
the common myths that Inline is much easier than all the rest, XS is
still the best way of accessing C/C++ from Perl.
The manpages you should read are:
perlxstut /* a tutorial, not complete but helpful nonetheless */
perlguts /* explains the concepts behind the Perl internals */
perlxs
perlcall /* if you call Perl code from your XS */
perlapi
perlapio /* the I/O related PerlAPI */
Tassilo
--
module. I did exactly what he said and it is not working for me.
When I run: perl Makefile.PL && make; I get an error:
Writing Makefile for Hello::World
make: Error -- rem: The system cannot find the file specified.
make: Error code -1
I have no idea what this means and why it occurs.
I also tried Inline C and I get the following error:
Undefined subroutine &main::hello called at ./test_inline.pl line 4.
Can someone please help!
Tassilo's posting:
Another alternative way is using pure XS. Inline::C/C++ are just
wrappers around XS. They look simpler but they aren't really. XS has
the
advantage that development happens in a more standard way: You work on
the .xs file and use another console to do a 'make'. Errors are thus
appearing on your console and not dumped in files in a hidden
directory
(as Inline does it).
When working with XS, you usually have the overhead of creating a real
module. But that's not really a bad thing. You start with h2xs:
ethan@ethan:~/Projects$ h2xs -c -b 5.5.3 -n Hello::World
Writing Hello/World/ppport.h
Writing Hello/World/World.pm
Writing Hello/World/World.xs
Writing Hello/World/Makefile.PL
Writing Hello/World/README
Writing Hello/World/t/1.t
Writing Hello/World/Changes
Writing Hello/World/MANIFEST
This creates a skeletal module with all required files. The -b switch
adds a compatibility layer to your module so that the newer portions
of
the PerlAPI will be made compatible with at least 5.00503 (for this
case).
After that, you add the functionality to Hello/World/World.xs. Right
now
it only contains:
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
MODULE = Hello::World PACKAGE = Hello::World
Adding an XS function that prints its argument as string looks like:
void
hello(string)
SV *string;
PPCODE:
printf("hello, %s\n", SvPV_nolen(string));
You put this below the 'MODULE =' line. Now you go to the other
console
and do a 'perl Makefile.PL && make':
ethan@ethan:~/Projects/Hello/World$ perl Makefile.PL && make
Checking if your kit is complete...
Looks good
Writing Makefile for Hello::World
cp World.pm blib/lib/Hello/World.pm
AutoSplitting blib/lib/Hello/World.pm (blib/lib/auto/Hello/World)
/usr/bin/perl /usr/lib/perl5/5.8.0/ExtUtils/xsubpp -typemap
/usr/lib/perl5/5.8.0/ExtUtils/typemap World.xs > World.xsc && mv
World.xsc World.c
Please specify prototyping behavior for World.xs (see perlxs manual)
cc -c -I. -O3 -march=athlon -fno-strict-aliasing -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64 -O2 -DVERSION=\"0.01\" -DXS_VERSION=\"0.01\"
-fpic "-I/usr/lib/perl5/5.8.0/i686-linux/CORE" World.c
Running Mkbootstrap for Hello::World ()
chmod 644 World.bs
rm -f blib/arch/auto/Hello/World/World.so
LD_RUN_PATH="" cc -shared -L/usr/local/lib World.o -o
blib/arch/auto/Hello/World/World.so
chmod 755 blib/arch/auto/Hello/World/World.so
cp World.bs blib/arch/auto/Hello/World/World.bs
chmod 644 blib/arch/auto/Hello/World/World.bs
Manifying blib/man3/Hello::World.3
And now, you can already call your function without installing the
module:
ethan@ethan:~/Projects/Hello/World$ perl -Mblib -MHello::World
Hello::World::hello("world");
__END__
hello, world
ethan@ethan:~/Projects/Hello/World$
If you do a 'make install' you have this module properly installed
system-wide.
Since it's a proper module, you have a file Hello/World/World.pm, too.
This is an ordinary Perl module file. If you want your function to be
exported automatically, you do it there:
@EXPORT = qw(hello);
After doing 'make' again (whenever you change something, do a 'make'),
you call it thusly:
ethan@ethan:~/Projects/Hello/World$ perl -Mblib -MHello::World
hello("world");
__END__
hello, world
ethan@ethan:~/Projects/Hello/World$
In the above command-lines, -Mblib tells perl to use the blib/
directory
as location of the module. blib/ holds the compiled but not yet
installed module.
XS does the same conversions as Inline::C, so the function hello()
could
also be written as:
void
hello(string)
char *string;
PPCODE:
printf("hello, %s\n", string);
Returning values from a function isn't hard either:
char *
hello_concat(string)
char *string;
PREINIT:
char *retstring;
int len;
CODE:
len = strlen(string) + 8;
New(0, retstring, len, char);
memcpy(retstring, "hello, ", 7);
memcpy(retstring + 7, string, strlen(string));
retstring[len] = 0;
RETVAL = retstring;
OUTPUT:
RETVAL
Just as you can pass in Perl types and do the conversion yourself, you
can use the Perl stack explicitely to return a SV. That way, you can
return lists of values by XPUSH()ing them and then telling perl how
many
values you pushed with XSRETURN(num_of_values):
void
hello_stack(string)
char *string;
PREINIT:
SV *retval;
PPCODE:
retval = newSVpv("hello, ", 7);
SvGROW(retval, strlen(string));
sv_catpv(retval, (const char*)string);
/* sv_2mortal() makes the SV mortal:
* that is, it will auto-destroy itself when it goes
* out of scope */
XPUSHs(sv_2mortal(retval));
XSRETURN(1);
I can't much comment on SWIG. From the XS/Inline/SWIG trio I'd say it
is
the worst choice since it's not Perl specific. It may make the first
steps of wrapping a library into a Perl module easier, but you have
better control over what happens when using Inline or XS. If you
ignore
the common myths that Inline is much easier than all the rest, XS is
still the best way of accessing C/C++ from Perl.
The manpages you should read are:
perlxstut /* a tutorial, not complete but helpful nonetheless */
perlguts /* explains the concepts behind the Perl internals */
perlxs
perlcall /* if you call Perl code from your XS */
perlapi
perlapio /* the I/O related PerlAPI */
Tassilo
--