El Módulo P5NCI

La siguiente subrutina _hcf calcula el máximo común divisor de dos números. El código es ''puro cálculo'' por lo que la implementación Perl es obviamente inferior en rendimiento a la correspondiente versión C:

$ cat -n hcf.c
 1  int hcf(int x, int y) {
 2    int t;
 3
 4    if (y > x) {
 5      t = x; x = y; y = t;
 6    }
 7    if (x == y) return x;
 8    while (y) {
 9      t = x;
10      x = y;
11      y = t % y;
12    }
13    return x;
14  }

Compilación

Para poder llamar a la versión C de la subrutina desde Perl lo único que necesitamos es crear una librería dinámica:

$ cc  -shared  hcf.o -o libhcf.so
$ ls -ltr | tail -1
-rwxr-xr-x  1 lhp lhp 5446 2007-05-29 16:52 libhcf.so
$ nm libhcf.so                  # nm nos lista los símbolos en la librería 
00001650 A __bss_start
000003c0 t call_gmon_start
00001650 b completed.4463
00001558 d __CTOR_END__
00001554 d __CTOR_LIST__
         w __cxa_finalize@@GLIBC_2.1.3
000004f0 t __do_global_ctors_aux
000003f0 t __do_global_dtors_aux
00001648 d __dso_handle
00001560 d __DTOR_END__
0000155c d __DTOR_LIST__
00001568 a _DYNAMIC
00001650 A _edata
00001654 A _end
00000534 T _fini
00000450 t frame_dummy
00000550 r __FRAME_END__
00001634 a _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
0000048c T hcf                    # Nuestra función máximo común divisor
00000485 t __i686.get_pc_thunk.bx
0000036c T _init
00001564 d __JCR_END__
00001564 d __JCR_LIST__
         w _Jv_RegisterClasses
0000164c d p.4462

LLamada desde Perl

El módulo P5NCI permite cargar la librería desde Perl y llamar a las funciones:

$ cat -n usehcf.pl
 1  #!/usr/local/bin/perl -w
 2  use strict;
 3  use P5NCI::Library;
 4
 5  my $lib = P5NCI::Library->new( library => './libhcf.so' );
 6  $lib->install_function( 'hcf', 'iii' );
 7
 8  print hcf( 20, 10 ), "\n";
 9  print hcf( 12, 9 ), "\n";
10  print hcf( 18, 12 ), "\n";
La llamada a P5NCI::Library->new carga la librería. La subsiguiente llamada al método install busca la función en la librería y crea una interfaz Perl para la especificación dada por la firma 'iii'. Esta firma indica que la función recibe dos enteros y devuelve un entero. Observe que mediante P5NCI es posible usar funciones cuyo fuente no esta disponible. Tampoco importa en que lenguaje esté escrito. Importa que dispongamos de la librería y que conozcamos el nombre y la interfaz de la función.

El constructor admite la opción path que permite especificar el path de búsqueda para la librería. En este caso podemos usar el ''nombre'' oficial de la librería (hcf) y no la especifciación completa. También dispone de una opción package que permite especificar el paquete en el que se aloja la función.

$ cat -n usehcf2.pl
 1  #!/usr/local/bin/perl -w
 2  use strict;
 3  use P5NCI::Library;
 4
 5  my $lib = P5NCI::Library->new( library => 'hcf', path => '.' );
 6  print "Path de búsqueda:\n@DynaLoader::dl_library_path\n";
 7  $lib->install_function( 'hcf', 'iii' );
 8
 9  print "hcf( 20, 10 ) = ",hcf( 20, 10 ), "\n";
10  print "hcf( 12,  9 ) = ",hcf( 12, 9 ), "\n";
11  print "hcf( 18, 12 ) = ",hcf( 18, 12 ), "\n";

La variable DynaLoader::dl_library_path contiene el camino de búsqueda de las librerías dinámicas.

Ejecución

Ahora al ejecutar el programa obtenemos el máximo común divisor para cada una de las tres parejas:

$ usehcf2.pl
Path de búsqueda:
. /usr/local/lib /lib /usr/lib
hcf( 20, 10 ) = 10
hcf( 12,  9 ) = 3
hcf( 18, 12 ) = 6

La portabilidad de P5NCI

La portabilidad de P5NCI es todavía insuficiente. El porcentaje de plataformas en las que funciona es bajo aún. Existen otros mecanismos para empotrar otros lenguajes en Perl: XS, Inline, etc. que son mas robustos.



Subsecciones
Casiano Rodríguez León
2012-02-29