Perl-Sensitive Sunglasses | |
PerlMonks |
perlman:perlxsby gods (Initiate) |
on Aug 25, 1999 at 06:50 UTC ( [id://409]=perlman: print w/replies, xml ) | Need Help?? |
perlxsCurrent Perl documentation can be found at perldoc.perl.org. Here is our local, out-dated (pre-5.6) version:
NAMEperlxs - XS language reference manual
DESCRIPTION
IntroductionXS 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 XSUB is a function in the XS language and is the core component of the Perl application interface. The XS compiler is called xsubpp. 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 typemaps 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. See the perlxstut manpage for a tutorial on the whole extension creation process. Note: For many extensions, Dave Beazley's SWIG system provides a significantly more convenient mechanism for creating the XS glue code. See http: for more information.
On The Road
Many of the examples which follow will concentrate on creating an interface between Perl and the
ONC+
RPC bind library functions. The
bool_t rpcb_gettime(const char *host, time_t *timep); From C this function will be called with the following statements.
#include <rpc/rpc.h> bool_t status; time_t timep; status = rpcb_gettime( "localhost", &timep );
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
use RPC; $status = rpcb_gettime( "localhost", $timep );
The following
XS file shows an
XS subroutine, or
XSUB, which demonstrates one possible interface to the
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include <rpc/rpc.h>
MODULE = RPC PACKAGE = RPC
bool_t rpcb_gettime(host,timep) char *host time_t &timep OUTPUT: timep 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 use command as shown earlier. Perl modules are explained in more detail later in this document.
package RPC;
require Exporter; require DynaLoader; @ISA = qw(Exporter DynaLoader); @EXPORT = qw( rpcb_gettime );
bootstrap RPC; 1;
Throughout this document a variety of interfaces to the
The Anatomy of an XSUB
The following
XSUB allows a Perl program to access a
C library function called
double sin(x) double x
When using
C pointers the indirection operator The function name and the return type must be placed on separate lines.
INCORRECT CORRECT
double sin(x) double double x sin(x) double x The function body may be indented or left-adjusted. The following example shows a function with its body left-adjusted. Most examples in this document will indent the body.
CORRECT
double sin(x) double x
The Argument StackThe 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.
XSUBs refer to their stack arguments with the macro ST(x), where x
refers to a position in this XSUB's part of the stack. Position 0 for that function would be known to the
XSUB as
The RETVAL Variable
The
RETVAL variable is a magic variable which always matches the return type of the
C library function. The
xsubpp 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
If the XSUB has a return type of perlman:perlguts then the compiler will not supply a RETVAL variable for that function. When using the PPCODE: directive the RETVAL variable is not needed, unless used explicitly.
If
PPCODE: directive is not used, perlman:perlguts return value should be used only for subroutines which do not return a
value, even if
CODE: directive is used which sets
Older versions of this document recommended to use perlman:perlguts return value in such cases. It was discovered that this could lead to segfaults in cases when
XSUB was
truely perlman:perlguts. This practice is now deprecated, and may be not supported at some future
version. Use the return value perlman:perlguts in such cases. (Currently
The MODULE KeywordThe 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. The following example will start the XS code and will place all functions in a package named RPC.
MODULE = RPC
The PACKAGE KeywordWhen 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.
MODULE = RPC PACKAGE = RPC
[ XS code in package RPC ]
MODULE = RPC PACKAGE = RPCB
[ XS code in package RPCB ]
MODULE = RPC PACKAGE = RPC
[ XS code in package RPC ] 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.
The PREFIX Keyword
The
PREFIX keyword designates prefixes which should be removed from the Perl function names. If the
C function is
This keyword should follow the PACKAGE keyword when used. If PACKAGE is not used then PREFIX should follow the MODULE keyword.
MODULE = RPC PREFIX = rpc_
MODULE = RPC PACKAGE = RPCB PREFIX = rpcb_
The OUTPUT: Keyword
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
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. 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.
bool_t rpcb_gettime(host,timep) char *host time_t &timep OUTPUT: timep The OUTPUT: keyword will also allow an output parameter to be mapped to a matching piece of code rather than to a typemap.
bool_t rpcb_gettime(host,timep) char *host time_t &timep OUTPUT: timep sv_setnv(ST(1), (double)timep);
xsubpp emits an automatic perlman:perlguts for all parameters in the
OUTPUT section of the
XSUB, except
RETVAL. This is the usually desired behavior, as it takes care of properly invoking 'set' magic on output parameters (needed for hash or array element parameters that must be created if they didn't exist). If for some reason, this behavior is not desired, the
OUTPUT section may contain a
The CODE: KeywordThis 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. The following XSUB is for a C function which requires special handling of its parameters. The Perl usage is given first.
$status = rpcb_gettime( "localhost", $timep ); The XSUB follows.
bool_t rpcb_gettime(host,timep) char *host time_t timep CODE: RETVAL = rpcb_gettime( host, &timep ); OUTPUT: timep RETVAL
The INIT: KeywordThe INIT: keyword allows initialization to be inserted into the XSUB before the compiler generates the call to the C function. Unlike the CODE: keyword above, this keyword does not affect the way the compiler handles RETVAL.
bool_t rpcb_gettime(host,timep) char *host time_t &timep INIT: printf("# Host is %s\n", host ); OUTPUT: timep
The NO_INIT KeywordThe NO_INIT keyword is used to indicate that a function parameter is being used only as an output value. The xsubpp 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.
The following example shows a variation of the
bool_t rpcb_gettime(host,timep) char *host time_t &timep = NO_INIT OUTPUT: timep
Initializing Function ParametersFunction 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 (or additional) initialization code.
The following code demonstrates how to supply initialization code for
function parameters. The initialization code is eval'd within double quotes
by the compiler before it is added to the output so anything which should
be interpreted literally [mainly
bool_t rpcb_gettime(host,timep) char *host = (char *)SvPV($arg,PL_na); time_t &timep = 0; OUTPUT: timep 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.
If the initialization begins with
bool_t rpcb_gettime(host,timep) time_t &timep ; /*\$v{time}=@{[$v{time}=$arg]}*/ char *host + SvOK($v{time}) ? SvPV($arg,PL_na) : NULL; OUTPUT: timep
Default Parameter ValuesDefault 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.
To allow the
XSUB for
$status = rpcb_gettime( $timep, $host );
$status = rpcb_gettime( $timep );
The
XSUB will look like the code which follows.
A
CODE: block is used to call the real
bool_t rpcb_gettime(timep,host="localhost") char *host time_t timep = NO_INIT CODE: RETVAL = rpcb_gettime( host, &timep ); OUTPUT: timep RETVAL
The PREINIT: KeywordThe PREINIT: keyword allows extra variables to be declared before the typemaps are expanded. If a variable is declared in a CODE: block then that variable will follow any typemap code. This may result in a C syntax error. To force the variable to be declared before the typemap code, place it into a PREINIT: block. The PREINIT: keyword may be used one or more times within an XSUB. The following examples are equivalent, but if the code is using complex typemaps then the first example is safer.
bool_t rpcb_gettime(timep) time_t timep = NO_INIT PREINIT: char *host = "localhost"; CODE: RETVAL = rpcb_gettime( host, &timep ); OUTPUT: timep RETVAL A correct, but error-prone example.
bool_t rpcb_gettime(timep) time_t timep = NO_INIT CODE: char *host = "localhost"; RETVAL = rpcb_gettime( host, &timep ); OUTPUT: timep RETVAL
The SCOPE: KeywordThe SCOPE: keyword allows scoping to be enabled for a particular XSUB. If enabled, the XSUB will invoke ENTER and LEAVE automatically.
To support potentially complex type mappings, if a typemap entry used by this
XSUB contains a comment like
To enable scoping:
SCOPE: ENABLE To disable scoping:
SCOPE: DISABLE
The INPUT: KeywordThe XSUB's parameters are usually evaluated immediately after entering the XSUB. The INPUT: keyword can be used to force those parameters to be evaluated a little later. The INPUT: keyword can be used multiple times within an XSUB and can be used to list one or more input variables. This keyword is used with the PREINIT: keyword.
The following example shows how the input parameter
bool_t rpcb_gettime(host,timep) char *host PREINIT: time_t tt; INPUT: time_t timep CODE: RETVAL = rpcb_gettime( host, &tt ); timep = tt; OUTPUT: timep RETVAL The next example shows each input parameter evaluated late.
bool_t rpcb_gettime(host,timep) PREINIT: time_t tt; INPUT: char *host PREINIT: char *h; INPUT: time_t timep CODE: h = host; RETVAL = rpcb_gettime( h, &tt ); timep = tt; OUTPUT: timep RETVAL
Variable-length Parameter Lists
XSUBs can have variable-length parameter lists by specifying an ellipsis
The host parameter for the
$status = rpcb_gettime( $timep, $host );
$status = rpcb_gettime( $timep ); The XS code, with ellipsis, follows.
bool_t rpcb_gettime(timep, ...) time_t timep = NO_INIT PREINIT: char *host = "localhost"; CODE: if( items > 1 ) host = (char *)SvPV(ST(1), PL_na); RETVAL = rpcb_gettime( host, &timep ); OUTPUT: timep RETVAL
The C_ARGS: KeywordThe C_ARGS: keyword allows creating of XSUBS which have different calling sequence from Perl than from C, without a need to write CODE: or CPPCODE: section. The contents of the C_ARGS: paragraph is put as the argument to the called C function without any change. For example, suppose that C function is declared as
symbolic nth_derivative(int n, symbolic function, int flags);
and that the default flags are kept in a global
C variable
$second_deriv = $function->nth_derivative(2); To do this, declare the XSUB as
symbolic nth_derivative(function, n) symbolic function int n C_ARGS: n, function, default_flags
The PPCODE: KeywordThe PPCODE: keyword is an alternate form of the CODE: keyword and is used to tell the xsubpp compiler that the programmer is supplying the code to control the argument stack for the XSUBs return values. Occasionally 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.
The following
XSUB will call the
C
void rpcb_gettime(host) char *host PREINIT: time_t timep; bool_t status; PPCODE: status = rpcb_gettime( host, &timep ); EXTEND(SP, 2); PUSHs(sv_2mortal(newSViv(status))); PUSHs(sv_2mortal(newSViv(timep)));
Notice that the programmer must supply the
C code necessary to have the real
The perlman:perlguts return type for this function tells the xsubpp 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.
The
Now the
($status, $timep) = rpcb_gettime("localhost"); When handling output parameters with a PPCODE section, be sure to handle 'set' magic properly. See the perlguts manpage for details about 'set' magic.
Returning Undef And Empty Lists
Occasionally the programmer will want to return simply
undef or an empty list if a function fails rather than a separate status value. The
$timep = rpcb_gettime( "localhost" );
The following
XSUB uses the perlman:perlguts return type as a mnemonic only, and uses a
CODE: block to indicate to the compiler that the programmer has supplied all the necessary code. The
SV * rpcb_gettime(host) char * host PREINIT: time_t timep; bool_t x; CODE: ST(0) = sv_newmortal(); if( rpcb_gettime( host, &timep ) ) sv_setnv( ST(0), (double)timep); The next example demonstrates how one would place an explicit undef in the return value, should the need arise.
SV * rpcb_gettime(host) char * host PREINIT: time_t timep; bool_t x; CODE: ST(0) = sv_newmortal(); if( rpcb_gettime( host, &timep ) ){ sv_setnv( ST(0), (double)timep); } else{ ST(0) = &PL_sv_undef; } To return an empty list one must use a PPCODE: block and then not push return values on the stack.
void rpcb_gettime(host) char *host PREINIT: time_t timep; PPCODE: if( rpcb_gettime( host, &timep ) ) PUSHs(sv_2mortal(newSViv(timep))); else{ /* Nothing pushed on stack, so an empty */ /* list is implicitly returned. */ } Some people may be inclined to include an explicit return in the above XSUB, rather than letting control fall through to the end. In those situations perlman:perlguts should be used, instead. This will ensure that the XSUB stack is properly adjusted. Consult perlman:perlguts for other perlman:perlguts macros.
The REQUIRE: KeywordThe REQUIRE: keyword is used to indicate the minimum version of the xsubpp compiler needed to compile the XS module. An XS module which contains the following statement will compile with only xsubpp version 1.922 or greater:
REQUIRE: 1.922
The CLEANUP: KeywordThis 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.
The BOOT: KeywordThe BOOT: keyword is used to add code to the extension's bootstrap function. The bootstrap function is generated by the xsubpp 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. 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.
BOOT: # The following message will be printed when the # bootstrap function executes. printf("Hello from the bootstrap!\n");
The VERSIONCHECK: Keyword
The
VERSIONCHECK: keyword corresponds to xsubpp's To enable version checking:
VERSIONCHECK: ENABLE To disable version checking:
VERSIONCHECK: DISABLE
The PROTOTYPES: Keyword
The
PROTOTYPES: keyword corresponds to xsubpp's To enable prototypes:
PROTOTYPES: ENABLE To disable prototypes:
PROTOTYPES: DISABLE
The PROTOTYPE: KeywordThis keyword is similar to the PROTOTYPES: keyword above but can be used to force xsubpp to use a specific prototype for the XSUB. This keyword overrides all other prototype options and keywords but affects only the current XSUB. Consult perlman:perlsub for information about Perl prototypes.
bool_t rpcb_gettime(timep, ...) time_t timep = NO_INIT PROTOTYPE: $;$ PREINIT: char *host = "localhost"; CODE: if( items > 1 ) host = (char *)SvPV(ST(1), PL_na); RETVAL = rpcb_gettime( host, &timep ); OUTPUT: timep RETVAL
The ALIAS: KeywordThe ALIAS: keyword allows an XSUB to have two or more unique Perl names and to know which of those names was used when it was invoked. The Perl names may be fully-qualified with package names. Each alias is given an index. The compiler will setup a variable called perlman:perlguts which contain the index of the alias which was used. When the XSUB is called with its declared name perlman:perlguts will be 0.
The following example will create aliases
bool_t rpcb_gettime(host,timep) char *host time_t &timep ALIAS: FOO::gettime = 1 BAR::getit = 2 INIT: printf("# ix = %d\n", ix ); OUTPUT: timep
The INTERFACE: KeywordThis keyword declares the current XSUB as a keeper of the given calling signature. If some text follows this keyword, it is considered as a list of functions which have this signature, and should be attached to XSUBs.
Say, if you have 4 functions
symbolic f(symbolic, symbolic); you code them all by using XSUB
symbolic interface_s_ss(arg1, arg2) symbolic arg1 symbolic arg2 INTERFACE: multiply divide add subtract
The advantage of this approach comparing to
ALIAS: keyword is that one can attach an extra function
(This example supposes that there was no
INTERFACE_MACRO: section, otherwise one needs to use
something else instead of
The INTERFACE_MACRO: Keyword
This keyword allows one to define an
INTERFACE using a different way to extract a function pointer from an
XSUB. The text which follows this keyword should give the name of macros which would extract/set a function pointer. The extractor macro is given return type,
The default value is
Suppose that in the previous example functions pointers for
#define XSINTERFACE_FUNC_BYOFFSET(ret,cv,f) \ ((XSINTERFACE_CVT(ret,))fp[CvXSUBANY(cv).any_i32]) #define XSINTERFACE_FUNC_BYOFFSET_set(cv,f) \ CvXSUBANY(cv).any_i32 = CAT2( f, _off ) in C section,
symbolic interface_s_ss(arg1, arg2) symbolic arg1 symbolic arg2 INTERFACE_MACRO: XSINTERFACE_FUNC_BYOFFSET XSINTERFACE_FUNC_BYOFFSET_set INTERFACE: multiply divide add subtract in XSUB section.
The INCLUDE: KeywordThis keyword can be used to pull other files into the XS module. The other files may have XS code. INCLUDE: can also be used to run a command to generate the XS code to be pulled into the module.
The file Rpcb1.xsh contains our
bool_t rpcb_gettime(host,timep) char *host time_t &timep OUTPUT: timep The XS module can use INCLUDE: to pull that file into it.
INCLUDE: Rpcb1.xsh
If the parameters to the
INCLUDE: keyword are followed by a pipe (
INCLUDE: cat Rpcb1.xsh |
The CASE: KeywordThe CASE: keyword allows an XSUB to have multiple distinct parts with each part acting as a virtual XSUB. CASE: is greedy and if it is used then all other XS keywords must be contained within a CASE:. This means nothing may precede the first CASE: in the XSUB and anything following the last CASE: is included in that case.
A
CASE: might switch via a parameter of the
XSUB, via the
perlman:perlguts
ALIAS: variable (see The ALIAS: Keyword), or maybe via the perlman:perlguts variable (see Variable-length Parameter Lists). The last
CASE: becomes the
default case if it is not associated with a conditional. The following example shows
CASE switched via
perlman:perlguts with a function
long rpcb_gettime(a,b) CASE: ix == 1 ALIAS: x_gettime = 1 INPUT: # 'a' is timep, 'b' is host char *b time_t a = NO_INIT CODE: RETVAL = rpcb_gettime( b, &a ); OUTPUT: a RETVAL CASE: # 'a' is host, 'b' is timep char *a time_t &b = NO_INIT OUTPUT: b RETVAL That function can be called with either of the following statements. Note the different argument lists.
$status = rpcb_gettime( $host, $timep );
$status = x_gettime( $timep, $host );
The & Unary Operator
The & unary operator is used to tell the compiler that it should dereference the object when it calls the
C function. This is used when a
CODE: block is not used and the object is a not a pointer type (the object is an
int or
The following
XSUB will generate incorrect
C code. The xsubpp compiler will turn this into code which calls
bool_t rpcb_gettime(host,timep) char *host time_t timep OUTPUT: timep
That problem is corrected by using the
bool_t rpcb_gettime(host,timep) char *host time_t &timep OUTPUT: timep
Inserting Comments and C Preprocessor DirectivesC preprocessor directives are allowed within BOOT:, PREINIT: INIT:, CODE:, PPCODE:, and CLEANUP: blocks, as well as outside the functions. Comments are allowed anywhere after the MODULE keyword. The compiler will pass the preprocessor directives through untouched and will remove the commented lines.
Comments can be added to XSUBs by placing a If you use preprocessor directives to choose one of two versions of a function, use
#if ... version1 #else /* ... version2 */ #endif and not
#if ... version1 #endif #if ... version2 #endif because otherwise xsubpp will believe that you made a duplicate definition of the function. Also, put a blank line before the #else/#endif so it will not be seen as part of the function body.
Using XS With C++
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
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. The next examples will use the following C++ class.
class color { public: color(); ~color(); int blue(); void set_blue( int );
private: int c_blue; };
The XSUBs for the
int color::blue()
void color::set_blue( val ) int val
Both functions will expect an object as the first parameter. The xsubpp
compiler will call that object perlman:perlguts and will use it to call the specified method. So in the
C++ code the
RETVAL = THIS->blue();
THIS->set_blue( val ); If the function's name is DESTROY then the C++ delete function will be called and perlman:perlguts will be given as its parameter.
void color::DESTROY() The C++ code will call delete.
delete THIS;
If the function's name is new then the
C++
color * color::new()
The
C++ code will call
RETVAL = new color(); The following is an example of a typemap that could be used for this C++ example.
TYPEMAP color * O_OBJECT
OUTPUT # The Perl object is blessed into 'CLASS', which should be a # char* having the name of the package for the blessing. O_OBJECT sv_setref_pv( $arg, CLASS, (void*)$var );
INPUT O_OBJECT if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) $var = ($type)SvIV((SV*)SvRV( $arg )); else{ warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" ); XSRETURN_UNDEF; }
Interface StrategyWhen 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. 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. Identify which values are used by only 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. 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. 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.
Perl Objects And C StructuresWhen dealing with C structures one should select either T_PTROBJ or T_PTRREF 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 because the XSUB will attempt to verify that the Perl object is of the expected type.
The following
XS code shows the
struct netconfig *getnetconfigent(const char *netid);
A
typedef struct netconfig Netconfig;
MODULE = RPC PACKAGE = RPC
Netconfig * getnetconfigent(netid) char *netid
MODULE = RPC PACKAGE = NetconfigPtr PREFIX = rpcb_
void rpcb_DESTROY(netconf) Netconfig *netconf CODE: printf("Now in NetconfigPtr::DESTROY\n"); free( netconf ); This example requires the following typemap entry. Consult the typemap section for more information about adding new typemaps for an extension.
TYPEMAP Netconfig * T_PTROBJ This example will be used with the following Perl statements.
use RPC; $netconf = getnetconfigent("udp");
When Perl destroys the object referenced by
The Typemap
The typemap is a collection of code fragments which are used by the xsubpp
compiler to map
C function parameters and values to Perl values. The
typemap file may consist of three sections labeled
The default typemap in the
Most extensions which require a custom typemap will need only the
TYPEMAP section of the typemap file. The custom typemap used in the
TYPEMAP Netconfig *<tab>T_PTROBJ
Here's a more complicated example: suppose that you wanted
typedef struct netconfig * Net_Config;
And then provide a typemap entry
TYPEMAP Net_Config T_PTROBJ_SPECIAL
INPUT T_PTROBJ_SPECIAL if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")) { IV tmp = SvIV((SV*)SvRV($arg)); $var = ($type) tmp; } else croak(\"$var is not of type ${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")
OUTPUT T_PTROBJ_SPECIAL sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\", (void*)$var); The INPUT and OUTPUT sections substitute underscores for double-colons on the fly, giving the desired effect. This example demonstrates some of the power and versatility of the typemap facility.
EXAMPLES
File
#include "EXTERN.h" #include "perl.h" #include "XSUB.h"
#include <rpc/rpc.h>
typedef struct netconfig Netconfig;
MODULE = RPC PACKAGE = RPC
SV * rpcb_gettime(host="localhost") char *host PREINIT: time_t timep; CODE: ST(0) = sv_newmortal(); if( rpcb_gettime( host, &timep ) ) sv_setnv( ST(0), (double)timep );
Netconfig * getnetconfigent(netid="udp") char *netid
MODULE = RPC PACKAGE = NetconfigPtr PREFIX = rpcb_
void rpcb_DESTROY(netconf) Netconfig *netconf CODE: printf("NetconfigPtr::DESTROY\n"); free( netconf );
File
TYPEMAP Netconfig * T_PTROBJ
File
package RPC;
require Exporter; require DynaLoader; @ISA = qw(Exporter DynaLoader); @EXPORT = qw(rpcb_gettime getnetconfigent);
bootstrap RPC; 1;
File
use RPC;
$netconf = getnetconfigent(); $a = rpcb_gettime(); print "time = $a\n"; print "netconf = $netconf\n";
$netconf = getnetconfigent("tcp"); $a = rpcb_gettime("poplar"); print "time = $a\n"; print "netconf = $netconf\n";
XS VERSION
This document covers features supported by
AUTHORDean Roehrich <roehrich@cray.com> Jul 8, 1996 Return to the Library |
|