diff options
Diffstat (limited to 'upstream/archlinux/man1/perlxstut.1perl')
-rw-r--r-- | upstream/archlinux/man1/perlxstut.1perl | 1499 |
1 files changed, 1499 insertions, 0 deletions
diff --git a/upstream/archlinux/man1/perlxstut.1perl b/upstream/archlinux/man1/perlxstut.1perl new file mode 100644 index 00000000..8ce84046 --- /dev/null +++ b/upstream/archlinux/man1/perlxstut.1perl @@ -0,0 +1,1499 @@ +.\" -*- mode: troff; coding: utf-8 -*- +.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. +.ie n \{\ +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{\ +. if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" ======================================================================== +.\" +.IX Title "PERLXSTUT 1perl" +.TH PERLXSTUT 1perl 2024-02-11 "perl v5.38.2" "Perl Programmers Reference Guide" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH NAME +perlxstut \- Tutorial for writing XSUBs +.SH DESCRIPTION +.IX Header "DESCRIPTION" +This tutorial will educate the reader on the steps involved in creating +a Perl extension. The reader is assumed to have access to perlguts, +perlapi and perlxs. +.PP +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. +.PP +This tutorial was written from a Unix point of view. Where I know them +to be otherwise different for other platforms (e.g. Win32), I will list +them. If you find something that was missed, please let me know. +.SH "SPECIAL NOTES" +.IX Header "SPECIAL NOTES" +.SS make +.IX Subsection "make" +This tutorial assumes that the make program that Perl is configured to +use is called \f(CW\*(C`make\*(C'\fR. Instead of running "make" in the examples that +follow, you may have to substitute whatever make program Perl has been +configured to use. Running \fBperl \-V:make\fR should tell you what it is. +.SS "Version caveat" +.IX Subsection "Version caveat" +When writing a Perl extension for general consumption, one should expect that +the extension will be used with versions of Perl different from the +version available on your machine. Since you are reading this document, +the version of Perl on your machine is probably 5.005 or later, but the users +of your extension may have more ancient versions. +.PP +To understand what kinds of incompatibilities one may expect, and in the rare +case that the version of Perl on your machine is older than this document, +see the section on "Troubleshooting these Examples" for more information. +.PP +If your extension uses some features of Perl which are not available on older +releases of Perl, your users would appreciate an early meaningful warning. +You would probably put this information into the \fIREADME\fR file, but nowadays +installation of extensions may be performed automatically, guided by \fICPAN.pm\fR +module or other tools. +.PP +In MakeMaker-based installations, \fIMakefile.PL\fR provides the earliest +opportunity to perform version checks. One can put something like this +in \fIMakefile.PL\fR for this purpose: +.PP +.Vb 8 +\& eval { require 5.007 } +\& or die <<EOD; +\& ############ +\& ### This module uses frobnication framework which is not available +\& ### before version 5.007 of Perl. Upgrade your Perl before +\& ### installing Kara::Mba. +\& ############ +\& EOD +.Ve +.SS "Dynamic Loading versus Static Loading" +.IX Subsection "Dynamic Loading versus Static Loading" +It is commonly thought that if a system does not have the capability to +dynamically load a library, you cannot build XSUBs. This is incorrect. +You \fIcan\fR build them, but you must link the XSUBs subroutines with the +rest of Perl, creating a new executable. This situation is similar to +Perl 4. +.PP +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. +.PP +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 "\f(CW\*(C`make\*(C'\fR" with no arguments is executed, run the command +"\f(CW\*(C`make perl\*(C'\fR" instead. +.PP +If you have generated such a statically-linked executable by choice, then +instead of saying "\f(CW\*(C`make test\*(C'\fR", you should say "\f(CW\*(C`make test_static\*(C'\fR". +On systems that cannot build dynamically-loadable libraries at all, simply +saying "\f(CW\*(C`make test\*(C'\fR" is sufficient. +.SS "Threads and PERL_NO_GET_CONTEXT" +.IX Subsection "Threads and PERL_NO_GET_CONTEXT" +For threaded builds, perl requires the context pointer for the current +thread, without \f(CW\*(C`PERL_NO_GET_CONTEXT\*(C'\fR, perl will call a function to +retrieve the context. +.PP +For improved performance, include: +.PP +.Vb 1 +\& #define PERL_NO_GET_CONTEXT +.Ve +.PP +as shown below. +.PP +For more details, see perlguts. +.SH TUTORIAL +.IX Header "TUTORIAL" +Now let's go on with the show! +.SS "EXAMPLE 1" +.IX Subsection "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. +.PP +Run "\f(CW\*(C`h2xs \-A \-n Mytest\*(C'\fR". This creates a directory named Mytest, +possibly under ext/ if that directory exists in the current working +directory. Several files will be created under the Mytest dir, including +MANIFEST, Makefile.PL, lib/Mytest.pm, Mytest.xs, t/Mytest.t, and Changes. +.PP +The MANIFEST file contains the names of all the files just created in the +Mytest directory. +.PP +The file Makefile.PL should look something like this: +.PP +.Vb 1 +\& use ExtUtils::MakeMaker; +\& +\& # See lib/ExtUtils/MakeMaker.pm for details of how to influence +\& # the contents of the Makefile that is written. +\& WriteMakefile( +\& NAME => \*(AqMytest\*(Aq, +\& VERSION_FROM => \*(AqMytest.pm\*(Aq, # finds $VERSION +\& LIBS => [\*(Aq\*(Aq], # e.g., \*(Aq\-lm\*(Aq +\& DEFINE => \*(Aq\*(Aq, # e.g., \*(Aq\-DHAVE_SOMETHING\*(Aq +\& INC => \*(Aq\-I\*(Aq, # e.g., \*(Aq\-I. \-I/usr/include/other\*(Aq +\& ); +.Ve +.PP +The file Mytest.pm should start with something like this: +.PP +.Vb 1 +\& package Mytest; +\& +\& use 5.008008; +\& use strict; +\& use warnings; +\& +\& require Exporter; +\& +\& our @ISA = qw(Exporter); +\& our %EXPORT_TAGS = ( \*(Aqall\*(Aq => [ qw( +\& +\& ) ] ); +\& +\& our @EXPORT_OK = ( @{ $EXPORT_TAGS{\*(Aqall\*(Aq} } ); +\& +\& our @EXPORT = qw( +\& +\& ); +\& +\& our $VERSION = \*(Aq0.01\*(Aq; +\& +\& require XSLoader; +\& XSLoader::load(\*(AqMytest\*(Aq, $VERSION); +\& +\& # Preloaded methods go here. +\& +\& 1; +\& _\|_END_\|_ +\& # Below is the stub of documentation for your module. You better +\& # edit it! +.Ve +.PP +The rest of the .pm file contains sample code for providing documentation for +the extension. +.PP +Finally, the Mytest.xs file should look something like this: +.PP +.Vb 4 +\& #define PERL_NO_GET_CONTEXT +\& #include "EXTERN.h" +\& #include "perl.h" +\& #include "XSUB.h" +\& +\& #include "ppport.h" +\& +\& MODULE = Mytest PACKAGE = Mytest +.Ve +.PP +Let's edit the .xs file by adding this to the end of the file: +.PP +.Vb 4 +\& void +\& hello() +\& CODE: +\& printf("Hello, world!\en"); +.Ve +.PP +It is okay for the lines starting at the "CODE:" line to not be indented. +However, for readability purposes, it is suggested that you indent CODE: +one level and the lines following one more level. +.PP +Now we'll run "\f(CW\*(C`perl Makefile.PL\*(C'\fR". This will create a real Makefile, +which make needs. Its output looks something like: +.PP +.Vb 5 +\& % perl Makefile.PL +\& Checking if your kit is complete... +\& Looks good +\& Writing Makefile for Mytest +\& % +.Ve +.PP +Now, running make will produce output that looks something like this (some +long lines have been shortened for clarity and some extraneous lines have +been deleted): +.PP +.Vb 10 +\& % make +\& cp lib/Mytest.pm blib/lib/Mytest.pm +\& perl xsubpp \-typemap typemap Mytest.xs > Mytest.xsc && \e +\& mv Mytest.xsc Mytest.c +\& Please specify prototyping behavior for Mytest.xs (see perlxs manual) +\& cc \-c Mytest.c +\& Running Mkbootstrap for Mytest () +\& chmod 644 Mytest.bs +\& rm \-f blib/arch/auto/Mytest/Mytest.so +\& cc \-shared \-L/usr/local/lib Mytest.o \-o blib/arch/auto/Mytest/Mytest.so +\& +\& chmod 755 blib/arch/auto/Mytest/Mytest.so +\& cp Mytest.bs blib/arch/auto/Mytest/Mytest.bs +\& chmod 644 blib/arch/auto/Mytest/Mytest.bs +\& Manifying blib/man3/Mytest.3pm +\& % +.Ve +.PP +You can safely ignore the line about "prototyping behavior" \- it is +explained in "The PROTOTYPES: Keyword" in perlxs. +.PP +Perl has its own special way of easily writing test scripts, but for this +example only, we'll create our own test script. Create a file called hello +that looks like this: +.PP +.Vb 1 +\& #! /opt/perl5/bin/perl +\& +\& use ExtUtils::testlib; +\& +\& use Mytest; +\& +\& Mytest::hello(); +.Ve +.PP +Now we make the script executable (\f(CW\*(C`chmod +x hello\*(C'\fR), run the script +and we should see the following output: +.PP +.Vb 3 +\& % ./hello +\& Hello, world! +\& % +.Ve +.SS "EXAMPLE 2" +.IX Subsection "EXAMPLE 2" +Now let's add to our extension a subroutine that will take a single numeric +argument as input and return 1 if the number is even or 0 if the number +is odd. +.PP +Add the following to the end of Mytest.xs: +.PP +.Vb 7 +\& int +\& is_even(input) +\& int input +\& CODE: +\& RETVAL = (input % 2 == 0); +\& OUTPUT: +\& RETVAL +.Ve +.PP +There does not need to be whitespace at the start of the "\f(CW\*(C`int input\*(C'\fR" +line, but it is useful for improving readability. Placing a semi-colon at +the end of that line is also optional. Any amount and kind of whitespace +may be placed between the "\f(CW\*(C`int\*(C'\fR" and "\f(CW\*(C`input\*(C'\fR". +.PP +Now re-run make to rebuild our new shared library. +.PP +Now perform the same steps as before, generating a Makefile from the +Makefile.PL file, and running make. +.PP +In order to test that our extension works, we now need to look at the +file Mytest.t. 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. +.PP +.Vb 2 +\& use Test::More tests => 4; +\& BEGIN { use_ok(\*(AqMytest\*(Aq) }; +\& +\& ######################### +\& +\& # Insert your test code below, the Test::More module is use()ed here +\& # so read its man page ( perldoc Test::More ) for help writing this +\& # test script. +\& +\& is( Mytest::is_even(0), 1 ); +\& is( Mytest::is_even(1), 0 ); +\& is( Mytest::is_even(2), 1 ); +.Ve +.PP +We will be calling the test script through the command "\f(CW\*(C`make test\*(C'\fR". You +should see output that looks something like this: +.PP +.Vb 7 +\& %make test +\& PERL_DL_NONLAZY=1 /usr/bin/perl "\-MExtUtils::Command::MM" "\-e" +\& "test_harness(0, \*(Aqblib/lib\*(Aq, \*(Aqblib/arch\*(Aq)" t/*.t +\& t/Mytest....ok +\& All tests successful. +\& Files=1, Tests=4, 0 wallclock secs ( 0.03 cusr + 0.00 csys = 0.03 CPU) +\& % +.Ve +.SS "What has gone on?" +.IX Subsection "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. +.PP +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. +.PP +The .pm and .xs files 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. +.PP +Generating the Makefile and running \f(CW\*(C`make\*(C'\fR created a directory called 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. +.PP +Invoking the test script via "\f(CW\*(C`make test\*(C'\fR" did something very important. +It invoked perl with all those \f(CW\*(C`\-I\*(C'\fR arguments so that it could find the +various files that are part of the extension. It is \fIvery\fR important that +while you are still testing extensions that you use "\f(CW\*(C`make test\*(C'\fR". If you +try to run the test script all by itself, you will get a fatal error. +Another reason it is important to use "\f(CW\*(C`make test\*(C'\fR" to run your test +script is that if you are testing an upgrade to an already-existing version, +using "\f(CW\*(C`make test\*(C'\fR" ensures that you will test your new extension, not the +already-existing version. +.PP +When Perl sees a \f(CW\*(C`use extension;\*(C'\fR, it searches for a file with the same name +as the \f(CW\*(C`use\*(C'\fR'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 +\&\f(CW@INC\fR array. +.PP +In our case, Mytest.pm tells perl that it will need the Exporter and Dynamic +Loader extensions. It then sets the \f(CW@ISA\fR and \f(CW@EXPORT\fR arrays and the +\&\f(CW$VERSION\fR 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. +.PP +The two arrays \f(CW@ISA\fR and \f(CW@EXPORT\fR are very important. The \f(CW@ISA\fR +array contains a list of other packages in which to search for methods (or +subroutines) that do not exist in the current package. This is usually +only important for object-oriented extensions (which we will talk about +much later), and so usually doesn't need to be modified. +.PP +The \f(CW@EXPORT\fR array tells Perl which of the extension's variables and +subroutines should be placed into the calling package's namespace. Because +you don't know if the user has already used your variable and subroutine +names, it's vitally important to carefully select what to export. Do \fInot\fR +export method or variable names \fIby default\fR without a good reason. +.PP +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 and variables, then +you can export them via another array, called \f(CW@EXPORT_OK\fR. This array +does not automatically place its subroutine and variable names into the +namespace unless the user specifically requests that this be done. +.PP +See perlmod for more information. +.PP +The \f(CW$VERSION\fR 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. +.SS "Writing good test scripts" +.IX Subsection "Writing good test scripts" +The importance of writing good test scripts cannot be over-emphasized. 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. +.PP +By running "\f(CW\*(C`make test\*(C'\fR", you ensure that your Mytest.t script runs and uses +the correct version of your extension. If you have many test cases, +save your test files in the "t" directory and use the suffix ".t". +When you run "\f(CW\*(C`make test\*(C'\fR", all of these test files will be executed. +.SS "EXAMPLE 3" +.IX Subsection "EXAMPLE 3" +Our third extension will take one argument as its input, round off that +value, and set the \fIargument\fR to the rounded value. +.PP +Add the following to the end of Mytest.xs: +.PP +.Vb 10 +\& 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 +.Ve +.PP +Edit the Makefile.PL file so that the corresponding line looks like this: +.PP +.Vb 1 +\& LIBS => [\*(Aq\-lm\*(Aq], # e.g., \*(Aq\-lm\*(Aq +.Ve +.PP +Generate the Makefile and run make. Change the test number in Mytest.t to +"9" and add the following tests: +.PP +.Vb 1 +\& my $i; +\& +\& $i = \-1.5; +\& Mytest::round($i); +\& is( $i, \-2.0, \*(AqRounding \-1.5 to \-2.0\*(Aq ); +\& +\& $i = \-1.1; +\& Mytest::round($i); +\& is( $i, \-1.0, \*(AqRounding \-1.1 to \-1.0\*(Aq ); +\& +\& $i = 0.0; +\& Mytest::round($i); +\& is( $i, 0.0, \*(AqRounding 0.0 to 0.0\*(Aq ); +\& +\& $i = 0.5; +\& Mytest::round($i); +\& is( $i, 1.0, \*(AqRounding 0.5 to 1.0\*(Aq ); +\& +\& $i = 1.2; +\& Mytest::round($i); +\& is( $i, 1.0, \*(AqRounding 1.2 to 1.0\*(Aq ); +.Ve +.PP +Running "\f(CW\*(C`make test\*(C'\fR" should now print out that all nine tests are okay. +.PP +Notice that in these new test cases, the argument passed to round was a +scalar variable. You might be wondering if you can round a constant or +literal. To see what happens, temporarily add the following line to Mytest.t: +.PP +.Vb 1 +\& Mytest::round(3); +.Ve +.PP +Run "\f(CW\*(C`make test\*(C'\fR" and notice that Perl dies with a fatal error. Perl won't +let you change the value of constants! +.SS "What's new here?" +.IX Subsection "What's new here?" +.IP \(bu 4 +We've made some changes to Makefile.PL. In this case, we've specified an +extra library to be linked into the extension's shared library, the math +library libm in this case. We'll talk later about how to write XSUBs that +can call every routine in a library. +.IP \(bu 4 +The value of the function is not being passed back as the function's return +value, but by changing the value of the variable that was passed into the +function. You might have guessed that when you saw that the return value +of round is of type "void". +.SS "Input and Output Parameters" +.IX Subsection "Input and Output Parameters" +You specify the parameters that will be passed into the XSUB on the line(s) +after you declare the function's return value and name. Each input parameter +line starts with optional whitespace, and may have an optional terminating +semicolon. +.PP +The list of output parameters occurs at the very end of the function, just +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, we wanted the "return value" placed in the original variable +which we passed in, so we listed it (and not RETVAL) in the OUTPUT: section. +.SS "The XSUBPP Program" +.IX Subsection "The XSUBPP Program" +The \fBxsubpp\fR program takes the XS code in the .xs file and translates 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. +.SS "The TYPEMAP file" +.IX Subsection "The TYPEMAP file" +The \fBxsubpp\fR program 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). There's a brief discussion +below, but all the nitty-gritty details can be found in perlxstypemap. +If you have a new-enough version of perl (5.16 and up) or an upgraded +XS compiler (\f(CW\*(C`ExtUtils::ParseXS\*(C'\fR 3.13_01 or better), then you can inline +typemaps in your XS instead of writing separate files. +Either way, this typemap thing is split into three parts: +.PP +The first section maps various C data types to a name, which corresponds +somewhat with the various Perl types. The second section contains C code +which \fBxsubpp\fR uses to handle input parameters. The third section contains +C code which \fBxsubpp\fR uses to handle output parameters. +.PP +Let's take a look at a portion of the .c file created for our extension. +The file name is Mytest.c: +.PP +.Vb 10 +\& XS(XS_Mytest_round) +\& { +\& dXSARGS; +\& if (items != 1) +\& Perl_croak(aTHX_ "Usage: Mytest::round(arg)"); +\& PERL_UNUSED_VAR(cv); /* \-W */ +\& { +\& 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 */ +\& SvSETMAGIC(ST(0)); +\& } +\& XSRETURN_EMPTY; +\& } +.Ve +.PP +Notice the two lines commented with "XXXXX". If you check the first part +of the typemap file (or section), you'll see that doubles are of type +T_DOUBLE. In the INPUT part of the typemap, 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 perlguts; we'll talk more later about what +that "\fBST\fR\|(0)" means in the section on the argument stack. +.SS "Warning about Output Arguments" +.IX Subsection "Warning about Output Arguments" +In general, it's not a good idea to write extensions that modify their input +parameters, as in Example 3. Instead, you should probably return multiple +values in an array and let the caller handle them (we'll do this in a later +example). However, in order to better accommodate calling pre-existing C +routines, which often do modify their input parameters, this behavior is +tolerated. +.SS "EXAMPLE 4" +.IX Subsection "EXAMPLE 4" +In this example, we'll now begin to write XSUBs 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. +.PP +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. +.PP +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. +.PP +In the mylib directory, create a file mylib.h that looks like this: +.PP +.Vb 1 +\& #define TESTVAL 4 +\& +\& extern double foo(int, long, const char*); +.Ve +.PP +Also create a file mylib.c that looks like this: +.PP +.Vb 2 +\& #include <stdlib.h> +\& #include "mylib.h" +\& +\& double +\& foo(int a, long b, const char *c) +\& { +\& return (a + b + atof(c) + TESTVAL); +\& } +.Ve +.PP +And finally create a file Makefile.PL that looks like this: +.PP +.Vb 7 +\& use ExtUtils::MakeMaker; +\& $Verbose = 1; +\& WriteMakefile( +\& NAME => \*(AqMytest2::mylib\*(Aq, +\& SKIP => [qw(all static static_lib dynamic dynamic_lib)], +\& clean => {\*(AqFILES\*(Aq => \*(Aqlibmylib$(LIB_EXT)\*(Aq}, +\& ); +\& +\& +\& sub MY::top_targets { +\& \*(Aq +\& all :: static +\& +\& pure_all :: static +\& +\& static :: libmylib$(LIB_EXT) +\& +\& libmylib$(LIB_EXT): $(O_FILES) +\& $(AR) cr libmylib$(LIB_EXT) $(O_FILES) +\& $(RANLIB) libmylib$(LIB_EXT) +\& +\& \*(Aq; +\& } +.Ve +.PP +Make sure you use a tab and not spaces on the lines beginning with "$(AR)" +and "$(RANLIB)". Make will not function properly if you use spaces. +It has also been reported that the "cr" argument to $(AR) is unnecessary +on Win32 systems. +.PP +We will now create the main top-level Mytest2 files. Change to the directory +above Mytest2 and run the following command: +.PP +.Vb 1 +\& % h2xs \-O \-n Mytest2 Mytest2/mylib/mylib.h +.Ve +.PP +This will print out a warning about overwriting Mytest2, but that's okay. +Our files are stored in Mytest2/mylib, and will be untouched. +.PP +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 argument MYEXTLIB to +the WriteMakefile call so that it looks like this: +.PP +.Vb 8 +\& WriteMakefile( +\& NAME => \*(AqMytest2\*(Aq, +\& VERSION_FROM => \*(AqMytest2.pm\*(Aq, # finds $VERSION +\& LIBS => [\*(Aq\*(Aq], # e.g., \*(Aq\-lm\*(Aq +\& DEFINE => \*(Aq\*(Aq, # e.g., \*(Aq\-DHAVE_SOMETHING\*(Aq +\& INC => \*(Aq\*(Aq, # e.g., \*(Aq\-I/usr/include/other\*(Aq +\& MYEXTLIB => \*(Aqmylib/libmylib$(LIB_EXT)\*(Aq, +\& ); +.Ve +.PP +and then at the end add a subroutine (which will override the pre-existing +subroutine). Remember to use a tab character to indent the line beginning +with "cd"! +.PP +.Vb 6 +\& sub MY::postamble { +\& \*(Aq +\& $(MYEXTLIB): mylib/Makefile +\& cd mylib && $(MAKE) $(PASSTHRU) +\& \*(Aq; +\& } +.Ve +.PP +Let's also fix the MANIFEST file by appending the following three lines: +.PP +.Vb 3 +\& mylib/Makefile.PL +\& mylib/mylib.c +\& mylib/mylib.h +.Ve +.PP +To keep our namespace nice and unpolluted, edit the .pm file and change +the variable \f(CW@EXPORT\fR to \f(CW@EXPORT_OK\fR. Finally, in the +\&.xs file, edit the #include line to read: +.PP +.Vb 1 +\& #include "mylib/mylib.h" +.Ve +.PP +And also add the following function definition to the end of the .xs file: +.PP +.Vb 7 +\& double +\& foo(a,b,c) +\& int a +\& long b +\& const char * c +\& OUTPUT: +\& RETVAL +.Ve +.PP +Now we also need to create a typemap because the default Perl doesn't +currently support the \f(CW\*(C`const char *\*(C'\fR type. Include a new TYPEMAP +section in your XS code before the above function: +.PP +.Vb 3 +\& TYPEMAP: <<END +\& const char * T_PV +\& END +.Ve +.PP +Now run perl on the top-level Makefile.PL. Notice that it also created a +Makefile in the mylib directory. Run make and watch that it does cd into +the mylib directory and run make in there as well. +.PP +Now edit the Mytest2.t script and change the number of tests to "5", +and add the following lines to the end of the script: +.PP +.Vb 3 +\& is( Mytest2::foo( 1, 2, "Hello, world!" ), 7 ); +\& is( Mytest2::foo( 1, 2, "0.0" ), 7 ); +\& ok( abs( Mytest2::foo( 0, 0, "\-3.4" ) \- 0.6 ) <= 0.01 ); +.Ve +.PP +(When dealing with floating-point comparisons, it is best to not check for +equality, but rather that the difference between the expected and actual +result is below a certain amount (called epsilon) which is 0.01 in this case) +.PP +Run "\f(CW\*(C`make test\*(C'\fR" and all should be well. There are some warnings on missing +tests for the Mytest2::mylib extension, but you can ignore them. +.SS "What has happened here?" +.IX Subsection "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. +.IP \(bu 4 +In the .xs file, there's now a #include directive with the absolute path to +the mylib.h header file. We changed this to a relative path so that we +could move the extension directory if we wanted to. +.IP \(bu 4 +There's now some new C code that's been added to the .xs file. The purpose +of the \f(CW\*(C`constant\*(C'\fR routine is to make the values that are #define'd in the +header file accessible by the Perl script (by calling either \f(CW\*(C`TESTVAL\*(C'\fR or +\&\f(CW&Mytest2::TESTVAL\fR). There's also some XS code to allow calls to the +\&\f(CW\*(C`constant\*(C'\fR routine. +.IP \(bu 4 +The .pm file originally exported the name \f(CW\*(C`TESTVAL\*(C'\fR in the \f(CW@EXPORT\fR 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 \f(CW@EXPORT\fR array. Alternately, if you don't +mind using the "fully qualified name" of a variable, you could move most +or all of the items from the \f(CW@EXPORT\fR array into the \f(CW@EXPORT_OK\fR array. +.IP \(bu 4 +If our include file had contained #include directives, these would not have +been processed by h2xs. There is no good solution to this right now. +.IP \(bu 4 +We've also told Perl about the library that we built in the mylib +subdirectory. That required only the addition of the \f(CW\*(C`MYEXTLIB\*(C'\fR 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 +library (as opposed to a dynamically loadable library) and provided the +commands to build it. +.SS "Anatomy of .xs file" +.IX Subsection "Anatomy of .xs file" +The .xs file of "EXAMPLE 4" contained some new elements. To understand +the meaning of these elements, pay attention to the line which reads +.PP +.Vb 1 +\& MODULE = Mytest2 PACKAGE = Mytest2 +.Ve +.PP +Anything before this line is plain C code which describes which headers +to include, and defines some convenience functions. No translations are +performed on this part, apart from having embedded POD documentation +skipped over (see perlpod) it goes into the generated output C file as is. +.PP +Anything after this line is the description of XSUB functions. +These descriptions are translated by \fBxsubpp\fR into C code which +implements these functions using Perl calling conventions, and which +makes these functions visible from Perl interpreter. +.PP +Pay a special attention to the function \f(CW\*(C`constant\*(C'\fR. This name appears +twice in the generated .xs file: once in the first part, as a static C +function, then another time in the second part, when an XSUB interface to +this static C function is defined. +.PP +This is quite typical for .xs files: usually the .xs file provides +an interface to an existing C function. Then this C function is defined +somewhere (either in an external library, or in the first part of .xs file), +and a Perl interface to this function (i.e. "Perl glue") is described in the +second part of .xs file. The situation in "EXAMPLE 1", "EXAMPLE 2", +and "EXAMPLE 3", when all the work is done inside the "Perl glue", is +somewhat of an exception rather than the rule. +.SS "Getting the fat out of XSUBs" +.IX Subsection "Getting the fat out of XSUBs" +In "EXAMPLE 4" the second part of .xs file contained the following +description of an XSUB: +.PP +.Vb 7 +\& double +\& foo(a,b,c) +\& int a +\& long b +\& const char * c +\& OUTPUT: +\& RETVAL +.Ve +.PP +Note that in contrast with "EXAMPLE 1", "EXAMPLE 2" and "EXAMPLE 3", +this description does not contain the actual \fIcode\fR for what is done +during a call to Perl function \fBfoo()\fR. To understand what is going +on here, one can add a CODE section to this XSUB: +.PP +.Vb 9 +\& double +\& foo(a,b,c) +\& int a +\& long b +\& const char * c +\& CODE: +\& RETVAL = foo(a,b,c); +\& OUTPUT: +\& RETVAL +.Ve +.PP +However, these two XSUBs provide almost identical generated C code: \fBxsubpp\fR +compiler is smart enough to figure out the \f(CW\*(C`CODE:\*(C'\fR section from the first +two lines of the description of XSUB. What about \f(CW\*(C`OUTPUT:\*(C'\fR section? In +fact, that is absolutely the same! The \f(CW\*(C`OUTPUT:\*(C'\fR section can be removed +as well, \fIas far as \fR\f(CI\*(C`CODE:\*(C'\fR\fI section or \fR\f(CI\*(C`PPCODE:\*(C'\fR\fI section\fR is not +specified: \fBxsubpp\fR can see that it needs to generate a function call +section, and will autogenerate the OUTPUT section too. Thus one can +shortcut the XSUB to become: +.PP +.Vb 5 +\& double +\& foo(a,b,c) +\& int a +\& long b +\& const char * c +.Ve +.PP +Can we do the same with an XSUB +.PP +.Vb 7 +\& int +\& is_even(input) +\& int input +\& CODE: +\& RETVAL = (input % 2 == 0); +\& OUTPUT: +\& RETVAL +.Ve +.PP +of "EXAMPLE 2"? To do this, one needs to define a C function \f(CW\*(C`int +is_even(int input)\*(C'\fR. As we saw in "Anatomy of .xs file", a proper place +for this definition is in the first part of .xs file. In fact a C function +.PP +.Vb 5 +\& int +\& is_even(int arg) +\& { +\& return (arg % 2 == 0); +\& } +.Ve +.PP +is probably overkill for this. Something as simple as a \f(CW\*(C`#define\*(C'\fR will +do too: +.PP +.Vb 1 +\& #define is_even(arg) ((arg) % 2 == 0) +.Ve +.PP +After having this in the first part of .xs file, the "Perl glue" part becomes +as simple as +.PP +.Vb 3 +\& int +\& is_even(input) +\& int input +.Ve +.PP +This technique of separation of the glue part from the workhorse part has +obvious tradeoffs: if you want to change a Perl interface, you need to +change two places in your code. However, it removes a lot of clutter, +and makes the workhorse part independent from idiosyncrasies of Perl calling +convention. (In fact, there is nothing Perl-specific in the above description, +a different version of \fBxsubpp\fR might have translated this to TCL glue or +Python glue as well.) +.SS "More about XSUB arguments" +.IX Subsection "More about XSUB arguments" +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 +\&\fBxsubpp\fR compiler. +.PP +When you specify arguments to routines in the .xs file, you are really +passing three pieces of information for each argument 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 calling convention for the argument in the call to the library function. +.PP +While Perl passes arguments to functions by reference, +C passes arguments by value; to implement a C function which modifies data +of one of the "arguments", the actual argument of this C function would be +a pointer to the data. Thus two C functions with declarations +.PP +.Vb 2 +\& int string_length(char *s); +\& int upper_case_char(char *cp); +.Ve +.PP +may have completely different semantics: the first one may inspect an array +of chars pointed by s, and the second one may immediately dereference \f(CW\*(C`cp\*(C'\fR +and manipulate \f(CW*cp\fR only (using the return value as, say, a success +indicator). From Perl one would use these functions in +a completely different manner. +.PP +One conveys this info to \fBxsubpp\fR by replacing \f(CW\*(C`*\*(C'\fR before the +argument by \f(CW\*(C`&\*(C'\fR. \f(CW\*(C`&\*(C'\fR means that the argument should be passed to a library +function by its address. The above two function may be XSUB-ified as +.PP +.Vb 3 +\& int +\& string_length(s) +\& char * s +\& +\& int +\& upper_case_char(cp) +\& char &cp +.Ve +.PP +For example, consider: +.PP +.Vb 4 +\& int +\& foo(a,b) +\& char &a +\& char * b +.Ve +.PP +The first Perl 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 Perl argument would be treated as a string pointer and assigned +to the variable b. The \fIvalue\fR of b would be passed into the function foo. +The actual call to the function foo that \fBxsubpp\fR generates would look like +this: +.PP +.Vb 1 +\& foo(&a, b); +.Ve +.PP +\&\fBxsubpp\fR will parse the following function argument lists identically: +.PP +.Vb 3 +\& char &a +\& char&a +\& char & a +.Ve +.PP +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 +call to foo 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". +.PP +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. +.SS "The Argument Stack" +.IX Subsection "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. "ST" is actually a macro that points to the n'th argument +on the argument stack. \fBST\fR\|(0) is thus the first argument on the stack and +therefore the first argument passed to the XSUB, \fBST\fR\|(1) is the second +argument, and so on. +.PP +When you list the arguments to the XSUB in the .xs file, that tells \fBxsubpp\fR +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. +.PP +The actual values on the argument stack are pointers to the values passed +in. When an argument is listed as being an OUTPUT value, its corresponding +value on the stack (i.e., \fBST\fR\|(0) if it was the first argument) is changed. +You can verify this by looking at the C code generated for Example 3. +The code for the \fBround()\fR XSUB routine contains lines that look like this: +.PP +.Vb 3 +\& double arg = (double)SvNV(ST(0)); +\& /* Round the contents of the variable arg */ +\& sv_setnv(ST(0), (double)arg); +.Ve +.PP +The arg variable is initially set by taking the value from \fBST\fR\|(0), then is +stored back into \fBST\fR\|(0) at the end of the routine. +.PP +XSUBs are also allowed to return lists, not just scalars. This must be +done by manipulating stack values \fBST\fR\|(0), \fBST\fR\|(1), etc, in a subtly +different way. See perlxs for details. +.PP +XSUBs are also allowed to avoid automatic conversion of Perl function arguments +to C function arguments. See perlxs for details. Some people prefer +manual conversion by inspecting \f(CWST(i)\fR even in the cases when automatic +conversion will do, arguing that this makes the logic of an XSUB call clearer. +Compare with "Getting the fat out of XSUBs" for a similar tradeoff of +a complete separation of "Perl glue" and "workhorse" parts of an XSUB. +.PP +While experts may argue about these idioms, a novice to Perl guts may +prefer a way which is as little Perl-guts-specific as possible, meaning +automatic conversion and automatic call generation, as in +"Getting the fat out of XSUBs". This approach has the additional +benefit of protecting the XSUB writer from future changes to the Perl API. +.SS "Extending your Extension" +.IX Subsection "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. You can also consult AutoLoader for an alternate +way to store and load your extra subroutines. +.SS "Documenting your Extension" +.IX Subsection "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 +manpage directory when the extension is installed. +.PP +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. +.PP +See perlpod for more information about the pod format. +.SS "Installing your Extension" +.IX Subsection "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. +.PP +Alternately, you can specify the exact directory to place the extension's +files by placing a "PREFIX=/destination/directory" after the make install +(or in between the make and install if you have a brain-dead version of make). +This can be very useful if you are building an extension that will eventually +be distributed to multiple systems. You can then just archive the files in +the destination directory and distribute them to your destination systems. +.SS "EXAMPLE 5" +.IX Subsection "EXAMPLE 5" +In this example, we'll do some more work with the argument stack. The +previous examples have all returned only a single value. We'll now +create an extension that returns an array. +.PP +This extension is very Unix-oriented (struct statfs and the statfs system +call). If you are not running on a Unix system, you can substitute for +statfs any other function that returns multiple values, you can hard-code +values to be returned to the caller (although this will be a bit harder +to test the error case), or you can simply not do this example. If you +change the XSUB, be sure to fix the test cases to match the changes. +.PP +Return to the Mytest directory and add the following code to the end of +Mytest.xs: +.PP +.Vb 6 +\& void +\& statfs(path) +\& char * path +\& INIT: +\& int i; +\& struct statfs buf; +\& +\& PPCODE: +\& i = statfs(path, &buf); +\& if (i == 0) { +\& XPUSHs(sv_2mortal(newSVnv(buf.f_bavail))); +\& XPUSHs(sv_2mortal(newSVnv(buf.f_bfree))); +\& XPUSHs(sv_2mortal(newSVnv(buf.f_blocks))); +\& XPUSHs(sv_2mortal(newSVnv(buf.f_bsize))); +\& XPUSHs(sv_2mortal(newSVnv(buf.f_ffree))); +\& XPUSHs(sv_2mortal(newSVnv(buf.f_files))); +\& XPUSHs(sv_2mortal(newSVnv(buf.f_type))); +\& } else { +\& XPUSHs(sv_2mortal(newSVnv(errno))); +\& } +.Ve +.PP +You'll also need to add the following code to the top of the .xs file, just +after the include of "XSUB.h": +.PP +.Vb 1 +\& #include <sys/vfs.h> +.Ve +.PP +Also add the following code segment to Mytest.t while incrementing the "9" +tests to "11": +.PP +.Vb 1 +\& my @a; +\& +\& @a = Mytest::statfs("/blech"); +\& ok( scalar(@a) == 1 && $a[0] == 2 ); +\& +\& @a = Mytest::statfs("/"); +\& is( scalar(@a), 7 ); +.Ve +.SS "New Things in this Example" +.IX Subsection "New Things in this Example" +This example added quite a few new concepts. We'll take them one at a time. +.IP \(bu 4 +The INIT: directive contains code that will be placed immediately after +the argument stack is decoded. C does not allow variable declarations at +arbitrary locations inside a function, +so this is usually the best way to declare local variables needed by the XSUB. +(Alternatively, one could put the whole \f(CW\*(C`PPCODE:\*(C'\fR section into braces, and +put these declarations on top.) +.IP \(bu 4 +This routine also returns a different number of arguments depending on the +success or failure of the call to statfs. If there is an error, the error +number is returned as a single-element array. If the call is successful, +then a 7\-element array is returned. Since only one argument is passed into +this function, we need room on the stack to hold the 7 values which may be +returned. +.Sp +We do this by using the PPCODE: directive, rather than the CODE: directive. +This tells \fBxsubpp\fR that we will be managing the return values that will be +put on the argument stack by ourselves. +.IP \(bu 4 +When we want to place values to be returned to the caller onto the stack, +we use the series of macros that begin with "XPUSH". There are five +different versions, for placing integers, unsigned integers, doubles, +strings, and Perl scalars on the stack. In our example, we placed a +Perl scalar onto the stack. (In fact this is the only macro which +can be used to return multiple values.) +.Sp +The XPUSH* macros will automatically extend the return stack to prevent +it from being overrun. You push values onto the stack in the order you +want them seen by the calling program. +.IP \(bu 4 +The values pushed onto the return stack of the XSUB are actually mortal SV's. +They are made mortal so that once the values are copied by the calling +program, the SV's that held the returned values can be deallocated. +If they were not mortal, then they would continue to exist after the XSUB +routine returned, but would not be accessible. This is a memory leak. +.IP \(bu 4 +If we were interested in performance, not in code compactness, in the success +branch we would not use \f(CW\*(C`XPUSHs\*(C'\fR macros, but \f(CW\*(C`PUSHs\*(C'\fR macros, and would +pre-extend the stack before pushing the return values: +.Sp +.Vb 1 +\& EXTEND(SP, 7); +.Ve +.Sp +The tradeoff is that one needs to calculate the number of return values +in advance (though overextending the stack will not typically hurt +anything but memory consumption). +.Sp +Similarly, in the failure branch we could use \f(CW\*(C`PUSHs\*(C'\fR \fIwithout\fR extending +the stack: the Perl function reference comes to an XSUB on the stack, thus +the stack is \fIalways\fR large enough to take one return value. +.SS "EXAMPLE 6" +.IX Subsection "EXAMPLE 6" +In this example, we will accept a reference to an array as an input +parameter, and return a reference to an array of hashes. This will +demonstrate manipulation of complex Perl data types from an XSUB. +.PP +This extension is somewhat contrived. It is based on the code in +the previous example. It calls the statfs function multiple times, +accepting a reference to an array of filenames as input, and returning +a reference to an array of hashes containing the data for each of the +filesystems. +.PP +Return to the Mytest directory and add the following code to the end of +Mytest.xs: +.PP +.Vb 8 +\& SV * +\& multi_statfs(paths) +\& SV * paths +\& INIT: +\& AV * results; +\& SSize_t numpaths = 0, n; +\& int i; +\& struct statfs buf; +\& +\& SvGETMAGIC(paths); +\& if ((!SvROK(paths)) +\& || (SvTYPE(SvRV(paths)) != SVt_PVAV) +\& || ((numpaths = av_top_index((AV *)SvRV(paths))) < 0)) +\& { +\& XSRETURN_UNDEF; +\& } +\& results = (AV *)sv_2mortal((SV *)newAV()); +\& CODE: +\& for (n = 0; n <= numpaths; n++) { +\& HV * rh; +\& STRLEN l; +\& SV * path = *av_fetch((AV *)SvRV(paths), n, 0); +\& char * fn = SvPVbyte(path, l); +\& +\& i = statfs(fn, &buf); +\& if (i != 0) { +\& av_push(results, newSVnv(errno)); +\& continue; +\& } +\& +\& rh = (HV *)sv_2mortal((SV *)newHV()); +\& +\& hv_store(rh, "f_bavail", 8, newSVnv(buf.f_bavail), 0); +\& hv_store(rh, "f_bfree", 7, newSVnv(buf.f_bfree), 0); +\& hv_store(rh, "f_blocks", 8, newSVnv(buf.f_blocks), 0); +\& hv_store(rh, "f_bsize", 7, newSVnv(buf.f_bsize), 0); +\& hv_store(rh, "f_ffree", 7, newSVnv(buf.f_ffree), 0); +\& hv_store(rh, "f_files", 7, newSVnv(buf.f_files), 0); +\& hv_store(rh, "f_type", 6, newSVnv(buf.f_type), 0); +\& +\& av_push(results, newRV_inc((SV *)rh)); +\& } +\& RETVAL = newRV_inc((SV *)results); +\& OUTPUT: +\& RETVAL +.Ve +.PP +And add the following code to Mytest.t, while incrementing the "11" +tests to "13": +.PP +.Vb 3 +\& my $results = Mytest::multi_statfs([ \*(Aq/\*(Aq, \*(Aq/blech\*(Aq ]); +\& ok( ref $results\->[0] ); +\& ok( ! ref $results\->[1] ); +.Ve +.SS "New Things in this Example" +.IX Subsection "New Things in this Example" +There are a number of new concepts introduced here, described below: +.IP \(bu 4 +This function does not use a typemap. Instead, we declare it as accepting +one SV* (scalar) parameter, and returning an SV* value, and we take care of +populating these scalars within the code. Because we are only returning +one value, we don't need a \f(CW\*(C`PPCODE:\*(C'\fR directive \- instead, we use \f(CW\*(C`CODE:\*(C'\fR +and \f(CW\*(C`OUTPUT:\*(C'\fR directives. +.IP \(bu 4 +When dealing with references, it is important to handle them with caution. +The \f(CW\*(C`INIT:\*(C'\fR block first calls SvGETMAGIC(paths), in case +paths is a tied variable. Then it checks that \f(CW\*(C`SvROK\*(C'\fR returns +true, which indicates that paths is a valid reference. (Simply +checking \f(CW\*(C`SvROK\*(C'\fR won't trigger FETCH on a tied variable.) It +then verifies that the object referenced by paths is an array, using \f(CW\*(C`SvRV\*(C'\fR +to dereference paths, and \f(CW\*(C`SvTYPE\*(C'\fR to discover its type. As an added test, +it checks that the array referenced by paths is non-empty, using the +\&\f(CW\*(C`av_top_index\*(C'\fR function (which returns \-1 if the array is empty). The +XSRETURN_UNDEF macro is used to abort the XSUB and return the undefined value +whenever all three of these conditions are not met. +.IP \(bu 4 +We manipulate several arrays in this XSUB. Note that an array is represented +internally by an AV* pointer. The functions and macros for manipulating +arrays are similar to the functions in Perl: \f(CW\*(C`av_top_index\*(C'\fR returns the +highest index in an AV*, much like $#array; \f(CW\*(C`av_fetch\*(C'\fR fetches a single scalar +value from an array, given its index; \f(CW\*(C`av_push\*(C'\fR pushes a scalar value onto the +end of the array, automatically extending the array as necessary. +.Sp +Specifically, we read pathnames one at a time from the input array, and +store the results in an output array (results) in the same order. If +statfs fails, the element pushed onto the return array is the value of +errno after the failure. If statfs succeeds, though, the value pushed +onto the return array is a reference to a hash containing some of the +information in the statfs structure. +.Sp +As with the return stack, it would be possible (and a small performance win) +to pre-extend the return array before pushing data into it, since we know +how many elements we will return: +.Sp +.Vb 1 +\& av_extend(results, numpaths); +.Ve +.IP \(bu 4 +We are performing only one hash operation in this function, which is storing +a new scalar under a key using \f(CW\*(C`hv_store\*(C'\fR. A hash is represented by an HV* +pointer. Like arrays, the functions for manipulating hashes from an XSUB +mirror the functionality available from Perl. See perlguts and perlapi +for details. +.IP \(bu 4 +To create a reference, we use the \f(CW\*(C`newRV_inc\*(C'\fR function. Note that you can +cast an AV* or an HV* to type SV* in this case (and many others). This +allows you to take references to arrays, hashes and scalars with the same +function. Conversely, the \f(CW\*(C`SvRV\*(C'\fR function always returns an SV*, which may +need to be cast to the appropriate type if it is something other than a +scalar (check with \f(CW\*(C`SvTYPE\*(C'\fR). +.IP \(bu 4 +At this point, xsubpp is doing very little work \- the differences between +Mytest.xs and Mytest.c are minimal. +.SS "EXAMPLE 7 (Coming Soon)" +.IX Subsection "EXAMPLE 7 (Coming Soon)" +XPUSH args AND set RETVAL AND assign return value to array +.SS "EXAMPLE 8 (Coming Soon)" +.IX Subsection "EXAMPLE 8 (Coming Soon)" +Setting $! +.SS "EXAMPLE 9 Passing open files to XSes" +.IX Subsection "EXAMPLE 9 Passing open files to XSes" +You would think passing files to an XS is difficult, with all the +typeglobs and stuff. Well, it isn't. +.PP +Suppose that for some strange reason we need a wrapper around the +standard C library function \f(CWfputs()\fR. This is all we need: +.PP +.Vb 5 +\& #define PERLIO_NOT_STDIO 0 /* For co\-existence with stdio only */ +\& #define PERL_NO_GET_CONTEXT /* This is more efficient */ +\& #include "EXTERN.h" +\& #include "perl.h" +\& #include "XSUB.h" +\& +\& #include <stdio.h> +\& +\& int +\& fputs(s, stream) +\& char * s +\& FILE * stream +.Ve +.PP +The real work is done in the standard typemap. +.PP +For more details, see +"Co-existence with stdio" in perlapio. +.PP +\&\fBBut\fR you lose all the fine stuff done by the perlio layers. This +calls the stdio function \f(CWfputs()\fR, which knows nothing about them. +.PP +The standard typemap offers three variants of PerlIO *: +\&\f(CW\*(C`InputStream\*(C'\fR (T_IN), \f(CW\*(C`InOutStream\*(C'\fR (T_INOUT) and \f(CW\*(C`OutputStream\*(C'\fR +(T_OUT). A bare \f(CW\*(C`PerlIO *\*(C'\fR is considered a T_INOUT. If it matters +in your code (see below for why it might) #define or typedef +one of the specific names and use that as the argument or result +type in your XS file. +.PP +The standard typemap does not contain PerlIO * before perl 5.7, +but it has the three stream variants. Using a PerlIO * directly +is not backwards compatible unless you provide your own typemap. +.PP +For streams coming \fIfrom\fR perl the main difference is that +\&\f(CW\*(C`OutputStream\*(C'\fR will get the output PerlIO * \- which may make +a difference on a socket. Like in our example... +.PP +For streams being handed \fIto\fR perl a new file handle is created +(i.e. a reference to a new glob) and associated with the PerlIO * +provided. If the read/write state of the PerlIO * is not correct then you +may get errors or warnings from when the file handle is used. +So if you opened the PerlIO * as "w" it should really be an +\&\f(CW\*(C`OutputStream\*(C'\fR if open as "r" it should be an \f(CW\*(C`InputStream\*(C'\fR. +.PP +Now, suppose you want to use perlio layers in your XS. We'll use the +perlio \f(CWPerlIO_puts()\fR function as an example. +.PP +In the C part of the XS file (above the first MODULE line) you +have +.PP +.Vb 3 +\& #define OutputStream PerlIO * +\& or +\& typedef PerlIO * OutputStream; +.Ve +.PP +And this is the XS code: +.PP +.Vb 8 +\& int +\& perlioputs(s, stream) +\& char * s +\& OutputStream stream +\& CODE: +\& RETVAL = PerlIO_puts(stream, s); +\& OUTPUT: +\& RETVAL +.Ve +.PP +We have to use a \f(CW\*(C`CODE\*(C'\fR section because \f(CWPerlIO_puts()\fR has the arguments +reversed compared to \f(CWfputs()\fR, and we want to keep the arguments the same. +.PP +Wanting to explore this thoroughly, we want to use the stdio \f(CWfputs()\fR +on a PerlIO *. This means we have to ask the perlio system for a stdio +\&\f(CW\*(C`FILE *\*(C'\fR: +.PP +.Vb 10 +\& int +\& perliofputs(s, stream) +\& char * s +\& OutputStream stream +\& PREINIT: +\& FILE *fp = PerlIO_findFILE(stream); +\& CODE: +\& if (fp != (FILE*) 0) { +\& RETVAL = fputs(s, fp); +\& } else { +\& RETVAL = \-1; +\& } +\& OUTPUT: +\& RETVAL +.Ve +.PP +Note: \f(CWPerlIO_findFILE()\fR will search the layers for a stdio +layer. If it can't find one, it will call \f(CWPerlIO_exportFILE()\fR to +generate a new stdio \f(CW\*(C`FILE\*(C'\fR. Please only call \f(CWPerlIO_exportFILE()\fR if +you want a \fInew\fR \f(CW\*(C`FILE\*(C'\fR. It will generate one on each call and push a +new stdio layer. So don't call it repeatedly on the same +file. \f(CWPerlIO_findFILE()\fR will retrieve the stdio layer once it has been +generated by \f(CWPerlIO_exportFILE()\fR. +.PP +This applies to the perlio system only. For versions before 5.7, +\&\f(CWPerlIO_exportFILE()\fR is equivalent to \f(CWPerlIO_findFILE()\fR. +.SS "Troubleshooting these Examples" +.IX Subsection "Troubleshooting these Examples" +As mentioned at the top of this document, if you are having problems with +these example extensions, you might see if any of these help you. +.IP \(bu 4 +In versions of 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: +.Sp +.Vb 1 +\& use lib \*(Aq./blib\*(Aq; +.Ve +.IP \(bu 4 +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: +.Sp +.Vb 1 +\& use lib \*(Aq./blib\*(Aq; +.Ve +.IP \(bu 4 +In versions 5.000 and 5.001, instead of using the above line, you will need +to use the following line: +.Sp +.Vb 1 +\& BEGIN { unshift(@INC, "./blib") } +.Ve +.IP \(bu 4 +This document assumes that the executable named "perl" is Perl version 5. +Some systems may have installed Perl version 5 as "perl5". +.SH "See also" +.IX Header "See also" +For more information, consult perlguts, perlapi, perlxs, perlmod, +perlapio, and perlpod +.SH Author +.IX Header "Author" +Jeff Okamoto <\fIokamoto@corp.hp.com\fR> +.PP +Reviewed and assisted by Dean Roehrich, Ilya Zakharevich, Andreas Koenig, +and Tim Bunce. +.PP +PerlIO material contributed by Lupe Christoph, with some clarification +by Nick Ing-Simmons. +.PP +Changes for h2xs as of Perl 5.8.x by Renee Baecker +.PP +This document is now maintained as part of Perl itself. +.SS "Last Changed" +.IX Subsection "Last Changed" +2020\-10\-05 |