Para crear el esqueleto de un módulo que incluye código C usando  XS 
utilizaremos  h2xs  con las opción -A.
1 lhp@nereida:~/Lperl/src/XSUB$ h2xs -A -n Example 2 Defaulting to backwards compatibility with perl 5.8.8 3 If you intend this module to be compatible with earlier perl versions, please 4 specify a minimum perl version with the -b option. 5 ! 6 Writing Example/ppport.h 7 Writing Example/lib/Example.pm ! 8 Writing Example/Example.xs 9 Writing Example/Makefile.PL 10 Writing Example/README 11 Writing Example/t/Example.t 12 Writing Example/Changes 13 Writing Example/MANIFEST 14 lhp@nereida:~/Lperl/src/XSUB$La opción
-A indica que no se requiere carga automática
de constantes. En esta ocasión omitimos la habitual opción -X 
para indicar que se trata de una extensión XS.
Un cambio que es apreciable de la salida es la creación 
del fichero Example/Example.xs.
El módulo generado  Example.pm también es un poco diferente
del que se obtiene cuando se usa -X.
Veamos un extracto del fichero Example.pm:
 lhp@nereida:~/Lperl/src/XSUB$ cd Example/lib/
 lhp@nereida:~/Lperl/src/XSUB/Example/lib$ cat -n Example.pm
  1  package Example;
  2
  3  use 5.008008;
  4  use strict;
  5  use warnings;
  6
  7  require Exporter;
  8
  9  our @ISA = qw(Exporter);
  .  .................
!30  require XSLoader;
!31  XSLoader::load('Example', $VERSION);
 32
 33  # Preloaded methods go here.
 34
 35  1;
 36  __END__
 .. ........ 
 lhp@nereida:~/Lperl/src/XSUB/Example/lib$
