home *** CD-ROM | disk | FTP | other *** search
- <!-- $RCSfile$$Revision$$Date$ -->
- <!-- $Log$ -->
- <HTML>
- <TITLE> PERLAPI </TITLE>
- <h2>NAME</h2>
- perlapi - Perl 5 application programming interface for C extensions
- <p><h2>DESCRIPTION</h2>
- <h3>Introduction</h3>
- XS is a language used to create an extension interface
- between Perl and some C library which one wishes to use with
- Perl. The XS interface is combined with the library to
- create a new library which can be linked to Perl. An <B>XSUB</B>
- is a function in the XS language and is the core component
- of the Perl application interface.
- <p>The XS compiler is called <B>xsubpp</B>. This compiler will embed
- the constructs necessary to let an XSUB, which is really a C
- function in disguise, manipulate Perl values and creates the
- glue necessary to let Perl access the XSUB. The compiler
- uses <B>typemaps</B> to determine how to map C function parameters
- and variables to Perl values. The default typemap handles
- many common C types. A supplement typemap must be created
- to handle special structures and types for the library being
- linked.
- <p>Many of the examples which follow will concentrate on creating an
- interface between Perl and the ONC+RPC bind library functions.
- Specifically, the rpcb_gettime() function will be used to demonstrate many
- features of the XS language. This function has two parameters; the first
- is an input parameter and the second is an output parameter. The function
- also returns a status value.
- <p><pre>
- bool_t rpcb_gettime(const char *host, time_t *timep);
- </pre>
- From C this function will be called with the following
- statements.
- <p><pre>
- #include <rpc/rpc.h>
- bool_t status;
- time_t timep;
- status = rpcb_gettime( "localhost", &timep );
- </pre>
- If an XSUB is created to offer a direct translation between this function
- and Perl, then this XSUB will be used from Perl with the following code.
- The $status and $timep variables will contain the output of the function.
- <p><pre>
- use RPC;
- $status = rpcb_gettime( "localhost", $timep );
- </pre>
- The following XS file shows an XS subroutine, or XSUB, which
- demonstrates one possible interface to the rpcb_gettime()
- function. This XSUB represents a direct translation between
- C and Perl and so preserves the interface even from Perl.
- This XSUB will be invoked from Perl with the usage shown
- above. Note that the first three #include statements, for
- <B>EXTERN.h</B>, <B>perl.h</B>, and <B>XSUB.h</B>, will always be present at the
- beginning of an XS file. This approach and others will be
- expanded later in this document.
- <p><pre>
- #include "EXTERN.h"
- #include "perl.h"
- #include "XSUB.h"
- #include <rpc/rpc.h>
- </pre>
- <pre>
- MODULE = RPC PACKAGE = RPC
- </pre>
- <pre>
- bool_t
- rpcb_gettime(host,timep)
- char * host
- time_t &timep
- OUTPUT:
- timep
- </pre>
- Any extension to Perl, including those containing XSUBs,
- should have a Perl module to serve as the bootstrap which
- pulls the extension into Perl. This module will export the
- extension's functions and variables to the Perl program and
- will cause the extension's XSUBs to be linked into Perl.
- The following module will be used for most of the examples
- in this document and should be used from Perl with the
- <A HREF="perlfunc.html#perlfunc_263">use</A>
-
- command as shown earlier. Perl modules are explained in
- more detail later in this document.
- <p><pre>
- package RPC;
- </pre>
- <pre>
- require Exporter;
- require DynaLoader;
- @ISA = qw(Exporter DynaLoader);
- @EXPORT = qw( rpcb_gettime );
- </pre>
- <pre>
- bootstrap RPC;
- 1;
- </pre>
- Throughout this document a variety of interfaces to the rpcb_gettime()
- XSUB will be explored. The XSUBs will take their parameters in different
- orders or will take different numbers of parameters. In each case the
- XSUB is an abstraction between Perl and the real C rpcb_gettime()
- function, and the XSUB must always ensure that the real rpcb_gettime()
- function is called with the correct parameters. This abstraction will
- allow the programmer to create a more Perl-like interface to the C
- function.
- <p><h3>The Anatomy of an XSUB</h3>
- The following XSUB allows a Perl program to access a C library function called sin(). The XSUB will imitate the C
- function which takes a single argument and returns a single
- value.
- <p><pre>
- double
- sin(x)
- double<tab>x
- </pre>
- The compiler expects a tab between the parameter name and its type, and
- any or no whitespace before the type. When using C pointers the
- indirection operator
- <A HREF="perlcall.html#perlcall_39">*</A>
- should be considered part of the type and the
- address operator <B>&</B> should be considered part of the variable, as is
- demonstrated in the rpcb_gettime() function above. See the section on
- typemaps for more about handling qualifiers and unary operators in C
- types.
- <p>The parameter list of a function must not have whitespace
- after the open-parenthesis or before the close-parenthesis.
- <p><pre>
- INCORRECT CORRECT
- </pre>
- <pre>
- double double
- sin( x ) sin(x)
- double x double x
- </pre>
- The function name and the return type must be placed on
- separate lines.
- <p><pre>
- INCORRECT CORRECT
- </pre>
- <pre>
- double sin(x) double
- double x sin(x)
- double x
- </pre>
- <h3>The Argument Stack</h3>
- The argument stack is used to store the values which are
- sent as parameters to the XSUB and to store the XSUB's
- return value. In reality all Perl functions keep their
- values on this stack at the same time, each limited to its
- own range of positions on the stack. In this document the
- first position on that stack which belongs to the active
- function will be referred to as position 0 for that function.
- <p>XSUBs refer to their stack arguments with the macro <B>ST(x)</B>, where <I>x</I> refers
- to a position in this XSUB's part of the stack. Position 0 for that
- function would be known to the XSUB as ST(0). The XSUB's incoming
- parameters and outgoing return values always begin at ST(0). For many
- simple cases the <B>xsubpp</B> compiler will generate the code necessary to
- handle the argument stack by embedding code fragments found in the
- typemaps. In more complex cases the programmer must supply the code.
- <p><h3>The RETVAL Variable</h3>
- The RETVAL variable is a magic variable which always matches
- the return type of the C library function. The <B>xsubpp</B> compiler will
- supply this variable in each XSUB and by default will use it to hold the
- return value of the C library function being called. In simple cases the
- value of RETVAL will be placed in ST(0) of the argument stack where it can
- be received by Perl as the return value of the XSUB.
- <p>If the XSUB has a return type of <B>void</B> then the compiler will
- not supply a RETVAL variable for that function. When using
- the PPCODE: directive the RETVAL variable may not be needed.
- <p><h3>The MODULE Keyword</h3>
- The MODULE keyword is used to start the XS code and to
- specify the package of the functions which are being
- defined. All text preceding the first MODULE keyword is
- considered C code and is passed through to the output
- untouched. Every XS module will have a bootstrap function
- which is used to hook the XSUBs into Perl. The package name
- of this bootstrap function will match the value of the last
- MODULE statement in the XS source files. The value of
- MODULE should always remain constant within the same XS
- file, though this is not required.
- <p>The following example will start the XS code and will place
- all functions in a package named RPC.
- <p><pre>
- MODULE = RPC
- </pre>
- <h3>The PACKAGE Keyword</h3>
- When functions within an XS source file must be separated into packages
- the PACKAGE keyword should be used. This keyword is used with the MODULE
- keyword and must follow immediately after it when used.
- <p><pre>
- MODULE = RPC PACKAGE = RPC
- </pre>
- <pre>
- [ XS code in package RPC ]
- </pre>
- <pre>
- MODULE = RPC PACKAGE = RPCB
- </pre>
- <pre>
- [ XS code in package RPCB ]
- </pre>
- <pre>
- MODULE = RPC PACKAGE = RPC
- </pre>
- <pre>
- [ XS code in package RPC ]
- </pre>
- Although this keyword is optional and in some cases provides redundant
- information it should always be used. This keyword will ensure that the
- XSUBs appear in the desired package.
- <p><h3>The PREFIX Keyword</h3>
- The PREFIX keyword designates prefixes which should be
- removed from the Perl function names. If the C function is
- <B>rpcb_gettime()</B> and the PREFIX value is <B>rpcb_</B> then Perl will
- see this function as <B>gettime()</B>.
- <p>This keyword should follow the PACKAGE keyword when used.
- If PACKAGE is not used then PREFIX should follow the MODULE
- keyword.
- <p><pre>
- MODULE = RPC PREFIX = rpc_
- </pre>
- <pre>
- MODULE = RPC PACKAGE = RPCB PREFIX = rpcb_
- </pre>
- <h3>The OUTPUT: Keyword</h3>
- The OUTPUT: keyword indicates that certain function parameters should be
- updated (new values made visible to Perl) when the XSUB terminates or that
- certain values should be returned to the calling Perl function. For
- simple functions, such as the sin() function above, the RETVAL variable is
- automatically designated as an output value. In more complex functions
- the <B>xsubpp</B> compiler will need help to determine which variables are output
- variables.
- <p>This keyword will normally be used to complement the CODE: keyword.
- The RETVAL variable is not recognized as an output variable when the
- CODE: keyword is present. The OUTPUT: keyword is used in this
- situation to tell the compiler that RETVAL really is an output
- variable.
- <p>The OUTPUT: keyword can also be used to indicate that function parameters
- are output variables. This may be necessary when a parameter has been
- modified within the function and the programmer would like the update to
- be seen by Perl. If function parameters are listed under OUTPUT: along
- with the RETVAL variable then the RETVAL variable must be the last one
- listed.
- <p><pre>
- bool_t
- rpcb_gettime(host,timep)
- char * host
- time_t &timep
- OUTPUT:
- timep
- </pre>
- The OUTPUT: keyword will also allow an output parameter to
- be mapped to a matching piece of code rather than to a
- typemap.
- <p><pre>
- bool_t
- rpcb_gettime(host,timep)
- char * host
- time_t &timep
- OUTPUT:
- timep<tab>sv_setnv(ST(1), (double)timep);
- </pre>
- <h3>The CODE: Keyword</h3>
- This keyword is used in more complicated XSUBs which require
- special handling for the C function. The RETVAL variable is
- available but will not be returned unless it is specified
- under the OUTPUT: keyword.
- <p>The following XSUB is for a C function which requires special handling of
- its parameters. The Perl usage is given first.
- <p><pre>
- $status = rpcb_gettime( "localhost", $timep );
- </pre>
- The XSUB follows.
- <p><pre>
- bool_t rpcb_gettime(host,timep)
- char * host
- time_t timep
- CODE:
- RETVAL = rpcb_gettime( host, &timep );
- OUTPUT:
- timep
- RETVAL
- </pre>
- In many of the examples shown here the CODE: block (and
- other blocks) will often be contained within braces ( <B>{</B> and
- <B>}</B> ). This protects the CODE: block from complex INPUT
- typemaps and ensures the resulting C code is legal.
- <p><h3>The NO_INIT Keyword</h3>
- The NO_INIT keyword is used to indicate that a function
- parameter is being used only as an output value. The <B>xsubpp</B>
- compiler will normally generate code to read the values of
- all function parameters from the argument stack and assign
- them to C variables upon entry to the function. NO_INIT
- will tell the compiler that some parameters will be used for
- output rather than for input and that they will be handled
- before the function terminates.
- <p>The following example shows a variation of the rpcb_gettime() function.
- This function uses the timep variable only as an output variable and does
- not care about its initial contents.
- <p><pre>
- bool_t
- rpcb_gettime(host,timep)
- char * host
- time_t &timep = NO_INIT
- OUTPUT:
- timep
- </pre>
- <h3>Initializing Function Parameters</h3>
- Function parameters are normally initialized with their
- values from the argument stack. The typemaps contain the
- code segments which are used to transfer the Perl values to
- the C parameters. The programmer, however, is allowed to
- override the typemaps and supply alternate initialization
- code.
- <p>The following code demonstrates how to supply initialization code for
- function parameters. The initialization code is eval'd by the compiler
- before it is added to the output so anything which should be interpreted
- literally, such as double quotes, must be protected with backslashes.
- <p><pre>
- bool_t
- rpcb_gettime(host,timep)
- char * host = (char *)SvPV(ST(0),na);
- time_t &timep = 0;
- OUTPUT:
- timep
- </pre>
- This should not be used to supply default values for parameters. One
- would normally use this when a function parameter must be processed by
- another library function before it can be used. Default parameters are
- covered in the next section.
- <p><h3>Default Parameter Values</h3>
- Default values can be specified for function parameters by
- placing an assignment statement in the parameter list. The
- default value may be a number or a string. Defaults should
- always be used on the right-most parameters only.
- <p>To allow the XSUB for rpcb_gettime() to have a default host
- value the parameters to the XSUB could be rearranged. The
- XSUB will then call the real rpcb_gettime() function with
- the parameters in the correct order. Perl will call this
- XSUB with either of the following statements.
- <p><pre>
- $status = rpcb_gettime( $timep, $host );
- </pre>
- <pre>
- $status = rpcb_gettime( $timep );
- </pre>
- The XSUB will look like the code which follows. A CODE:
- block is used to call the real rpcb_gettime() function with
- the parameters in the correct order for that function.
- <p><pre>
- bool_t
- rpcb_gettime(timep,host="localhost")
- char * host
- time_t timep = NO_INIT
- CODE:
- RETVAL = rpcb_gettime( host, &timep );
- OUTPUT:
- timep
- RETVAL
- </pre>
- <h3>Variable-length Parameter Lists</h3>
- XSUBs can have variable-length parameter lists by specifying an ellipsis
- <B>(...)</B> in the parameter list. This use of the ellipsis is similar to that
- found in ANSI C. The programmer is able to determine the number of
- arguments passed to the XSUB by examining the <B>items</B> variable which the
- <B>xsubpp</B> compiler supplies for all XSUBs. By using this mechanism one can
- create an XSUB which accepts a list of parameters of unknown length.
- <p>The <I>host</I> parameter for the rpcb_gettime() XSUB can be
- optional so the ellipsis can be used to indicate that the
- XSUB will take a variable number of parameters. Perl should
- be able to call this XSUB with either of the following statments.
- <p><pre>
- $status = rpcb_gettime( $timep, $host );
- </pre>
- <pre>
- $status = rpcb_gettime( $timep );
- </pre>
- The XS code, with ellipsis, follows.
- <p><pre>
- bool_t
- rpcb_gettime(timep, ...)
- time_t timep = NO_INIT
- CODE:
- {
- char *host = "localhost";
- </pre>
- <pre>
- if( items > 1 )
- host = (char *)SvPV(ST(1), na);
- RETVAL = rpcb_gettime( host, &timep );
- }
- OUTPUT:
- timep
- RETVAL
- </pre>
- <h3>The PPCODE: Keyword</h3>
- The PPCODE: keyword is an alternate form of the CODE: keyword and is used
- to tell the <B>xsubpp</B> compiler that the programmer is supplying the code to
- control the argument stack for the XSUBs return values. Occassionally one
- will want an XSUB to return a list of values rather than a single value.
- In these cases one must use PPCODE: and then explicitly push the list of
- values on the stack. The PPCODE: and CODE: keywords are not used
- together within the same XSUB.
- <p>The following XSUB will call the C rpcb_gettime() function
- and will return its two output values, timep and status, to
- Perl as a single list.
- <p><pre>
- void rpcb_gettime(host)
- char * host
- PPCODE:
- {
- time_t timep;
- bool_t status;
- status = rpcb_gettime( host, &timep );
- EXTEND(sp, 2);
- PUSHs(sv_2mortal(newSVnv(status)));
- PUSHs(sv_2mortal(newSVnv(timep)));
- }
- </pre>
- Notice that the programmer must supply the C code necessary
- to have the real rpcb_gettime() function called and to have
- the return values properly placed on the argument stack.
- <p>The <B>void</B> return type for this function tells the <B>xsubpp</B> compiler that
- the RETVAL variable is not needed or used and that it should not be created.
- In most scenarios the void return type should be used with the PPCODE:
- directive.
- <p>The EXTEND() macro is used to make room on the argument
- stack for 2 return values. The PPCODE: directive causes the
- <B>xsubpp</B> compiler to create a stack pointer called <B>sp</B>, and it
- is this pointer which is being used in the EXTEND() macro.
- The values are then pushed onto the stack with the PUSHs()
- macro.
- <p>Now the rpcb_gettime() function can be used from Perl with
- the following statement.
- <p><pre>
- ($status, $timep) = rpcb_gettime("localhost");
- </pre>
- <h3>Returning Undef And Empty Lists</h3>
- Occassionally the programmer will want to simply return
-
- <A HREF="perlfunc.html#perlfunc_258">undef</A>
- or an empty list if a function fails rather than a
- separate status value. The rpcb_gettime() function offers
- just this situation. If the function succeeds we would like
- to have it return the time and if it fails we would like to
- have undef returned. In the following Perl code the value
- of $timep will either be undef or it will be a valid time.
- <p><pre>
- $timep = rpcb_gettime( "localhost" );
- </pre>
- The following XSUB uses the <B>void</B> return type to disable the generation of
- the RETVAL variable and uses a CODE: block to indicate to the compiler
- that the programmer has supplied all the necessary code. The
- sv_newmortal() call will initialize the return value to undef, making that
- the default return value.
- <p><pre>
- void
- rpcb_gettime(host)
- char * host
- CODE:
- {
- time_t timep;
- bool_t x;
- ST(0) = sv_newmortal();
- if( rpcb_gettime( host, &timep ) )
- sv_setnv( ST(0), (double)timep);
- }
- </pre>
- The next example demonstrates how one would place an explicit undef in the
- return value, should the need arise.
- <p><pre>
- void
- rpcb_gettime(host)
- char * host
- CODE:
- {
- time_t timep;
- bool_t x;
- ST(0) = sv_newmortal();
- if( rpcb_gettime( host, &timep ) ){
- sv_setnv( ST(0), (double)timep);
- }
- else{
- ST(0) = &sv_undef;
- }
- }
- </pre>
- To return an empty list one must use a PPCODE: block and
- then not push return values on the stack.
- <p><pre>
- void
- rpcb_gettime(host)
- char * host
- PPCODE:
- {
- time_t timep;
- if( rpcb_gettime( host, &timep ) )
- PUSHs(sv_2mortal(newSVnv(timep)));
- else{
- /* Nothing pushed on stack, so an empty */
- /* list is implicitly returned. */
- }
- }
- </pre>
- <h3>The CLEANUP: Keyword</h3>
- This keyword can be used when an XSUB requires special cleanup procedures
- before it terminates. When the CLEANUP: keyword is used it must follow
- any CODE:, PPCODE:, or OUTPUT: blocks which are present in the XSUB. The
- code specified for the cleanup block will be added as the last statements
- in the XSUB.
- <p><h3>The BOOT: Keyword</h3>
- The BOOT: keyword is used to add code to the extension's bootstrap
- function. The bootstrap function is generated by the <B>xsubpp</B> compiler and
- normally holds the statements necessary to register any XSUBs with Perl.
- With the BOOT: keyword the programmer can tell the compiler to add extra
- statements to the bootstrap function.
- <p>This keyword may be used any time after the first MODULE keyword and should
- appear on a line by itself. The first blank line after the keyword will
- terminate the code block.
- <p><pre>
- BOOT:
- # The following message will be printed when the
- # bootstrap function executes.
- printf("Hello from the bootstrap!\n");
- </pre>
- <h3>Inserting Comments and C Preprocessor Directives</h3>
- Comments and C preprocessor directives are allowed within
- CODE:, PPCODE:, BOOT:, and CLEANUP: blocks. The compiler
- will pass the preprocessor directives through untouched and
- will remove the commented lines. Comments can be added to
- XSUBs by placing a <B>#</B> at the beginning of the line. Care
- should be taken to avoid making the comment look like a C
- preprocessor directive, lest it be interpreted as such.
- <p><h3>Using XS With C++</h3>
- If a function is defined as a C++ method then it will assume
- its first argument is an object pointer. The object pointer
- will be stored in a variable called THIS. The object should
- have been created by C++ with the new() function and should
- be blessed by Perl with the sv_setptrobj() macro. The
- blessing of the object by Perl can be handled by the
- T_PTROBJ typemap.
- <p>If the method is defined as static it will call the C++
- function using the class::method() syntax. If the method is not static
- the function will be called using the THIS->method() syntax.
- <p><h3>Perl Variables</h3>
- The following demonstrates how the Perl variable $host can
- be accessed from an XSUB. The function <B>perl_get_sv()</B> is
- used to obtain a pointer to the variable, known as an <B>SV</B>
- (Scalar Variable) internally. The package name <B>RPC</B> will be
- added to the name of the variable so perl_get_sv() will know
- in which package $host can be found. If the package name is
- not supplied then perl_get_sv() will search package <B>main</B> for
- the variable. The macro <B>SvPVX()</B> is then used to dereference
- the SV to obtain a <B>char*</B> pointer to its contents.
- <p><pre>
- void
- rpcb_gettime()
- PPCODE:
- {
- char *host;
- SV *hostsv;
- time_t timep;
- </pre>
- <pre>
- hostsv = perl_get_sv( "RPC::host", FALSE );
- if( hostsv != NULL ){
- host = SvPVX( hostsv );
- if( rpcb_gettime( host, &timep ) )
- PUSHs(sv_2mortal(newSVnv(timep)));
- }
- }
- </pre>
- This Perl code can be used to call that XSUB.
- <p><pre>
- $RPC::host = "localhost";
- $timep = rpcb_gettime();
- </pre>
- In the above example the SV contained a C <B>char*</B> but a Perl
- scalar variable may also contain numbers and references. If
- the SV is expected to have a C
- <A HREF="perlfunc.html#perlfunc_156">int</A>
- then the macro <B>SvIVX()</B>
- should be used to dereference the SV. When the SV contains
- a C double then <B>SvNVX()</B> should be used.
- <p>The macro <B>SvRV()</B> can be used to dereference an SV when it is a Perl
- reference. The result will be another SV which points to the actual Perl
- variable. This can then be dereferenced with SvPVX(), SvNVX(), or
- SvIVX(). The following XSUB will use SvRV().
- <p><pre>
- void rpcb_gettime()
- PPCODE:
- {
- char *host;
- SV *rv;
- SV *hostsv;
- time_t timep;
- </pre>
- <pre>
- rv = perl_get_sv( "RPC::host", FALSE );
- if( rv != NULL ){
- hostsv = SvRV( rv );
- host = SvPVX( hostsv );
- if( rpcb_gettime( host, &timep ) )
- PUSHs(sv_2mortal(newSVnv(timep)));
- }
- }
- </pre>
- This Perl code will create a variable $RPC::host which is a
- reference to $MY::host. The variable $MY::host contains the
- hostname which will be used.
- <p><pre>
- $MY::host = "localhost";
- $RPC::host = \$MY::host;
- $timep = rpcb_gettime();
- </pre>
- The second argument to perl_get_sv() will normally be <B>FALSE</B>
- as shown in the above examples. An argument of <B>TRUE</B> will
- cause variables to be created if they do not already exist.
- One should not use TRUE unless steps are taken to deal with
- a possibly empty SV.
- <p>XSUBs may use <B>perl_get_av()</B>, <B>perl_get_hv()</B>, and <B>perl_get_cv()</B> to
- access Perl arrays, hashes, and code values.
- <p><h3>Interface Stategy</h3>
- When designing an interface between Perl and a C library a straight
- translation from C to XS is often sufficient. The interface will often be
- very C-like and occasionally nonintuitive, especially when the C function
- modifies one of its parameters. In cases where the programmer wishes to
- create a more Perl-like interface the following strategy may help to
- identify the more critical parts of the interface.
- <p>Identify the C functions which modify their parameters. The XSUBs for
- these functions may be able to return lists to Perl, or may be
- candidates to return undef or an empty list in case of failure.
- <p>Identify which values are used only by the C and XSUB functions
- themselves. If Perl does not need to access the contents of the value
- then it may not be necessary to provide a translation for that value
- from C to Perl.
- <p>Identify the pointers in the C function parameter lists and return
- values. Some pointers can be handled in XS with the & unary operator on
- the variable name while others will require the use of the * operator on
- the type name. In general it is easier to work with the & operator.
- <p>Identify the structures used by the C functions. In many
- cases it may be helpful to use the T_PTROBJ typemap for
- these structures so they can be manipulated by Perl as
- blessed objects.
- <p><h3>The Perl Module</h3>
- The Perl module is the link between the extension library,
- which was generated from XS code, and the Perl interpreter.
- The module is used to tell Perl what the extension library
- contains. The name and package of the module should match
- the name of the library.
- <p>The following is a Perl module for an extension containing
- some ONC+ RPC bind library functions.
- <p><pre>
- package RPC;
- </pre>
- <pre>
- require Exporter;
- require DynaLoader;
- @ISA = qw(Exporter DynaLoader);
- @EXPORT = qw( rpcb_gettime rpcb_getmaps rpcb_getaddr
- rpcb_rmtcall rpcb_set rpcb_unset );
- </pre>
- <pre>
- bootstrap RPC;
- 1;
- </pre>
- The RPC extension contains the functions found in the
- @EXPORT list. By using the <B>Exporter</B> module the RPC module
- can make these function names visible to the rest of the
- Perl program. The <B>DynaLoader</B> module will allow the RPC
- module to bootstrap the extension library. To load this
- extension and make the functions available, the following
- Perl statement should be used.
- <p><pre>
- use RPC;
- </pre>
- For more information about the DynaLoader consult its documentation in the
- ext/DynaLoader directory in the Perl source.
- <p><h3>Perl Objects And C Structures</h3>
- When dealing with C structures one should select either
- <B>T_PTROBJ</B> or <B>T_PTRREF</B> for the XS type. Both types are
- designed to handle pointers to complex objects. The
- T_PTRREF type will allow the Perl object to be unblessed
- while the T_PTROBJ type requires that the object be blessed.
- By using T_PTROBJ one can achieve a form of type-checking
- since the XSUB will attempt to verify that the Perl object
- is of the expected type.
- <p>The following XS code shows the getnetconfigent() function which is used
- with ONC TIRPC. The getnetconfigent() function will return a pointer to a
- C structure and has the C prototype shown below. The example will
- demonstrate how the C pointer will become a Perl reference. Perl will
- consider this reference to be a pointer to a blessed object and will
- attempt to call a destructor for the object. A destructor will be
- provided in the XS source to free the memory used by getnetconfigent().
- Destructors in XS can be created by specifying an XSUB function whose name
- ends with the word <B>DESTROY</B>. XS destructors can be used to free memory
- which may have been malloc'd by another XSUB.
- <p><pre>
- struct netconfig *getnetconfigent(const char *netid);
- </pre>
- A <B>typedef</B> will be created for <B>struct netconfig</B>. The Perl
- object will be blessed in a class matching the name of the C
- type, with the tag <B>Ptr</B> appended, and the name should not
- have embedded spaces if it will be a Perl package name. The
- destructor will be placed in a class corresponding to the
- class of the object and the PREFIX keyword will be used to
- trim the name to the word DESTROY as Perl will expect.
- <p><pre>
- typedef struct netconfig Netconfig;
- </pre>
- <pre>
- MODULE = RPC PACKAGE = RPC
- </pre>
- <pre>
- Netconfig *
- getnetconfigent(netid)
- char * netid
- </pre>
- <pre>
- MODULE = RPC PACKAGE = NetconfigPtr PREFIX = rpcb_
- </pre>
- <pre>
- void
- rpcb_DESTROY(netconf)
- Netconfig * netconf
- CODE:
- printf("Now in NetconfigPtr::DESTROY\n");
- free( netconf );
- </pre>
- This example requires the following typemap entry. Consult the typemap
- section for more information about adding new typemaps for an extension.
- <p><pre>
- TYPEMAP
- Netconfig * T_PTROBJ
- </pre>
- This example will be used with the following Perl statements.
- <p><pre>
- use RPC;
- $netconf = getnetconfigent("udp");
- </pre>
- When Perl destroys the object referenced by $netconf it will send the
- object to the supplied XSUB DESTROY function. Perl cannot determine, and
- does not care, that this object is a C struct and not a Perl object. In
- this sense, there is no difference between the object created by the
- getnetconfigent() XSUB and an object created by a normal Perl subroutine.
- <p><h3>C Headers and Perl</h3>
- The <B>h2xs</B> compiler is designed to convert C header files in
- /usr/include into Perl extensions. This compiler will
- create a directory under the <B>ext</B> directory of the Perl
- source and will populate it with a Makefile, a Perl Module,
- an XS source file, and a MANIFEST file.
- <p>The following command will create an extension called <B>Rusers</B>
- from the <rpcsvc/rusers.h> header.
- <p><pre>
- h2xs rpcsvc/rusers
- </pre>
- When the Rusers extension has been compiled and installed
- Perl can use it to retrieve any <B>#define</B> statements which
- were in the C header.
- <p><pre>
- use Rusers;
- print "RPC program number for rusers service: ";
- print &RUSERSPROG, "\n";
- </pre>
- <h3>Creating A New Extension</h3>
- The <B>h2xs</B> compiler can generate template source files and
- Makefiles. These templates offer a suitable starting point
- for most extensions. The following example demonstrates how
- one might use <B>h2xs</B> to create an extension containing the RPC
- functions in this document.
- <p>The extension will not use autoloaded functions and will not define
- constants, so the <B>-A</B> option will be given to <B>h2xs</B>. When run from the
- Perl source directory, the <B>h2xs</B> compiler will create the directory
- ext/RPC and will populate it with files called RPC.xs, RPC.pm, Makefile.PL,
- and MANIFEST. The XS code for the RPC functions should be added to the
- RPC.xs file. The @EXPORT list in RPC.pm should be updated to include the
- functions from RPC.xs.
- <p><pre>
- h2xs -An RPC
- </pre>
- To compile the extension for dynamic loading the following
- command should be executed from the ext/RPC directory.
- <p><pre>
- make dynamic
- </pre>
- If the extension will be statically linked into the Perl
- binary then the makefile (use <B>makefile</B>, not <B>Makefile</B>) in the
- Perl source directory should be edited to add <B>ext/RPC/RPC.a</B>
- to the <B>static_ext</B> variable. Before making this change Perl
- should have already been built. After the makefile has been
- updated the following command should be executed from the
- Perl source directory.
- <p><pre>
- make
- </pre>
- Perl's <B>Configure</B> script can also be used to add extensions. The extension
- should be placed in the <B>ext</B> directory under the Perl source before Perl
- has been built and prior to running Configure. When Configure is run it
- will find the extension along with the other extensions in the <B>ext</B>
- directory and will add it to the list of extensions to be built. When make
- is run the extension will be built along with the other extensions.
- <p>Configure recognizes extensions if they have an XS source
- file which matches the name of the extension directory. If
- the extension directory includes a MANIFEST file Configure
- will search that file for any <B>.SH</B> files and extract them
- after it extracts all the other .SH files listed in the main
- MANIFEST. The main Perl Makefile will then run <B>make</B> in the
- extension's directory if it finds an XS file matching the
- name of the extension's directory.
- <p><h3>The Typemap</h3>
- The typemap is a collection of code fragments which are used by the <B>xsubpp</B>
- compiler to map C function parameters and values to Perl values. The
- typemap file may consist of three sections labeled <B>TYPEMAP</B>, <B>INPUT</B>, and
- <B>OUTPUT</B>. The INPUT section tells the compiler how to translate Perl values
- into variables of certain C types. The OUTPUT section tells the compiler
- how to translate the values from certain C types into values Perl can
- understand. The TYPEMAP section tells the compiler which of the INPUT and
- OUTPUT code fragments should be used to map a given C type to a Perl value.
- Each of the sections of the typemap must be preceded by one of the TYPEMAP,
- INPUT, or OUTPUT keywords.
- <p>The default typemap in the <B>ext</B> directory of the Perl source contains many
- useful types which can be used by Perl extensions. Some extensions define
- additional typemaps which they keep in their own directory. These
- additional typemaps may reference INPUT and OUTPUT maps in the main
- typemap. The <B>xsubpp</B> compiler will allow the extension's own typemap to
- override any mappings which are in the default typemap.
- <p>Most extensions which require a custom typemap will need only the TYPEMAP
- section of the typemap file. The custom typemap used in the
- getnetconfigent() example shown earlier demonstrates what may be the typical
- use of extension typemaps. That typemap is used to equate a C structure
- with the T_PTROBJ typemap. The typemap used by getnetconfigent() is shown
- here. Note that the C type is separated from the XS type with a tab and
- that the C unary operator
- <A HREF="perlcall.html#perlcall_39">*</A>
- is considered to be a part of the C type name.
- <p><pre>
- TYPEMAP
- Netconfig *<tab>T_PTROBJ
- </pre>
- <h2>EXAMPLES</h2>
- File <B>RPC.xs</B>: Interface to some ONC+ RPC bind library functions.
- <p><pre>
- #include "EXTERN.h"
- #include "perl.h"
- #include "XSUB.h"
- </pre>
- <pre>
- #include <rpc/rpc.h>
- </pre>
- <pre>
- typedef struct netconfig Netconfig;
- </pre>
- <pre>
- MODULE = RPC PACKAGE = RPC
- </pre>
- <pre>
- void
- rpcb_gettime(host="localhost")
- char * host
- CODE:
- {
- time_t timep;
- ST(0) = sv_newmortal();
- if( rpcb_gettime( host, &timep ) )
- sv_setnv( ST(0), (double)timep );
- }
- </pre>
- <pre>
- Netconfig *
- getnetconfigent(netid="udp")
- char * netid
- </pre>
- <pre>
- MODULE = RPC PACKAGE = NetconfigPtr PREFIX = rpcb_
- </pre>
- <pre>
- void
- rpcb_DESTROY(netconf)
- Netconfig * netconf
- CODE:
- printf("NetconfigPtr::DESTROY\n");
- free( netconf );
- </pre>
- File <B>typemap</B>: Custom typemap for RPC.xs.
- <p><pre>
- TYPEMAP
- Netconfig * T_PTROBJ
- </pre>
- File <B>RPC.pm</B>: Perl module for the RPC extension.
- <p><pre>
- package RPC;
- </pre>
- <pre>
- require Exporter;
- require DynaLoader;
- @ISA = qw(Exporter DynaLoader);
- @EXPORT = qw(rpcb_gettime getnetconfigent);
- </pre>
- <pre>
- bootstrap RPC;
- 1;
- </pre>
- File <B>rpctest.pl</B>: Perl test program for the RPC extension.
- <p><pre>
- use RPC;
- </pre>
- <pre>
- $netconf = getnetconfigent();
- $a = rpcb_gettime();
- print "time = $a\n";
- print "netconf = $netconf\n";
- </pre>
- <pre>
- $netconf = getnetconfigent("tcp");
- $a = rpcb_gettime("poplar");
- print "time = $a\n";
- print "netconf = $netconf\n";
- </pre>
- <h2>AUTHOR</h2>
- Dean Roehrich <roehrich@cray.com>
- September 27, 1994<p>