This tutorial starts with very simple examples and becomes more complex, bringing in more features that are available. Thus, certain statements towards the beginning may be incomplete. The reader is encouraged to read the entire document before lambasting the author about apparent mistakes.
This tutorial is still under construction. Constructive comments are welcome.
Run h2xs -A -n Test1
. This creates a directory named Test1, possibly under
ext/ if it exists in the current working directory. Four files will be
created in the Test1 dir: MANIFEST, Makefile.PL, Test1.pm, Test1.xs.
The MANIFEST file should contain the names of the four files created.
The file Makefile.PL should look something like this:
The file Test1.pm should look something like this:
And the Test1.xs file should look something like this:
Let's edit the .xs file by adding this to the end of the file:
Now we'll run perl Makefile.PL
. This will create a real Makefile,
which make needs. It's output looks something like:
Now, running make will produce output that looks something like this:
Now we'll create a test script, test1.pl in the Test1 directory. It should look like this:
Now we run the script and we should see the following output:
Run h2xs -A -n Test2
. This will create a Test2 directory with a file
Test2.xs underneath it. Add the following to the end of the XS file:
(Note that the line after the declaration of is_even is indented one tab stop. Although there is a tab between ``int'' and ``input'', this can be any amount of white space. Also notice that there is no semi-colon following the ``declaration'' of the variable input)
Now perform the same steps before, generating a Makefile from the Makefile.PL file, and running make.
Our test file test2.pl will now look like:
The output should look like:
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 tells Perl how to load your extension.
Generating the invoking the Makefile created a directory blib 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.
Finally, our test scripts do two important things. First of all, they place the directory ``blib'' at the head of the @INC array. Placing this inside a BEGIN block assures us that Perl will look in the blib directory hierarchy before looking in the system directories. This could be important if you are upgrading an already-existing extension and do not want to disturb the system version until you are ready to install it.
Second, the test scripts tell Perl to use extension; . When Perl sees this, it searches for a .pm file of the same name in the various directories kept in the @INC array. If it cannot be found, perl will die with an error that will look something like:
The .pm file tells perl that it will need the Exporter and Dynamic Loader extensions. It then sets the @ISA array, which is used for looking up methods that might not exist in the current package, and finally tells perl to bootstrap the module. Perl will call its dynamic loader routine and load the shared library.
The @EXPORT array in the .pm file tells Perl which of the extension's routines should be placed into the calling package's namespace. In our two examples so far, we have not modified the @EXPORT array, so our test scripts must call the routines by their complete name (e.g., Test1::hello). If we placed the name of the routine in the @EXPORT array, so that the .pm file looked like:
Then the hello routine would also be callable from the ``main'' package. We could therefore change test1.pl to look like:
And we would get the same output, ``Hello, world!''.
Most of the time you do not want to export the names of your extension's subroutines, because they might accidentally clash with other subroutines from other extensions or from the calling program itself.
Run h2xs -A -n Test3
. This will create a Test3 directory with a file
Test3.xs underneath it. Add the following to the end of the XS file:
Edit the file Makefile.PL so that the corresponding line looks like this:
Generate the Makefile and run make. The test script test3.pl looks like:
Notice the output from trying to send a constant in to the routine. Perl reports:
Perl won't let you change the value of two to, say, three, unlike a FORTRAN compiler from long, long ago!
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.
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. Otherwise, you specify which variables used in the XSUB function should be placed into the respective Perl variables passed in.
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 the .c file created for the Test3 extension.
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 perlguts; we'll talk more later about what that ``ST(0)'' means in the section on the argument stack.
Rather than attempt to find a library that exists on all systems, we'll first create our own C library, then create an XSUB to it.
Let's create the files libtest4.h and libtest4.c as follows:
Now let's compile it into a library. Since we'll be eventually using this archive to create a shared library, be sure to use the correct flags to generate position-independent code. In HP-UX, that's:
Now let's move the libtest4.h and libtest.a files into a sub-directory under /tmp, so we don't interfere with anything.
Okay, now that we have a header file and a library, let's begin actually writing the extension.
Run h2xs -n Test4 /tmp/test4/include/libtest4.h
(notice we are no longer
specifying -A as an argument). This will create a Test4 directory with a file
Test4.xs underneath it. If we look at it now, we'll see some interesting
things have been added to the various files.
constant
routine is to make the values that are #define'd in the
header file available to the Perl script by calling &main::TESTVAL
.
There's also some XS code to allow calls to the constant
routine.
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:
Now we must tell our Makefile template where our new library is. Edit the Makefile.PL and change the following line:
This specifies that we want the library test4 linked into our XSUB, and that it should also look in the directory /tmp/test4.
Let's also change the following line in the Makefile.PL to this:
and also change the #include in test4.xs to be:
Now we don't have to specify the absolute path of the header file in the .xs file, relying on the Makefile to tell the compiler where to find the header files. This is generally considered a Good Thing.
Okay, let's create the Makefile, and run make. You can ignore a message that may look like:
If you forgot to create the typemap file, you might see output that looks like this:
This error means that you have used a C datatype that xsubpp doesn't know how to convert between Perl and C. You'll have to create a typemap file to tell xsubpp how to do the conversions.
Jeff Okamoto <okamoto@hpcc123.corp.hp.com>