xsubpp
en su labor de traducir dos pasos importantes:
Existe un fichero typemap
por defecto
el cuál describe el proceso de conversión para los tipos
mas comunes.
El fichero de typemap
usado por defecto puede obtenerse ejecutando
el siguiente inline:
pp2@nereida:~$ perl -MConfig -le 'print "$Config{installprivlib}/ExtUtils/typemap"' /usr/share/perl/5.8/ExtUtils/typemap
Veamos un esquema del contenido del fichero typemap
.
Las elipsis corresponden a zonas suprimidas del fichero.
pp2@nereida:~$ cat -n /usr/share/perl/5.8/ExtUtils/typemap 1 # basic C types 2 int T_IV 3 unsigned T_UV 4 unsigned int T_UV 5 long T_IV 6 unsigned long T_UV 7 short T_IV 8 unsigned short T_UV 9 char T_CHAR 10 unsigned char T_U_CHAR 11 char * T_PV 12 unsigned char * T_PV 13 const char * T_PV 14 caddr_t T_PV .. ....... ..... 43 Boolean T_BOOL 44 float T_FLOAT 45 double T_DOUBLE 46 SysRet T_SYSRET 47 SysRetLong T_SYSRET 48 FILE * T_STDIO 49 PerlIO * T_INOUT 50 FileHandle T_PTROBJ 51 InputStream T_IN 52 InOutStream T_INOUT 53 OutputStream T_OUT 54 bool T_BOOL 55 56 ############################################################################# 57 INPUT 58 T_SV 59 $var = $arg 60 T_SVREF 61 if (SvROK($arg)) 62 $var = (SV*)SvRV($arg); 63 else 64 Perl_croak(aTHX_ \"$var is not a reference\") 65 T_AVREF 66 if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) 67 $var = (AV*)SvRV($arg); 68 else 69 Perl_croak(aTHX_ \"$var is not an array reference\") 70 T_HVREF 71 if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVHV) 72 $var = (HV*)SvRV($arg); 73 else 74 Perl_croak(aTHX_ \"$var is not a hash reference\") 75 T_CVREF 76 if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVCV) 77 $var = (CV*)SvRV($arg); 78 else 79 Perl_croak(aTHX_ \"$var is not a code reference\") 80 T_SYSRET 81 $var NOT IMPLEMENTED 82 T_UV 83 $var = ($type)SvUV($arg) 84 T_IV 85 $var = ($type)SvIV($arg) 86 T_INT 87 $var = (int)SvIV($arg) 88 T_ENUM 89 $var = ($type)SvIV($arg) 90 T_BOOL 91 $var = (bool)SvTRUE($arg) 92 T_U_INT 93 $var = (unsigned int)SvUV($arg) ... .............................. 110 T_DOUBLE 111 $var = (double)SvNV($arg) 112 T_PV 113 $var = ($type)SvPV_nolen($arg) 114 T_PTR 115 $var = INT2PTR($type,SvIV($arg)) ... ................................ 193 ############################################################################# 194 OUTPUT 195 T_SV 196 $arg = $var; 197 T_SVREF 198 $arg = newRV((SV*)$var); 199 T_AVREF 200 $arg = newRV((SV*)$var); 201 T_HVREF 202 $arg = newRV((SV*)$var); 203 T_CVREF 204 $arg = newRV((SV*)$var); 205 T_IV 206 sv_setiv($arg, (IV)$var); 207 T_UV 208 sv_setuv($arg, (UV)$var); 209 T_INT 210 sv_setiv($arg, (IV)$var); 211 T_SYSRET 212 if ($var != -1) { 213 if ($var == 0) 214 sv_setpvn($arg, "0 but true", 10); 215 else 216 sv_setiv($arg, (IV)$var); 217 } 218 T_ENUM 219 sv_setiv($arg, (IV)$var); 220 T_BOOL 221 $arg = boolSV($var); 222 T_U_INT 223 sv_setuv($arg, (UV)$var); 224 T_SHORT 225 sv_setiv($arg, (IV)$var); 226 T_U_SHORT 227 sv_setuv($arg, (UV)$var); 228 T_LONG 229 sv_setiv($arg, (IV)$var); 230 T_U_LONG 231 sv_setuv($arg, (UV)$var); 232 T_CHAR 233 sv_setpvn($arg, (char *)&$var, 1); 234 T_U_CHAR 235 sv_setuv($arg, (UV)$var); 236 T_FLOAT 237 sv_setnv($arg, (double)$var); 238 T_NV 239 sv_setnv($arg, (NV)$var); 240 T_DOUBLE 241 sv_setnv($arg, (double)$var); 242 T_PV 243 sv_setpv((SV*)$arg, $var); 244 T_PTR 245 sv_setiv($arg, PTR2IV($var)); ... ............................. 307 T_OUT 308 { 309 GV *gv = newGVgen("$Package"); 310 if ( do_open(gv, "+>&", 3, FALSE, 0, 0, $var) ) 311 sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))); 312 else 313 $arg = &PL_sv_undef; 314 } pp2@nereida:~$
TYPEMAP
)
contiene una lista de tipos C básicos y una cadena que se asocia con el tipo.
El tipo C y la cadena/token van separados por un tabulador.
Obsérvese que varios tipos C pueden ser asignados a la misma cadena.
Por ejemplo unsigned
y unsigned long
se corresponden
con
T_UV
.
INPUT
.
Es usado por xsubpp
para convertir los parámetros de la llamada
Perl a sus equivalentes C.
OUTPUT
.
Proporciona el código para traducir los valores retornados por la
función C a sus equivalentes Perl.
Por ejemplo, el código para traducir entre un valor escalar SV
y un entero C
se obtiene en las entradas
T_IV
:
1 # basic C types 2 int T_IV .. ... .... 56 ############################################################################# 57 INPUT .. .... ........................ 84 T_IV 85 $var = ($type)SvIV($arg) ... .... ........................ 193 ############################################################################# 194 OUTPUT ... .... ........................ 205 T_IV 206 sv_setiv($arg, (IV)$var);Lo que indica que, al traducir un argumento Perl (de ahí el nombre
$arg
) de una XSUB que espera un entero
se llamará a SvIV
17.1
sobre dicho argumento para obtener
la variable c (denotada por $var
).
Recíprocamente
se usará
sv_setiv
17.2
para asignar la parte entera
de la variable retornada al código Perl.
La notación $type
se sustituye por el tipo C de la variable.
debe ser uno de los tipos listados en la primera parte del fichero typemap
.
Consideremos el siguiente ejemplo:
lhp@nereida:~/Lperl/src/XSUB/TypeMapExample$ cat -n TypeMapExample.xs 1 #include "EXTERN.h" 2 #include "perl.h" 3 #include "XSUB.h" 4 5 #include "ppport.h" 6 7 void square(int x, int *x2) { 8 *x2 = x*x; 9 } 10 11 MODULE = TypeMapExample PACKAGE = TypeMapExample 12 13 void 14 square(x, x2) 15 int x 16 int &x2 = NO_INIT 17 OUTPUT: 18 x2
La palabra clave NO_INIT usada en la línea 16 indica que el parámetro es usado sólo como parámetro de salida. Si no se pone se producirán mensajes de advertencia:
lhp@nereida:~/Lperl/src/XSUB/TypeMapExample$ cat -n ./useypeMapexample.pl 1 #!/usr/local/bin/perl -w 2 use strict; 3 use blib; 4 use TypeMapExample; 5 6 my @a; 7 my $i = 0; 8 @ARGV = 1..5 unless @ARGV; 9 square($_, $a[$i++]) for @ARGV; 10 11 print "@a\n"; 12 lhp@nereida:~/Lperl/src/XSUB/TypeMapExample$ ./useypeMapexample.pl Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9. Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9. Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9. Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9. Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9. 1 4 9 16 25El ampersand en la declaración de
x2
en la línea 16 advierte al compilador
que en la llamada a la función debe pasar la dirección del argumento. Hay una diferencia
en XSUB entre estas dos declaraciones:
int * x2; int &x2;La primera indica que x2 es un vector de enteros. El valor de
x2
será pasado a la función. La segunda indica que
x2
es un entero que será pasado por referencia: su dirección
será pasada a la función.
La compilación con xsubpp
de este fuente produce la salida:
lhp@nereida:~/Lperl/src/XSUB/TypeMapExample$ xsubpp -typemap /usr/share/perl/5.8/ExtUtils/typemap \ TypeMapExample.xs | cat -n Please specify prototyping behavior for TypeMapExample.xs (see perlxs manual) 1 /* 2 * This file was generated automatically by xsubpp version 1.9508 from the 3 * contents of TypeMapExample.xs. Do not edit this file, edit TypeMapExample.xs instead. 4 * 5 * ANY CHANGES MADE HERE WILL BE LOST! 6 * 7 */ 8 9 #line 1 "TypeMapExample.xs" 10 #include "EXTERN.h" 11 #include "perl.h" 12 #include "XSUB.h" 13 14 #include "ppport.h" 15 16 void square(int x, int *x2) { 17 *x2 = x*x; 18 } 19 20 #line 21 "TypeMapExample.c" 21 22 XS(XS_TypeMapExample_square); /* prototype to pass -Wmissing-prototypes */ 23 XS(XS_TypeMapExample_square) 24 { 25 dXSARGS; 26 if (items != 2) 27 Perl_croak(aTHX_ "Usage: TypeMapExample::square(x, x2)"); 28 { 29 int x = (int)SvIV(ST(0)); 30 int x2; 31 32 square(x, &x2); 33 sv_setiv(ST(1), (IV)x2); 34 SvSETMAGIC(ST(1)); 35 } 36 XSRETURN_EMPTY; 37 } .. .................. código para C++
int x = (int)SvIV(ST(0))
y su correspondencia directa con el esqueleto que figura en el
typemap
: $var = ($type)SvIV($arg)
.
sv_setiv(ST(1), (IV)x2)
que se corresponde con el código de OUTPUT
que figura en el fichero typemap
:
sv_setiv($arg, (IV)$var)
lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ sed -ne '114,116p' XSUB.h # define dXSARGS \ dSP; dAXMARK; dITEMS #endif lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ grep -ni 'define dSP' * pp.h:76:#define dSP register SV **sp = PL_stack_sp lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ sed -ne '103,105p' XSUB.h #define dAXMARK \ I32 ax = POPMARK; \ register SV **mark = PL_stack_base + ax++ lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ grep -ni 'define ditems' * XSUB.h:107:#define dITEMS I32 items = SP - MARK
Casiano Rodríguez León