h2xs
el fichero coord.h
sin cambio alguno obtenemos una salida errónea:
lhp@nereida:~/Lperl/src/XSUB/h2xsexample$ cp coordlib/include/coord.h . lhp@nereida:~/Lperl/src/XSUB/h2xsexample$ h2xs -xn Coord coord.h Defaulting to backwards compatibility with perl 5.8.8 If you intend this module to be compatible with earlier perl versions, please specify a minimum perl version with the -b option. Writing Coord/ppport.h Scanning typemaps... Scanning /usr/share/perl/5.8/ExtUtils/typemap Scanning coord.h for functions... Expecting parenth after identifier in `struct _IO_FILE_plus _IO_2_1_stdin_; .... lhp@nereida:~/Lperl/src/XSUB/h2xsexample$ ls -ltr Coord/ total 120 -rw-r--r-- 1 lhp lhp 118192 2006-07-08 11:50 ppport.h -rw-r--r-- 1 lhp lhp 0 2006-07-08 11:50 Coord.xsObserve que el fichero generado
Coord.xs
tiene tamaño 0.
El error es causado por las cabeceras de inclusión
de los fichero estandar:
lhp@nereida:~/Lperl/src/XSUB/h2xsexample$ head -2 coord.h #include <stdio.h> #include <math.h>Tambien el nombre
format
usado para el primer argumento de las funciones de
conversión
polar2str
y rectangular2str
produce problemas (en la sección
17.22.1
encontrará los contenidos de coord.h
)
Después de editar la copia de coord.h
, eliminar las primeras
líneas
y hacer los cambios en el nombre de los parámetros nos quedamos
con el siguiente fichero de descripción de la interfaz:
hp@nereida:~/projects/perl/src/XSUB/h2xsexample$ cat -n coord.h 1 #define PI 3.14159265358979323846264338327 2 3 typedef struct { 4 double mod; 5 double arg; 6 } polar; 7 8 polar getpolar(); 9 char * polar2str(const char * f, polar p); 10 11 typedef struct { 12 double x; 13 double y; 14 } rectangular; 15 16 rectangular getrectangular(); 17 char * rectangular2str(const char * f, rectangular r); 18 19 polar rc2pl(rectangular r); 20 rectangular pl2rc(polar p);Procedemos a compilar de nuevo con
h2xs
.
lhp@nereida:~/projects/perl/src/XSUB/h2xsexample$ h2xs -xa -n Coord coord.h Defaulting to backwards compatibility with perl 5.8.8 If you intend this module to be compatible with earlier perl versions, please specify a minimum perl version with the -b option. Writing Coord/ppport.h Scanning typemaps... Scanning /usr/share/perl/5.8/ExtUtils/typemap Scanning coord.h for functions... Scanning coord.h for typedefs... Writing Coord/lib/Coord.pm Use of uninitialized value in concatenation (.) or string at /usr/bin/h2xs line 1275. Use of uninitialized value in concatenation (.) or string at /usr/bin/h2xs line 1275. Writing Coord/Coord.xs Writing Coord/fallback/const-c.inc Writing Coord/fallback/const-xs.inc Writing Coord/typemap Writing Coord/Makefile.PL Writing Coord/README Writing Coord/t/Coord.t Writing Coord/Changes Writing Coord/MANIFEST lhp@nereida:~/projects/perl/src/XSUB/h2xsexample$La opción
-x
hace que se genere el código XSUB a partir de
las declaraciones en el fichero cabecera. Para ello, es necesario tener instalado
el paquete C::Scan .
La opción -a
hace que se generen funciones de acceso/mutación
(geter-seters en la terminología) a los campos
de las estructuras polar
y rectangular
.
Obsérvese que no hemos usado la opción -A
habilitando por tanto
la generación de código para el acceso desde Perl a las constantes
declaradas en el fichero de cabecera (en nuestro ejemplo la definición
de PI
). Esta es la causa de la existencia de los fichero const-c.inc
y const-xs.inc
.
A continuación editamos Makefile.PL
modificando las líneas 12 (entrada LIBS
) y 14 (entrada INC
)
para que el Makefile
generado pueda encontrar la librería:
lhp@nereida:~/projects/perl/src/XSUB/h2xsexample$ cd Coord/ lhp@nereida:~/projects/perl/src/XSUB/h2xsexample/Coord$ vi Makefile.PL .... lhp@nereida:~/projects/perl/src/XSUB/h2xsexample/Coord$ cat -n Makefile.PL 1 use 5.008008; 2 use ExtUtils::MakeMaker; 3 # See lib/ExtUtils/MakeMaker.pm for details of how to influence 4 # the contents of the Makefile that is written. 5 WriteMakefile( 6 NAME => 'Coord', 7 VERSION_FROM => 'lib/Coord.pm', # finds $VERSION 8 PREREQ_PM => {}, # e.g., Module::Name => 1.1 9 ($] >= 5.005 ? ## Add these new keywords supported since 5.005 10 (ABSTRACT_FROM => 'lib/Coord.pm', # retrieve abstract from module 11 AUTHOR => 'Lenguajes y Herramientas de Programacion <lhp@>') : ()), 12 LIBS => ['-L../coordlib/lib/ -lpl', '-lm'], # e.g., '-lm' 13 DEFINE => '', # e.g., '-DHAVE_SOMETHING' 14 INC => '-I. -I../coordlib/include', # e.g., '-I. -I/usr/include/other' 15 # Un-comment this if you add C files to link with later: 16 # OBJECT => '$(O_FILES)', # link all the C files too 17 ); 18 if (eval {require ExtUtils::Constant; 1}) { 19 # If you edit these definitions to change the constants used by this module, 20 # you will need to use the generated const-c.inc and const-xs.inc 21 # files to replace their "fallback" counterparts before distributing your 22 # changes. 23 my @names = (qw(PI)); 24 ExtUtils::Constant::WriteConstants( 25 NAME => 'Coord', 26 NAMES => \@names, 27 DEFAULT_TYPE => 'IV', 28 C_FILE => 'const-c.inc', 29 XS_FILE => 'const-xs.inc', 30 ); 31 32 } 33 else { 34 use File::Copy; 35 use File::Spec; 36 foreach my $file ('const-c.inc', 'const-xs.inc') { 37 my $fallback = File::Spec->catfile('fallback', $file); 38 copy ($fallback, $file) or die "Can't copy $fallback to $file: $!"; 39 } 40 }La compilación del módulo no da errores:
lhp@nereida:~/Lperl/src/XSUB/h2xsexample/Coord$ perl Makefile.PL Checking if your kit is complete... Looks good Warning: -L../coordlib/lib/ changed to -L/home/lhp/projects/perl/src/XSUB/h2xsexample/Coord/../coordlib/lib/ Writing Makefile for Coord lhp@nereida:~/Lperl/src/XSUB/h2xsexample/Coord$ make cp lib/Coord.pm blib/lib/Coord.pm AutoSplitting blib/lib/Coord.pm (blib/lib/auto/Coord) /usr/bin/perl /usr/share/perl/5.8/ExtUtils/xsubpp \ -typemap /usr/share/perl/5.8/ExtUtils/typemap -typemap typemap Coord.xs > Coord.xsc && mv Coord.xsc Coord.c cc -c -I. -I../coordlib/include -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN \ -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 \ -DVERSION=\"0.01\" -DXS_VERSION=\"0.01\" -fPIC "-I/usr/lib/perl/5.8/CORE" Coord.c Running Mkbootstrap for Coord () chmod 644 Coord.bs rm -f blib/arch/auto/Coord/Coord.so LD_RUN_PATH="/home/lhp/projects/perl/src/XSUB/h2xsexample/Coord/../coordlib/lib" \ cc -shared -L/usr/local/lib Coord.o -o blib/arch/auto/Coord/Coord.so \ -L/home/lhp/projects/perl/src/XSUB/h2xsexample/Coord/../coordlib/lib -lpl \ chmod 755 blib/arch/auto/Coord/Coord.so cp Coord.bs blib/arch/auto/Coord/Coord.bs chmod 644 blib/arch/auto/Coord/Coord.bs Manifying blib/man3/Coord.3pm lhp@nereida:~/Lperl/src/XSUB/h2xsexample/Coord$ make test PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" \ "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t t/Coord....ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.06 cusr + 0.00 csys = 0.06 CPU)Por cada
struct
el programa h2xs
produce dos clases. Así para
la struct polar
escribe una clase polar
y otra polarPtr
que se corresponde con el tipo polar *
. La clase polar
dispone de
dos métodos: un constructor new()
que crea un objeto polar
y
un método _to_ptr()
que construye el objeto polarPtr
que representa
al puntero al objeto polar
. La clase polarPtr
dispone de métodos
de acceso y mutación de los campos de la struct
.
Estos métodos tienen los mismos nombres que los campos: mod
, arg
.
Lo mismo sucede con la struct rectangular
. Además se provee de la clase
Coord
que contiene el resto de las subrutinas de la librería.
En el módulo Perl generado (lib/Coord.pm
)
sólo las constantes son exportadas por defecto. El
resto de símbolos es insertado en @EXPORT_OK
:
lhp@nereida:~/projects/perl/src/XSUB/h2xsexample/Coord$ sed -ne '20,34p' lib/Coord.pm | cat -n 1 our %EXPORT_TAGS = ( 'all' => [ qw( 2 PI 3 getpolar 4 getrectangular 5 pl2rc 6 polar2str 7 rc2pl 8 rectangular2str 9 ) ] ); 10 11 our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); 12 13 our @EXPORT = qw( 14 PI 15 );
No siempre el código generado por h2xs
funciona. Lo habitual es que el programador
tenga que intervenir para
reajustar el código, pero esta vez ha habido suerte:
tenemos un modo casi funcional como muestra el siguiente
ejemplo:
lhp@nereida:~/Lperl/src/XSUB/h2xsexample/Coord$ mkdir script lhp@nereida:~/Lperl/src/XSUB/h2xsexample/Coord$ vi usecoord.pl ..... lhp@nereida:~/Lperl/src/XSUB/h2xsexample/Coord$ cat -n usecoord.pl 1 #!/usr/local/bin/perl -w 2 use strict; 3 use blib; 4 use Coord; 5 6 print PI(),"\n"; 7 8 my $p = polar->new(); 9 my $pp = $p->_to_ptr; 10 11 $pp->mod(1); 12 $pp->arg(PI()/4); 13 14 my $m = $pp->mod; 15 my $a = $pp->arg; 16 17 print "($m, $a)\n"; 18 19 my $r = Coord::pl2rc($p); 20 my $rp = $r->_to_ptr; 21 print "(".$rp->x.", ".$rp->y,")\n"; lhp@nereida:~/Lperl/src/XSUB/h2xsexample/Coord$ ./usecoord.pl 3 (1, 0.75) (0.731688868873821, 0.681638760023334)Nos damos cuenta que algo raro ocurre con la impresión de
PI()
en la línea 6.
La constante esta siendo interpretada como entera. Reeditamos Makefile.PL
y cambiamos la línea
27 que se refiere al tipo por defecto de las constantes (campo DEFAULT_TYPE
para que contenga NV
en vez de IV
):
18 if (eval {require ExtUtils::Constant; 1}) { 19 # If you edit these definitions to change the constants used by this module, 20 # you will need to use the generated const-c.inc and const-xs.inc 21 # files to replace their "fallback" counterparts before distributing your 22 # changes. 23 my @names = (qw(PI)); 24 ExtUtils::Constant::WriteConstants( 25 NAME => 'Coord', 26 NAMES => \@names, 27 DEFAULT_TYPE => 'NV', 28 C_FILE => 'const-c.inc', 29 XS_FILE => 'const-xs.inc', 30 ); 31 32 }Después de rehacer el módulo (
make veryclean; perlMakefile.PL; make
)
la ejecución del programa de ejemplo produce
una salida correcta:
lhp@nereida:~/Lperl/src/XSUB/h2xsexample/Coord$ ./usecoord.pl 3.14159265358979 (1, 0.785398163397448) (0.707106781186548, 0.707106781186547)
Casiano Rodríguez León