Hay varios cambios. Primero, el módulo usa  XSLoader .
El módulo XSLoader proporciona el código necesario
para cargar librerías compartidas en Perl.
Las librerías compartidas serán creadas desde el código
XS en aquellos sistemas operativos que permiten 
el uso de librerías compartidas.
El segundo cambio está en la línea 31:
La función  XSLoader::load  
se encarga de cargar la librería dinámica
con nombre Example y comprueba que su versión
es $VERSION.
Una alternativa es usar el módulo DynaLoader.
El módulo  DynaLoader  proporciona un mecanismo mas potente
pero también una interfaz mas compleja.
El aspecto típico de un módulo XS construido con 
DynaLoader es similar:
package YourPackage; require DynaLoader; our @ISA = qw( OnePackage OtherPackage DynaLoader ); our $VERSION = '0.01'; bootstrap YourPackage $VERSION;
El fichero Example.xs debe contener los ficheros 
de cabecera que permiten el acceso a las funciones
internas de Perl (líneas 1-5).
lhp@nereida:~/Lperl/src/XSUB/Example$ cat -n Example.xs 1 #include "EXTERN.h" 2 #include "perl.h" 3 #include "XSUB.h" 4 5 #include "ppport.h" 6 7 8 MODULE = Example PACKAGE = Example 9 /* Aqui comienza la sección XS */
Para que un módulo XS sea portable en múltiples plataformas es necesario tener en cuenta
varios factores. Uno de ellos es que la API de Perl cambia con el tiempo.
Se añaden nuevas funciones y se eliminan otras.
El módulo  Devel::PPPort  tiene por objetivo proveer
compatibilidad a través de esos cambios de manera que un programador
XS no tenga que preocuparse del problema de las versiones de Perl.
Devel::PPPort genera un fichero C de cabecera ppport.h
que es al mismo tiempo un programa Perl que nos da información 
sobre la compatibilidad del código XS:
lhp@nereida:~/Lperl/src/XSUB/Example$ perl ppport.h Scanning ./Example.xs ... === Analyzing ./Example.xs === No need to include 'ppport.h' Suggested changes: --- ./Example.xs +++ ./Example.xs.patched @@ -2,7 +2,6 @@ #include "perl.h" #include "XSUB.h" -#include "ppport.h" MODULE = Example PACKAGE = ExamplePara generar
ppport.h sin la ayuda de h2xs podemos hacer.
perl -MDevel::PPPort -eDevel::PPPort::WriteFile
La inclusión de ppport.h nos da acceso a una parte de la API de Perl 
que no estaba disponible en versiones anteriores.
Ejecute  perl ppport.h --list-provided para obtener la lista de elementos 
proveídos por ppport.h.
Además se puede usar para obtener información sobre la portabilidad de las diferentes funciones, por ejemplo:
lhp@nereida:~/Lperl/src/XSUB/Example$ perl ppport.h --api-info=sv_magicext === sv_magicext === Supported at least starting from perl-5.7.3.
Para mas detalles consulta perldoc ppport.h.
Un fichero XS comienza con una sección en lenguaje C que termina con 
la primera aparición de la directiva  MODULE  (línea 8).
A partir de ahí pueden seguir otras directivas XS o 
definiciones  XSUB . Una  definición XSUB  proporciona la información
necesaria para establecer el puente entre los convenios de llamada
Perl  y los de C para una función dada. Se proporciona
una definición XSUB por cada función C que se desea hacer pública.
El lenguaje utilizado en este parte del fichero se conoce
como lenguaje XS. El traductor  xsubpp  reconoce los trozos
de documentación POD en ambas secciones.
La directiva MODULE declara el espacio de nombres del módulo y define el nombre de la librería que será creada. La palabra clave PACKAGE define el espacio de nombres Perl para las subrutinas. Después de esta línea todo lo que sigue es código XS. Añadamos el siguiente código XS:
lhp@nereida:~/Lperl/src/XSUB/Example$ cat -n Example.xs
 1  #include "EXTERN.h"
 2  #include "perl.h"
 3  #include "XSUB.h"
 4
 5  #include "ppport.h"
 6
 7  double computepi(int id, int N, int np) {
 8    double sum, left;
 9
10    int i;
11    for(i=id, sum = 0; i<N; i+=np) {
12      double x = (i + 0.5)/N;
13      sum += 4/(1 + x*x);
14    }
15    sum /= N;
16    return (sum);
17  }
18
19
20  MODULE = Example                PACKAGE = Example
21
22  double
23  computepi(id, N, np)
24  int id
25  int N
26  int np
Para funciones como computepi que manejan tipos simples 
la declaración de  XSUB  se limita a proporcionar el 
prototipo de la función (líneas 22-26) en estilo KR.
La primera línea define el tipo de retorno, luego sigue una línea
con la forma de llamada a la función y después una línea por argumento,
especificando su tipo C.
! 1 lhp@nereida:~/Lperl/src/XSUB/Example$ perl Makefile.PL 2 Checking if your kit is complete... 3 Looks good 4 Writing Makefile for Example ! 5 lhp@nereida:~/Lperl/src/XSUB/Example$ make 6 7 cp lib/Example.pm blib/lib/Example.pm 8 cp useexample.pl blib/lib/useexample.pl ! 9 /usr/bin/perl /usr/share/perl/5.8/ExtUtils/xsubpp ! -typemap /usr/share/perl/5.8/ExtUtils/typemap ! Example.xs > Example.xsc && mv Example.xsc Example.c !10 Please specify prototyping behavior for Example.xs (see perlxs manual) !11 cc -c -I. -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" ! Example.c !12 Running Mkbootstrap for Example () !13 chmod 644 Example.bs !14 rm -f blib/arch/auto/Example/Example.so !15 cc -shared -L/usr/local/lib Example.o -o blib/arch/auto/Example/Example.so \ 16 \ 17 !18 chmod 755 blib/arch/auto/Example/Example.so !19 cp Example.bs blib/arch/auto/Example/Example.bs !20 chmod 644 blib/arch/auto/Example/Example.bs 21 Manifying blib/man3/Example.3pm
Expliquemos en mas detalle la secuencia anterior:
Makefile (líneas 1-4) a partir de Makefile.PL:
lhp@nereida:~/Lperl/src/XSUB/Example$ 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              => 'Example',
 7      VERSION_FROM      => 'lib/Example.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/Example.pm', # retrieve abstract from module
