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
