home *** CD-ROM | disk | FTP | other *** search
- NAME
- perlXStut - Tutorial for XSUB's
-
- DESCRIPTION
- This tutorial will educate the reader on the steps
- involved in creating a Perl extension. The reader is
- assumed to have access to the perlguts manpage and the
- perlxs manpage.
-
- 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 in order to slowly ease the reader
- into building extensions.
-
- 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.
-
- o In versions of 5.002 prior to version beta 3, then the
- line in the .xs file about "PROTOTYPES: DISABLE" will
- cause a compiler error. Simply remove that line from
- the file.
-
- o In versions of 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';
-
- o 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") }
-
- o This document assumes that the executable named "perl"
- is Perl version 5. Some systems may have installed
- Perl version 5 as "perl5".
-
- DYNAMIC VERSUS STATIC
-
- It is commonly thought that if a system does not have the
- capability to dynamically load a library, you cannot build
- XSUB's. This is incorrect. You 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.
-
- 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 "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. It's 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 lib './blib';
-
- use Mytest;
-
- Mytest::hello();
-
- Now we run the script and we should see the following
- output:
-
- % perl hello
- Hello, world!
- %
-
- EXAMPLE 2
-
- Now let's add to our extension a subroutine that will take
- a single argument and return 0 if the argument is even, 1
- 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 re-run 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.
-
- In order 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.
-
- Remove the line that starts with "use lib", 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
- %
-
- 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 <extension>.pm and <extension>.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 -I
- arguments so that it could find the various files that are
- part of the extension.
-
- It is 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 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 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 the perlmod manpage 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.
-
- 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.
-
- EXAMPLE 3
-
- Our third extension will take one argument as its input,
- round off that value, and set the 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!
-
- 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, in this case 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.
-
- 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.
-
- 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.
-
- 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
- the perlguts manpage; we'll talk more later about what
- that "ST(0)" means in the section on the argument stack.
-
- WARNING
-
- In general, it's not a good idea to write extensions that
- modify their input parameters, as in Example 3. However,
- in order to better accomodate calling pre-existing C
- routines, which often do modify their input parameters,
- this behavior is tolerated.
-
- EXAMPLE 4
-
- In this example, we'll now begin to write XSUB's that will
- interact with pre-defined 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 testlib 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',
- 'clean' => {'FILES' => 'libmylib.a'},
- );
-
- sub MY::postamble {
- '
- 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)
- ';
- }
-
- (Note: Most makes will require that there be a tab
- character that indents the line "cd mylib && $(MAKE)".)
-
- 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 line setting @EXPORT to @EXPORT_OK.
- And 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 to not 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. 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.
-
- o
- In the .xs file, there's now a #include declaration with
- the full path to the mylib.h header file.
-
- o
- There's now some new C code that's been added to the .xs
- file. The purpose of the 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 &main::TESTVAL).
- There's also some XS code to allow calls to the constant
- routine.
-
- o
- 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 only going to be used by
- 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.
-
- We've also told Perl about the library that we built in
- the mylib subdirectory. That required only the addition
- of 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 simply specified 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.
-
- 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 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.
-
- 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 tell 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.
-
- 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 only loaded when called depends on where in the .pm
- file the subroutine definition is placed.
-
- 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 man page 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 the perlpod manpage for more information about the pod
- format.
-
- 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.
-
- SEE ALSO
-
- For more information, consult the perlguts manpage, the
- perlxs manpage, the perlmod manpage, and the perlpod
- manpage.
-
- Author
-
- Jeff Okamoto <okamoto@corp.hp.com>
-
- Reviewed and assisted by Dean Roehrich, Ilya Zakharevich,
- Andreas Koenig, and Tim Bunce.
-
- Last Changed
-
- 1996/2/9
-