11         AUTHOR         => 'Lenguajes y Herramientas de Programacion') : ()),
12      LIBS              => [''], # e.g., '-lm'
13      DEFINE            => '', # e.g., '-DHAVE_SOMETHING'
14      INC               => '-I.', # 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  );
La ejecución de Makefile.PL detecta la presencia de ficheros .xs 
en el directorio y adapta el Makefile para que dichos ficheros
sean procesados.
blib/lib/ (líneas 7-8).
El nombre blib viene de Build Library.
.c
la salida se almacena en un fichero temporal Example.xsc y luego
se renombra como Example.c.
Ello se hace para evitar que ficheros en proceso de formación 
puedan ser erróneamente tomados por código C válido.
PROTOTYPES: DISABLE
en el fichero XS justo después de la declaración 
MODULE:
lhp@nereida:~/Lperl/src/XSUB/Example$ cat -n Example.xs
     1  #include "EXTERN.h"
     2  #include "perl.h"
     3  #include "XSUB.h"
     4
     5  #include "ppport.h"
     6
    ..  .................................................
    20  MODULE = Example                PACKAGE = Example
    21  PROTOTYPES: DISABLE
    22
    23  double
    24  computepi(id, N, np)
    25  int id
    26  int N
    27  int np
Example.c generado por xsubpp
(línea 11).
cc -c -I. -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" Example.cEl compilador y las opciones del compilador usadas son las mismas que se emplearon para construir la instalación actual del intérprete Perl. Los valores con los que la versión usada de Perl fue compilada pueden obtenerse por medio del módulo Config . Por ejemplo:
lhp@nereida:~/Lperl/src/XSUB$  perl -MConfig -e 'print Config::myconfig()'
Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
  Platform:
    osname=linux, osvers=2.6.15.4, archname=i486-linux-gnu-thread-multi
    uname='linux ninsei 2.6.15.4 #1 smp preempt mon feb 20 09:48:53 pst 2006\
                                             i686 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN
    -Dcccdlflags=-fPIC -Darchname=i486-linux-gnu
    -Dprefix=/usr -Dprivlib=/usr/share/perl/5.8
    -Darchlib=/usr/lib/perl/5.8 -Dvendorprefix=/usr
    -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5
    -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.8.8
    -Dsitearch=/usr/local/lib/perl/5.8.8 -Dman1dir=/usr/share/man/man1
    -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1
    -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl
    -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Uusesfio -Uusenm
    -Duseshrplib -Dlibperl=libperl.so.5.8.8 -Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
! Compiler:
!   cc='cc', ccflags ='-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',
!   optimize='-O2',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN 
             -fno-strict-aliasing -pipe -I/usr/local/include'
    ccversion='', gccversion='4.0.3 (Debian 4.0.3-1)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.3.6.so, so=so, useshrplib=true, libperl=libperl.so.5.8.8
    gnulibc_version='2.3.6'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'
Config.
Observe que la librería se deja en el directorio
blib/arch/auto/Example/ (línea 18).
!13 chmod 644 Example.bs !14 rm -f blib/arch/auto/Example/Example.so !15 cc -shared -L/usr/local/lib Example.o -o blib/arch/auto/Example/Example.so \ 16 \ 17 !18 chmod 755 blib/arch/auto/Example/Example.so !19 cp Example.bs blib/arch/auto/Example/Example.bs !20 chmod 644 blib/arch/auto/Example/Example.bs 21 Manifying blib/man3/Example.3pm
Para probar el módulo escribimos un programa de prueba:
lhp@nereida:~/Lperl/src/XSUB/Example$ cat -n useexample.pl 1 #!/usr/bin/perl -w 2 use blib; # Para que encuentre el módulo 3 use strict; 4 use Example; 5 6 my $n = shift || 1000; 7 my $x = 0; 8 9 $x += Example::computepi(0,$n,4) for 0..3; 10 print "$x\n"; lhp@nereida:~/Lperl/src/XSUB/Example$ time ./useexample.pl 1000 3.14459174129814 real 0m0.032s user 0m0.020s sys 0m0.010s lhp@nereida:~/Lperl/src/XSUB/Example$ time ./useexample.pl 10000000 3.14159295358978 real 0m0.359s user 0m0.360s sys 0m0.000s
 
