740 lines
25 KiB
Plaintext
740 lines
25 KiB
Plaintext
|
=head1 NAME
|
||
|
|
||
|
perlXStut - Tutorial for XSUBs
|
||
|
|
||
|
=head1 DESCRIPTION
|
||
|
|
||
|
This tutorial will educate the reader on the steps involved in creating
|
||
|
a Perl extension. The reader is assumed to have access to L<perlguts> and
|
||
|
L<perlxs>.
|
||
|
|
||
|
This tutorial starts with very simple examples and becomes more complex,
|
||
|
with each new example adding new features. Certain concepts may not be
|
||
|
completely explained until later in the tutorial to ease the
|
||
|
reader slowly into building extensions.
|
||
|
|
||
|
=head2 VERSION CAVEAT
|
||
|
|
||
|
This tutorial tries hard to keep up with the latest development versions
|
||
|
of Perl. This often means that it is sometimes in advance of the latest
|
||
|
released version of Perl, and that certain features described here might
|
||
|
not work on earlier versions. This section will keep track of when various
|
||
|
features were added to Perl 5.
|
||
|
|
||
|
=over 4
|
||
|
|
||
|
=item *
|
||
|
|
||
|
In versions of Perl 5.002 prior to the gamma version, the test script
|
||
|
in Example 1 will not function properly. You need to change the "use
|
||
|
lib" line to read:
|
||
|
|
||
|
use lib './blib';
|
||
|
|
||
|
=item *
|
||
|
|
||
|
In versions of Perl 5.002 prior to version beta 3, the line in the .xs file
|
||
|
about "PROTOTYPES: DISABLE" will cause a compiler error. Simply remove that
|
||
|
line from the file.
|
||
|
|
||
|
=item *
|
||
|
|
||
|
In versions of Perl 5.002 prior to version 5.002b1h, the test.pl file was not
|
||
|
automatically created by h2xs. This means that you cannot say "make test"
|
||
|
to run the test script. You will need to add the following line before the
|
||
|
"use extension" statement:
|
||
|
|
||
|
use lib './blib';
|
||
|
|
||
|
=item *
|
||
|
|
||
|
In versions 5.000 and 5.001, instead of using the above line, you will need
|
||
|
to use the following line:
|
||
|
|
||
|
BEGIN { unshift(@INC, "./blib") }
|
||
|
|
||
|
=item *
|
||
|
|
||
|
This document assumes that the executable named "perl" is Perl version 5.
|
||
|
Some systems may have installed Perl version 5 as "perl5".
|
||
|
|
||
|
=back
|
||
|
|
||
|
=head2 DYNAMIC VERSUS STATIC
|
||
|
|
||
|
It is commonly thought that if a system does not have the capability to
|
||
|
load a library dynamically, you cannot build XSUBs. This is incorrect.
|
||
|
You I<can> build them, but you must link the XSUB's subroutines with the
|
||
|
rest of Perl, creating a new executable. This situation is similar to
|
||
|
Perl 4.
|
||
|
|
||
|
This tutorial can still be used on such a system. The XSUB build mechanism
|
||
|
will check the system and build a dynamically-loadable library if possible,
|
||
|
or else a static library and then, optionally, a new statically-linked
|
||
|
executable with that static library linked in.
|
||
|
|
||
|
Should you wish to build a statically-linked executable on a system which
|
||
|
can dynamically load libraries, you may, in all the following examples,
|
||
|
where the command "make" with no arguments is executed, run the command
|
||
|
"make perl" instead.
|
||
|
|
||
|
If you have generated such a statically-linked executable by choice, then
|
||
|
instead of saying "make test", you should say "make test_static". On systems
|
||
|
that cannot build dynamically-loadable libraries at all, simply saying "make
|
||
|
test" is sufficient.
|
||
|
|
||
|
=head2 EXAMPLE 1
|
||
|
|
||
|
Our first extension will be very simple. When we call the routine in the
|
||
|
extension, it will print out a well-known message and return.
|
||
|
|
||
|
Run C<h2xs -A -n Mytest>. This creates a directory named Mytest, possibly under
|
||
|
ext/ if that directory exists in the current working directory. Several files
|
||
|
will be created in the Mytest dir, including MANIFEST, Makefile.PL, Mytest.pm,
|
||
|
Mytest.xs, test.pl, and Changes.
|
||
|
|
||
|
The MANIFEST file contains the names of all the files created.
|
||
|
|
||
|
The file Makefile.PL should look something like this:
|
||
|
|
||
|
use ExtUtils::MakeMaker;
|
||
|
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
|
||
|
# the contents of the Makefile that is written.
|
||
|
WriteMakefile(
|
||
|
'NAME' => 'Mytest',
|
||
|
'VERSION_FROM' => 'Mytest.pm', # finds $VERSION
|
||
|
'LIBS' => [''], # e.g., '-lm'
|
||
|
'DEFINE' => '', # e.g., '-DHAVE_SOMETHING'
|
||
|
'INC' => '', # e.g., '-I/usr/include/other'
|
||
|
);
|
||
|
|
||
|
The file Mytest.pm should start with something like this:
|
||
|
|
||
|
package Mytest;
|
||
|
|
||
|
require Exporter;
|
||
|
require DynaLoader;
|
||
|
|
||
|
@ISA = qw(Exporter DynaLoader);
|
||
|
# Items to export into callers namespace by default. Note: do not export
|
||
|
# names by default without a very good reason. Use EXPORT_OK instead.
|
||
|
# Do not simply export all your public functions/methods/constants.
|
||
|
@EXPORT = qw(
|
||
|
|
||
|
);
|
||
|
$VERSION = '0.01';
|
||
|
|
||
|
bootstrap Mytest $VERSION;
|
||
|
|
||
|
# Preloaded methods go here.
|
||
|
|
||
|
# Autoload methods go after __END__, and are processed by the autosplit program.
|
||
|
|
||
|
1;
|
||
|
__END__
|
||
|
# Below is the stub of documentation for your module. You better edit it!
|
||
|
|
||
|
And the Mytest.xs file should look something like this:
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
extern "C" {
|
||
|
#endif
|
||
|
#include "EXTERN.h"
|
||
|
#include "perl.h"
|
||
|
#include "XSUB.h"
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
PROTOTYPES: DISABLE
|
||
|
|
||
|
MODULE = Mytest PACKAGE = Mytest
|
||
|
|
||
|
Let's edit the .xs file by adding this to the end of the file:
|
||
|
|
||
|
void
|
||
|
hello()
|
||
|
CODE:
|
||
|
printf("Hello, world!\n");
|
||
|
|
||
|
Now we'll run "perl Makefile.PL". This will create a real Makefile,
|
||
|
which make needs. Its output looks something like:
|
||
|
|
||
|
% perl Makefile.PL
|
||
|
Checking if your kit is complete...
|
||
|
Looks good
|
||
|
Writing Makefile for Mytest
|
||
|
%
|
||
|
|
||
|
Now, running make will produce output that looks something like this
|
||
|
(some long lines shortened for clarity):
|
||
|
|
||
|
% make
|
||
|
umask 0 && cp Mytest.pm ./blib/Mytest.pm
|
||
|
perl xsubpp -typemap typemap Mytest.xs >Mytest.tc && mv Mytest.tc Mytest.c
|
||
|
cc -c Mytest.c
|
||
|
Running Mkbootstrap for Mytest ()
|
||
|
chmod 644 Mytest.bs
|
||
|
LD_RUN_PATH="" ld -o ./blib/PA-RISC1.1/auto/Mytest/Mytest.sl -b Mytest.o
|
||
|
chmod 755 ./blib/PA-RISC1.1/auto/Mytest/Mytest.sl
|
||
|
cp Mytest.bs ./blib/PA-RISC1.1/auto/Mytest/Mytest.bs
|
||
|
chmod 644 ./blib/PA-RISC1.1/auto/Mytest/Mytest.bs
|
||
|
|
||
|
Now, although there is already a test.pl template ready for us, for this
|
||
|
example only, we'll create a special test script. Create a file called hello
|
||
|
that looks like this:
|
||
|
|
||
|
#! /opt/perl5/bin/perl
|
||
|
|
||
|
use ExtUtils::testlib;
|
||
|
|
||
|
use Mytest;
|
||
|
|
||
|
Mytest::hello();
|
||
|
|
||
|
Now we run the script and we should see the following output:
|
||
|
|
||
|
% perl hello
|
||
|
Hello, world!
|
||
|
%
|
||
|
|
||
|
=head2 EXAMPLE 2
|
||
|
|
||
|
Now let's add to our extension a subroutine that will take a single argument
|
||
|
and return 1 if the argument is even, 0 if the argument is odd.
|
||
|
|
||
|
Add the following to the end of Mytest.xs:
|
||
|
|
||
|
int
|
||
|
is_even(input)
|
||
|
int input
|
||
|
CODE:
|
||
|
RETVAL = (input % 2 == 0);
|
||
|
OUTPUT:
|
||
|
RETVAL
|
||
|
|
||
|
There does not need to be white space at the start of the "int input" line,
|
||
|
but it is useful for improving readability. The semi-colon at the end of
|
||
|
that line is also optional.
|
||
|
|
||
|
Any white space may be between the "int" and "input". It is also okay for
|
||
|
the four lines starting at the "CODE:" line to not be indented. However,
|
||
|
for readability purposes, it is suggested that you indent them 8 spaces
|
||
|
(or one normal tab stop).
|
||
|
|
||
|
Now rerun make to rebuild our new shared library.
|
||
|
|
||
|
Now perform the same steps as before, generating a Makefile from the
|
||
|
Makefile.PL file, and running make.
|
||
|
|
||
|
To test that our extension works, we now need to look at the
|
||
|
file test.pl. This file is set up to imitate the same kind of testing
|
||
|
structure that Perl itself has. Within the test script, you perform a
|
||
|
number of tests to confirm the behavior of the extension, printing "ok"
|
||
|
when the test is correct, "not ok" when it is not. Change the print
|
||
|
statement in the BEGIN block to print "1..4", and add the following code
|
||
|
to the end of the file:
|
||
|
|
||
|
print &Mytest::is_even(0) == 1 ? "ok 2" : "not ok 2", "\n";
|
||
|
print &Mytest::is_even(1) == 0 ? "ok 3" : "not ok 3", "\n";
|
||
|
print &Mytest::is_even(2) == 1 ? "ok 4" : "not ok 4", "\n";
|
||
|
|
||
|
We will be calling the test script through the command "make test". You
|
||
|
should see output that looks something like this:
|
||
|
|
||
|
% make test
|
||
|
PERL_DL_NONLAZY=1 /opt/perl5.002b2/bin/perl (lots of -I arguments) test.pl
|
||
|
1..4
|
||
|
ok 1
|
||
|
ok 2
|
||
|
ok 3
|
||
|
ok 4
|
||
|
%
|
||
|
|
||
|
=head2 WHAT HAS GONE ON?
|
||
|
|
||
|
The program h2xs is the starting point for creating extensions. In later
|
||
|
examples we'll see how we can use h2xs to read header files and generate
|
||
|
templates to connect to C routines.
|
||
|
|
||
|
h2xs creates a number of files in the extension directory. The file
|
||
|
Makefile.PL is a perl script which will generate a true Makefile to build
|
||
|
the extension. We'll take a closer look at it later.
|
||
|
|
||
|
The files E<lt>extensionE<gt>.pm and E<lt>extensionE<gt>.xs contain the meat
|
||
|
of the extension.
|
||
|
The .xs file holds the C routines that make up the extension. The .pm file
|
||
|
contains routines that tell Perl how to load your extension.
|
||
|
|
||
|
Generating and invoking the Makefile created a directory blib (which stands
|
||
|
for "build library") in the current working directory. This directory will
|
||
|
contain the shared library that we will build. Once we have tested it, we
|
||
|
can install it into its final location.
|
||
|
|
||
|
Invoking the test script via "make test" did something very important. It
|
||
|
invoked perl with all those C<-I> arguments so that it could find the various
|
||
|
files that are part of the extension.
|
||
|
|
||
|
It is I<very> important that while you are still testing extensions that
|
||
|
you use "make test". If you try to run the test script all by itself, you
|
||
|
will get a fatal error.
|
||
|
|
||
|
Another reason it is important to use "make test" to run your test script
|
||
|
is that if you are testing an upgrade to an already-existing version, using
|
||
|
"make test" insures that you use your new extension, not the already-existing
|
||
|
version.
|
||
|
|
||
|
When Perl sees a C<use extension;>, it searches for a file with the same name
|
||
|
as the use'd extension that has a .pm suffix. If that file cannot be found,
|
||
|
Perl dies with a fatal error. The default search path is contained in the
|
||
|
@INC array.
|
||
|
|
||
|
In our case, Mytest.pm tells perl that it will need the Exporter and Dynamic
|
||
|
Loader extensions. It then sets the @ISA and @EXPORT arrays and the $VERSION
|
||
|
scalar; finally it tells perl to bootstrap the module. Perl will call its
|
||
|
dynamic loader routine (if there is one) and load the shared library.
|
||
|
|
||
|
The two arrays that are set in the .pm file are very important. The @ISA
|
||
|
array contains a list of other packages in which to search for methods (or
|
||
|
subroutines) that do not exist in the current package. The @EXPORT array
|
||
|
tells Perl which of the extension's routines should be placed into the
|
||
|
calling package's namespace.
|
||
|
|
||
|
It's important to select what to export carefully. Do NOT export method names
|
||
|
and do NOT export anything else I<by default> without a good reason.
|
||
|
|
||
|
As a general rule, if the module is trying to be object-oriented then don't
|
||
|
export anything. If it's just a collection of functions then you can export
|
||
|
any of the functions via another array, called @EXPORT_OK.
|
||
|
|
||
|
See L<perlmod> for more information.
|
||
|
|
||
|
The $VERSION variable is used to ensure that the .pm file and the shared
|
||
|
library are "in sync" with each other. Any time you make changes to
|
||
|
the .pm or .xs files, you should increment the value of this variable.
|
||
|
|
||
|
=head2 WRITING GOOD TEST SCRIPTS
|
||
|
|
||
|
The importance of writing good test scripts cannot be overemphasized. You
|
||
|
should closely follow the "ok/not ok" style that Perl itself uses, so that
|
||
|
it is very easy and unambiguous to determine the outcome of each test case.
|
||
|
When you find and fix a bug, make sure you add a test case for it.
|
||
|
|
||
|
By running "make test", you ensure that your test.pl script runs and uses
|
||
|
the correct version of your extension. If you have many test cases, you
|
||
|
might want to copy Perl's test style. Create a directory named "t", and
|
||
|
ensure all your test files end with the suffix ".t". The Makefile will
|
||
|
properly run all these test files.
|
||
|
|
||
|
|
||
|
=head2 EXAMPLE 3
|
||
|
|
||
|
Our third extension will take one argument as its input, round off that
|
||
|
value, and set the I<argument> to the rounded value.
|
||
|
|
||
|
Add the following to the end of Mytest.xs:
|
||
|
|
||
|
void
|
||
|
round(arg)
|
||
|
double arg
|
||
|
CODE:
|
||
|
if (arg > 0.0) {
|
||
|
arg = floor(arg + 0.5);
|
||
|
} else if (arg < 0.0) {
|
||
|
arg = ceil(arg - 0.5);
|
||
|
} else {
|
||
|
arg = 0.0;
|
||
|
}
|
||
|
OUTPUT:
|
||
|
arg
|
||
|
|
||
|
Edit the Makefile.PL file so that the corresponding line looks like this:
|
||
|
|
||
|
'LIBS' => ['-lm'], # e.g., '-lm'
|
||
|
|
||
|
Generate the Makefile and run make. Change the BEGIN block to print out
|
||
|
"1..9" and add the following to test.pl:
|
||
|
|
||
|
$i = -1.5; &Mytest::round($i); print $i == -2.0 ? "ok 5" : "not ok 5", "\n";
|
||
|
$i = -1.1; &Mytest::round($i); print $i == -1.0 ? "ok 6" : "not ok 6", "\n";
|
||
|
$i = 0.0; &Mytest::round($i); print $i == 0.0 ? "ok 7" : "not ok 7", "\n";
|
||
|
$i = 0.5; &Mytest::round($i); print $i == 1.0 ? "ok 8" : "not ok 8", "\n";
|
||
|
$i = 1.2; &Mytest::round($i); print $i == 1.0 ? "ok 9" : "not ok 9", "\n";
|
||
|
|
||
|
Running "make test" should now print out that all nine tests are okay.
|
||
|
|
||
|
You might be wondering if you can round a constant. To see what happens, add
|
||
|
the following line to test.pl temporarily:
|
||
|
|
||
|
&Mytest::round(3);
|
||
|
|
||
|
Run "make test" and notice that Perl dies with a fatal error. Perl won't let
|
||
|
you change the value of constants!
|
||
|
|
||
|
=head2 WHAT'S NEW HERE?
|
||
|
|
||
|
Two things are new here. First, we've made some changes to Makefile.PL.
|
||
|
In this case, we've specified an extra library to link in, the math library
|
||
|
libm. We'll talk later about how to write XSUBs that can call every routine
|
||
|
in a library.
|
||
|
|
||
|
Second, the value of the function is being passed back not as the function's
|
||
|
return value, but through the same variable that was passed into the function.
|
||
|
|
||
|
=head2 INPUT AND OUTPUT PARAMETERS
|
||
|
|
||
|
You specify the parameters that will be passed into the XSUB just after you
|
||
|
declare the function return value and name. Each parameter line starts with
|
||
|
optional white space, and may have an optional terminating semicolon.
|
||
|
|
||
|
The list of output parameters occurs after the OUTPUT: directive. The use
|
||
|
of RETVAL tells Perl that you wish to send this value back as the return
|
||
|
value of the XSUB function. In Example 3, the value we wanted returned was
|
||
|
contained in the same variable we passed in, so we listed it (and not RETVAL)
|
||
|
in the OUTPUT: section.
|
||
|
|
||
|
=head2 THE XSUBPP COMPILER
|
||
|
|
||
|
The compiler xsubpp takes the XS code in the .xs file and converts it into
|
||
|
C code, placing it in a file whose suffix is .c. The C code created makes
|
||
|
heavy use of the C functions within Perl.
|
||
|
|
||
|
=head2 THE TYPEMAP FILE
|
||
|
|
||
|
The xsubpp compiler uses rules to convert from Perl's data types (scalar,
|
||
|
array, etc.) to C's data types (int, char *, etc.). These rules are stored
|
||
|
in the typemap file ($PERLLIB/ExtUtils/typemap). This file is split into
|
||
|
three parts.
|
||
|
|
||
|
The first part attempts to map various C data types to a coded flag, which
|
||
|
has some correspondence with the various Perl types. The second part contains
|
||
|
C code which xsubpp uses for input parameters. The third part contains C
|
||
|
code which xsubpp uses for output parameters. We'll talk more about the
|
||
|
C code later.
|
||
|
|
||
|
Let's now take a look at a portion of the .c file created for our extension.
|
||
|
|
||
|
XS(XS_Mytest_round)
|
||
|
{
|
||
|
dXSARGS;
|
||
|
if (items != 1)
|
||
|
croak("Usage: Mytest::round(arg)");
|
||
|
{
|
||
|
double arg = (double)SvNV(ST(0)); /* XXXXX */
|
||
|
if (arg > 0.0) {
|
||
|
arg = floor(arg + 0.5);
|
||
|
} else if (arg < 0.0) {
|
||
|
arg = ceil(arg - 0.5);
|
||
|
} else {
|
||
|
arg = 0.0;
|
||
|
}
|
||
|
sv_setnv(ST(0), (double)arg); /* XXXXX */
|
||
|
}
|
||
|
XSRETURN(1);
|
||
|
}
|
||
|
|
||
|
Notice the two lines marked with "XXXXX". If you check the first section of
|
||
|
the typemap file, you'll see that doubles are of type T_DOUBLE. In the
|
||
|
INPUT section, an argument that is T_DOUBLE is assigned to the variable
|
||
|
arg by calling the routine SvNV on something, then casting it to double,
|
||
|
then assigned to the variable arg. Similarly, in the OUTPUT section,
|
||
|
once arg has its final value, it is passed to the sv_setnv function to
|
||
|
be passed back to the calling subroutine. These two functions are explained
|
||
|
in L<perlguts>; we'll talk more later about what that "ST(0)" means in the
|
||
|
section on the argument stack.
|
||
|
|
||
|
=head2 WARNING
|
||
|
|
||
|
In general, it's not a good idea to write extensions that modify their input
|
||
|
parameters, as in Example 3. However, to accommodate better calling
|
||
|
pre-existing C routines, which often do modify their input parameters,
|
||
|
this behavior is tolerated. The next example will show how to do this.
|
||
|
|
||
|
=head2 EXAMPLE 4
|
||
|
|
||
|
In this example, we'll now begin to write XSUBs that will interact with
|
||
|
predefined C libraries. To begin with, we will build a small library of
|
||
|
our own, then let h2xs write our .pm and .xs files for us.
|
||
|
|
||
|
Create a new directory called Mytest2 at the same level as the directory
|
||
|
Mytest. In the Mytest2 directory, create another directory called mylib,
|
||
|
and cd into that directory.
|
||
|
|
||
|
Here we'll create some files that will generate a test library. These will
|
||
|
include a C source file and a header file. We'll also create a Makefile.PL
|
||
|
in this directory. Then we'll make sure that running make at the Mytest2
|
||
|
level will automatically run this Makefile.PL file and the resulting Makefile.
|
||
|
|
||
|
In the mylib directory, create a file mylib.h that looks like this:
|
||
|
|
||
|
#define TESTVAL 4
|
||
|
|
||
|
extern double foo(int, long, const char*);
|
||
|
|
||
|
Also create a file mylib.c that looks like this:
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include "./mylib.h"
|
||
|
|
||
|
double
|
||
|
foo(a, b, c)
|
||
|
int a;
|
||
|
long b;
|
||
|
const char * c;
|
||
|
{
|
||
|
return (a + b + atof(c) + TESTVAL);
|
||
|
}
|
||
|
|
||
|
And finally create a file Makefile.PL that looks like this:
|
||
|
|
||
|
use ExtUtils::MakeMaker;
|
||
|
$Verbose = 1;
|
||
|
WriteMakefile(
|
||
|
NAME => 'Mytest2::mylib',
|
||
|
SKIP => [qw(all static static_lib dynamic dynamic_lib)],
|
||
|
clean => {'FILES' => 'libmylib$(LIB_EXT)'},
|
||
|
);
|
||
|
|
||
|
|
||
|
sub MY::top_targets {
|
||
|
'
|
||
|
all :: static
|
||
|
|
||
|
static :: libmylib$(LIB_EXT)
|
||
|
|
||
|
libmylib$(LIB_EXT): $(O_FILES)
|
||
|
$(AR) cr libmylib$(LIB_EXT) $(O_FILES)
|
||
|
$(RANLIB) libmylib$(LIB_EXT)
|
||
|
|
||
|
';
|
||
|
}
|
||
|
|
||
|
We will now create the main top-level Mytest2 files. Change to the directory
|
||
|
above Mytest2 and run the following command:
|
||
|
|
||
|
% h2xs -O -n Mytest2 ./Mytest2/mylib/mylib.h
|
||
|
|
||
|
This will print out a warning about overwriting Mytest2, but that's okay.
|
||
|
Our files are stored in Mytest2/mylib, and will be untouched.
|
||
|
|
||
|
The normal Makefile.PL that h2xs generates doesn't know about the mylib
|
||
|
directory. We need to tell it that there is a subdirectory and that we
|
||
|
will be generating a library in it. Let's add the following key-value
|
||
|
pair to the WriteMakefile call:
|
||
|
|
||
|
'MYEXTLIB' => 'mylib/libmylib$(LIB_EXT)',
|
||
|
|
||
|
and a new replacement subroutine too:
|
||
|
|
||
|
sub MY::postamble {
|
||
|
'
|
||
|
$(MYEXTLIB): mylib/Makefile
|
||
|
cd mylib && $(MAKE) $(PASTHRU)
|
||
|
';
|
||
|
}
|
||
|
|
||
|
(Note: Most makes will require that there be a tab character that indents
|
||
|
the line C<cd mylib && $(MAKE) $(PASTHRU)>, similarly for the Makefile in the
|
||
|
subdirectory.)
|
||
|
|
||
|
Let's also fix the MANIFEST file so that it accurately reflects the contents
|
||
|
of our extension. The single line that says "mylib" should be replaced by
|
||
|
the following three lines:
|
||
|
|
||
|
mylib/Makefile.PL
|
||
|
mylib/mylib.c
|
||
|
mylib/mylib.h
|
||
|
|
||
|
To keep our namespace nice and unpolluted, edit the .pm file and change
|
||
|
the lines setting @EXPORT to @EXPORT_OK (there are two: one in the line
|
||
|
beginning "use vars" and one setting the array itself). Finally, in the
|
||
|
.xs file, edit the #include line to read:
|
||
|
|
||
|
#include "mylib/mylib.h"
|
||
|
|
||
|
And also add the following function definition to the end of the .xs file:
|
||
|
|
||
|
double
|
||
|
foo(a,b,c)
|
||
|
int a
|
||
|
long b
|
||
|
const char * c
|
||
|
OUTPUT:
|
||
|
RETVAL
|
||
|
|
||
|
Now we also need to create a typemap file because the default Perl doesn't
|
||
|
currently support the const char * type. Create a file called typemap and
|
||
|
place the following in it:
|
||
|
|
||
|
const char * T_PV
|
||
|
|
||
|
Now run perl on the top-level Makefile.PL. Notice that it also created a
|
||
|
Makefile in the mylib directory. Run make and see that it does cd into
|
||
|
the mylib directory and run make in there as well.
|
||
|
|
||
|
Now edit the test.pl script and change the BEGIN block to print "1..4",
|
||
|
and add the following lines to the end of the script:
|
||
|
|
||
|
print &Mytest2::foo(1, 2, "Hello, world!") == 7 ? "ok 2\n" : "not ok 2\n";
|
||
|
print &Mytest2::foo(1, 2, "0.0") == 7 ? "ok 3\n" : "not ok 3\n";
|
||
|
print abs(&Mytest2::foo(0, 0, "-3.4") - 0.6) <= 0.01 ? "ok 4\n" : "not ok 4\n";
|
||
|
|
||
|
(When dealing with floating-point comparisons, it is often useful not to check
|
||
|
for equality, but rather the difference being below a certain epsilon factor,
|
||
|
0.01 in this case)
|
||
|
|
||
|
Run "make test" and all should be well.
|
||
|
|
||
|
=head2 WHAT HAS HAPPENED HERE?
|
||
|
|
||
|
Unlike previous examples, we've now run h2xs on a real include file. This
|
||
|
has caused some extra goodies to appear in both the .pm and .xs files.
|
||
|
|
||
|
=over 4
|
||
|
|
||
|
=item *
|
||
|
|
||
|
In the .xs file, there's now a #include declaration with the full path to
|
||
|
the mylib.h header file.
|
||
|
|
||
|
=item *
|
||
|
|
||
|
There's now some new C code that's been added to the .xs file. The purpose
|
||
|
of the C<constant> routine is to make the values that are #define'd in the
|
||
|
header file available to the Perl script (in this case, by calling
|
||
|
C<&main::TESTVAL>). There's also some XS code to allow calls to the
|
||
|
C<constant> routine.
|
||
|
|
||
|
=item *
|
||
|
|
||
|
The .pm file has exported the name TESTVAL in the @EXPORT array. This
|
||
|
could lead to name clashes. A good rule of thumb is that if the #define
|
||
|
is going to be used by only the C routines themselves, and not by the user,
|
||
|
they should be removed from the @EXPORT array. Alternately, if you don't
|
||
|
mind using the "fully qualified name" of a variable, you could remove most
|
||
|
or all of the items in the @EXPORT array.
|
||
|
|
||
|
=item *
|
||
|
|
||
|
If our include file contained #include directives, these would not be
|
||
|
processed at all by h2xs. There is no good solution to this right now.
|
||
|
|
||
|
=back
|
||
|
|
||
|
We've also told Perl about the library that we built in the mylib
|
||
|
subdirectory. That required the addition of only the MYEXTLIB variable
|
||
|
to the WriteMakefile call and the replacement of the postamble subroutine
|
||
|
to cd into the subdirectory and run make. The Makefile.PL for the
|
||
|
library is a bit more complicated, but not excessively so. Again we
|
||
|
replaced the postamble subroutine to insert our own code. This code
|
||
|
specified simply that the library to be created here was a static
|
||
|
archive (as opposed to a dynamically loadable library) and provided the
|
||
|
commands to build it.
|
||
|
|
||
|
=head2 SPECIFYING ARGUMENTS TO XSUBPP
|
||
|
|
||
|
With the completion of Example 4, we now have an easy way to simulate some
|
||
|
real-life libraries whose interfaces may not be the cleanest in the world.
|
||
|
We shall now continue with a discussion of the arguments passed to the
|
||
|
xsubpp compiler.
|
||
|
|
||
|
When you specify arguments in the .xs file, you are really passing three
|
||
|
pieces of information for each one listed. The first piece is the order
|
||
|
of that argument relative to the others (first, second, etc). The second
|
||
|
is the type of argument, and consists of the type declaration of the
|
||
|
argument (e.g., int, char*, etc). The third piece is the exact way in
|
||
|
which the argument should be used in the call to the library function
|
||
|
from this XSUB. This would mean whether or not to place a "&" before
|
||
|
the argument or not, meaning the argument expects to be passed the address
|
||
|
of the specified data type.
|
||
|
|
||
|
There is a difference between the two arguments in this hypothetical function:
|
||
|
|
||
|
int
|
||
|
foo(a,b)
|
||
|
char &a
|
||
|
char * b
|
||
|
|
||
|
The first argument to this function would be treated as a char and assigned
|
||
|
to the variable a, and its address would be passed into the function foo.
|
||
|
The second argument would be treated as a string pointer and assigned to the
|
||
|
variable b. The I<value> of b would be passed into the function foo. The
|
||
|
actual call to the function foo that xsubpp generates would look like this:
|
||
|
|
||
|
foo(&a, b);
|
||
|
|
||
|
Xsubpp will identically parse the following function argument lists:
|
||
|
|
||
|
char &a
|
||
|
char&a
|
||
|
char & a
|
||
|
|
||
|
However, to help ease understanding, it is suggested that you place a "&"
|
||
|
next to the variable name and away from the variable type), and place a
|
||
|
"*" near the variable type, but away from the variable name (as in the
|
||
|
complete example above). By doing so, it is easy to understand exactly
|
||
|
what will be passed to the C function -- it will be whatever is in the
|
||
|
"last column".
|
||
|
|
||
|
You should take great pains to try to pass the function the type of variable
|
||
|
it wants, when possible. It will save you a lot of trouble in the long run.
|
||
|
|
||
|
=head2 THE ARGUMENT STACK
|
||
|
|
||
|
If we look at any of the C code generated by any of the examples except
|
||
|
example 1, you will notice a number of references to ST(n), where n is
|
||
|
usually 0. The "ST" is actually a macro that points to the n'th argument
|
||
|
on the argument stack. ST(0) is thus the first argument passed to the
|
||
|
XSUB, ST(1) is the second argument, and so on.
|
||
|
|
||
|
When you list the arguments to the XSUB in the .xs file, that tells xsubpp
|
||
|
which argument corresponds to which of the argument stack (i.e., the first
|
||
|
one listed is the first argument, and so on). You invite disaster if you
|
||
|
do not list them in the same order as the function expects them.
|
||
|
|
||
|
=head2 EXTENDING YOUR EXTENSION
|
||
|
|
||
|
Sometimes you might want to provide some extra methods or subroutines
|
||
|
to assist in making the interface between Perl and your extension simpler
|
||
|
or easier to understand. These routines should live in the .pm file.
|
||
|
Whether they are automatically loaded when the extension itself is loaded
|
||
|
or loaded only when called depends on where in the .pm file the subroutine
|
||
|
definition is placed.
|
||
|
|
||
|
=head2 DOCUMENTING YOUR EXTENSION
|
||
|
|
||
|
There is absolutely no excuse for not documenting your extension.
|
||
|
Documentation belongs in the .pm file. This file will be fed to pod2man,
|
||
|
and the embedded documentation will be converted to the manpage format,
|
||
|
then placed in the blib directory. It will be copied to Perl's man
|
||
|
page directory when the extension is installed.
|
||
|
|
||
|
You may intersperse documentation and Perl code within the .pm file.
|
||
|
In fact, if you want to use method autoloading, you must do this,
|
||
|
as the comment inside the .pm file explains.
|
||
|
|
||
|
See L<perlpod> for more information about the pod format.
|
||
|
|
||
|
=head2 INSTALLING YOUR EXTENSION
|
||
|
|
||
|
Once your extension is complete and passes all its tests, installing it
|
||
|
is quite simple: you simply run "make install". You will either need
|
||
|
to have write permission into the directories where Perl is installed,
|
||
|
or ask your system administrator to run the make for you.
|
||
|
|
||
|
=head2 SEE ALSO
|
||
|
|
||
|
For more information, consult L<perlguts>, L<perlxs>, L<perlmod>,
|
||
|
and L<perlpod>.
|
||
|
|
||
|
=head2 Author
|
||
|
|
||
|
Jeff Okamoto <F<okamoto@corp.hp.com>>
|
||
|
|
||
|
Reviewed and assisted by Dean Roehrich, Ilya Zakharevich, Andreas Koenig,
|
||
|
and Tim Bunce.
|
||
|
|
||
|
=head2 Last Changed
|
||
|
|
||
|
1996/7/10
|