diff options
Diffstat (limited to 'contrib/perl5/pod/perlxstut.pod')
-rw-r--r-- | contrib/perl5/pod/perlxstut.pod | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/contrib/perl5/pod/perlxstut.pod b/contrib/perl5/pod/perlxstut.pod new file mode 100644 index 0000000..867d42a --- /dev/null +++ b/contrib/perl5/pod/perlxstut.pod @@ -0,0 +1,739 @@ +=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 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', + 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 |