PAR: The Perl Archive Toolkit

El módulo PAR permite usar ficheros .zip que siguen un formato denominado Perl Archives.

Ficheros .par Simples

En una primera aproximación podemos decir que un fichero .par es un fichero zip que contiene módulos.

Supongamos que estoy en una máquina (orion) que tiene instalado el módulo Parse::Eyapp:

casiano@orion:/usr/local/share/perl/5.8.8$ perldoc -l Parse::Eyapp
/usr/local/share/perl/5.8.8/Parse/Eyapp.pm
Para crear un fichero .par basta con llamar a zip:
casiano@orion:/usr/local/share/perl/5.8.8$ zip -r /tmp/orionparse.par Parse/
updating: Parse/ (stored 0%)
updating: Parse/Eyapp.pm (deflated 69%)
updating: Parse/Eyapp/ (stored 0%)
updating: Parse/Eyapp/Lalr.pm (deflated 74%)
updating: Parse/Eyapp/YATW.pm (deflated 64%)
updating: Parse/Eyapp/Treeregexp.pm (deflated 77%)
updating: Parse/Eyapp/Parse.pm (deflated 78%)
updating: Parse/Eyapp/Scope.pm (deflated 61%)
updating: Parse/Eyapp/Options.pm (deflated 63%)
updating: Parse/Eyapp/Output.pm (deflated 60%)
updating: Parse/Eyapp/Node.pm (deflated 72%)
updating: Parse/Eyapp/Grammar.pm (deflated 71%)
updating: Parse/Eyapp/Driver.pm (deflated 70%)
updating: Parse/Eyapp/Base.pm (deflated 52%)
updating: Parse/Eyapp/_TreeregexpSupport.pm (deflated 50%)
La opción -r hace que zip recorra la estructura de directorios recursivamente.

Ahora transferimos el fichero /tmp/orionparse.par a una máquina (nereida) en la cual no esta instalado Parse::Eyapp:

lhp@nereida:~/Lperl/src$ scp orion:/tmp/orionparse.par .
orionparse.par                        100%  105KB 105.0KB/s   00:00
Utilizando PAR podemos cargar el módulo Parse::Eyapp desde el fichero /tmp/orionparse.par
lhp@nereida:~/Lperl/src$ perl -wde 0
main::(-e:1):   0
  DB<1> use PAR 'orionparse.par'
  DB<2> use Parse::Eyapp
  DB<3> print $Parse::Eyapp::VERSION
1.082
  DB<4>
Tambien podemos hacerlo con un one-liner:

lhp@nereida:~/Lperl/src$ perl -MPAR=orionparse.par -MParse::Eyapp -e 'print "$Parse::Eyapp::VERSION\n"'
1.082

Ejecutables en un .par

Es posible añadir ficheros ejecutables a un fichero .par. El módulo Parse::Eyapp viene con el ejecutable eyapp. Añadámoslo al fichero .par:

casiano@orion:/usr/local/share/perl/5.8.8$ which eyapp
/usr/local/bin/eyapp
casiano@orion:/usr/local/share/perl/5.8.8$ cd /usr/local/bin/
casiano@orion:/usr/local/bin$ zip -r /tmp/orionparse.par eyapp
  adding: eyapp (deflated 59%)
casiano@orion:/usr/local/bin$

Transferimos de nuevo el fichero .par a la máquina nereida:

lhp@nereida:~/Lperl/src$ scp orion:/tmp/orionparse.par .
orionparse.par                          100%  108KB 108.0KB/s   00:00
Siempre es posible listar los ficheros que forman parte de una distribución usando unzip con la opción -l:
lhp@nereida:~/Lperl/src$ unzip -l orionparse.par
Archive:  orionparse.par
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  11-02-07 12:40   Parse/
   135815  11-01-07 13:14   Parse/Eyapp.pm
        0  11-02-07 12:40   Parse/Eyapp/
    29574  09-17-07 16:38   Parse/Eyapp/Lalr.pm
     8178  09-17-07 16:17   Parse/Eyapp/YATW.pm
    51402  11-01-07 13:17   Parse/Eyapp/Treeregexp.pm
    52766  11-01-07 13:17   Parse/Eyapp/Parse.pm
    11069  09-17-07 16:40   Parse/Eyapp/Scope.pm
     6314  09-17-07 16:39   Parse/Eyapp/Options.pm
     8826  09-17-07 17:53   Parse/Eyapp/Output.pm
    23784  09-17-07 16:17   Parse/Eyapp/Node.pm
    13832  09-17-07 16:38   Parse/Eyapp/Grammar.pm
    17865  11-01-07 13:05   Parse/Eyapp/Driver.pm
     3673  09-17-07 16:37   Parse/Eyapp/Base.pm
     3296  09-17-07 16:40   Parse/Eyapp/_TreeregexpSupport.pm
     7102  11-02-07 12:40   eyapp
        0  07-10-08 10:22   Math/
        0  08-08-08 12:08   Math/Prime/
     5635  05-14-08 15:30   Math/Prime/XS.pm
 --------                   -------
   379131                   19 files
El programa par.pl permite ejecutar ficheros en un archivo .par:
lhp@nereida:~/Lperl/src$ par.pl orionparse.par eyapp -V
This is Parse::Eyapp version 1.082.
Por defecto par.pl busca por un ejecutable con nombre main.pl.

También puedo extraer el ejecutable:

lhp@nereida:~/Lperl/src/tmp$ unzip orionparse.par eyapp
Archive:  orionparse.par
  inflating: eyapp
y a continuación ejecutarlo usando el módulo PAR:
lhp@nereida:~/Lperl/src/tmp$ perl -MPAR=orionparse.par eyapp -V
This is Parse::Eyapp version 1.082.

Empaquetado de Modulos XS

PAR soporta la carga de módulos XS (véase perlxs). XS es un formato para la descripción de interfases entre código C y código Perl. Veamos un ejemplo. La sesión se inicia como administrador arrancando cpan para a continuación descargar el módulo Math::Prime::XS el cual, como su nombre indica, tiene partes escritas en C:

root@orion:~# cpan

cpan shell -- CPAN exploration and modules installation (v1.7602)
ReadLine support enabled
El comando
look Math::Prime::XS
que emitimos a continuación indica que queremos abrir una shell en el directorio de la distribución de Math::Prime::XS. Si el módulo no está actualizado, cpan procederá a descargarse la última versión antes de abrir una shell:
cpan> look Math::Prime::XS
CPAN: Storable loaded ok
Going to read /root/.cpan/Metadata
  Database was generated on Fri, 08 Aug 2008 03:02:59 GMT
CPAN: LWP::UserAgent loaded ok
Fetching with LWP:
  ftp://perl.di.uminho.pt/pub/CPAN/authors/01mailrc.txt.gz
Going to read /root/.cpan/sources/authors/01mailrc.txt.gz
CPAN: Compress::Zlib loaded ok
Fetching with LWP:
  ftp://perl.di.uminho.pt/pub/CPAN/modules/02packages.details.txt.gz
Going to read /root/.cpan/sources/modules/02packages.details.txt.gz
  Database was generated on Thu, 21 Aug 2008 02:03:21 GMT
Fetching with LWP:
  ftp://perl.di.uminho.pt/pub/CPAN/modules/03modlist.data.gz
Going to read /root/.cpan/sources/modules/03modlist.data.gz
Going to write /root/.cpan/Metadata
Running look for module Math::Prime::XS

Trying to open a subshell in the build directory...
CPAN: Digest::MD5 loaded ok
Checksum for /root/.cpan/sources/authors/id/S/SC/SCHUBIGER/Math-Prime-XS-0.20.tar.gz ok
Scanning cache /root/.cpan/build for sizes
Math-Prime-XS-0.20/
Math-Prime-XS-0.20/Changes
Math-Prime-XS-0.20/lib/
Math-Prime-XS-0.20/lib/Math/
Math-Prime-XS-0.20/lib/Math/Prime/
Math-Prime-XS-0.20/lib/Math/Prime/XS.pm
Math-Prime-XS-0.20/ppport.h
Math-Prime-XS-0.20/MANIFEST
Math-Prime-XS-0.20/XS.xs
Math-Prime-XS-0.20/t/
Math-Prime-XS-0.20/t/pod-coverage.t
Math-Prime-XS-0.20/t/calc_primes.t
Math-Prime-XS-0.20/t/pod.t
Math-Prime-XS-0.20/t/00-load.t
Math-Prime-XS-0.20/INSTALL
Math-Prime-XS-0.20/Build.PL
Math-Prime-XS-0.20/META.yml
Math-Prime-XS-0.20/Makefile.PL
Math-Prime-XS-0.20/README
Removing previously used /root/.cpan/build/Math-Prime-XS-0.20
Working directory is /root/.cpan/build/Math-Prime-XS-0.20
Aunque la sesión ha sido arrancada como root podría haberla hecho como un usuario ordinario. El único objetivo era descargar la distribución de Math::Prime::XS y posicionarse en el correspondiente directorio.
root@orion:~/.cpan/build/Math-Prime-XS-0.20# ls -l
total 204
-r--r--r-- 1 csegura csegura    786 2008-05-14 15:30 Build.PL
-r--r--r-- 1 csegura csegura   1445 2008-05-14 15:30 Changes
-r--r--r-- 1 csegura csegura    290 2008-05-14 15:30 INSTALL
drwxr-xr-x 3 csegura csegura   4096 2008-05-14 15:30 lib
-r--r--r-- 1 csegura csegura    498 2008-05-14 15:30 Makefile.PL
-r--r--r-- 1 csegura csegura    172 2008-05-14 15:30 MANIFEST
-r--r--r-- 1 csegura csegura    560 2008-05-14 15:30 META.yml
-r--r--r-- 1 csegura csegura 154956 2008-05-14 15:30 ppport.h
-r--r--r-- 1 csegura csegura   5033 2008-05-14 15:30 README
drwxr-xr-x 2 csegura csegura   4096 2008-05-14 15:30 t
-r--r--r-- 1 csegura csegura   4843 2008-05-14 15:30 XS.xs
Construimos la distribución siguiendo el procedimiento habitual:
root@orion:~/.cpan/build/Math-Prime-XS-0.20# perl Makefile.PL
Checking if your kit is complete...
Looks good
Writing Makefile for Math::Prime::XS
root@orion:~/.cpan/build/Math-Prime-XS-0.20# make
cp lib/Math/Prime/XS.pm blib/lib/Math/Prime/XS.pm
/usr/bin/perl /usr/local/share/perl/5.8.8/ExtUtils/xsubpp  \
            -typemap /usr/share/perl/5.8/ExtUtils/typemap  \
                         XS.xs > XS.xsc && mv XS.xsc XS.c
cc -c   -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.20\" -DXS_VERSION=\"0.20\" -fPIC "-I/usr/lib/perl/5.8/CORE"   XS.c
Running Mkbootstrap for Math::Prime::XS ()
chmod 644 XS.bs
rm -f blib/arch/auto/Math/Prime/XS/XS.so
cc  -shared -L/usr/local/lib XS.o  -o blib/arch/auto/Math/Prime/XS/XS.so    
chmod 755 blib/arch/auto/Math/Prime/XS/XS.so
cp XS.bs blib/arch/auto/Math/Prime/XS/XS.bs
chmod 644 blib/arch/auto/Math/Prime/XS/XS.bs
Manifying blib/man3/Math::Prime::XS.3pm
El aspecto mas notable de esta construcción es que se ha llamado al compilador de C. Las opciones pasadas al compilador han sido las mismas que se usaron en la instalación de Perl en la plataforma en uso. Ahora cambiamos al directorio de construcción blib:
root@orion:~/.cpan/build/Math-Prime-XS-0.20# cd blib
En el directorio arch está la librería .so (shared object). En el directorio lib esta el módulo Perl .pm que contiene la interfaz Perl a las funciones C:
root@orion:~/.cpan/build/Math-Prime-XS-0.20/blib# tree
.
|-- arch
|   `-- auto
|       `-- Math
|           `-- Prime
|               `-- XS
|                   |-- XS.bs
|                   `-- XS.so
|-- bin
|-- lib
|   |-- Math
|   |   `-- Prime
|   |       `-- XS.pm
|   `-- auto
|       `-- Math
|           `-- Prime
|               `-- XS
|-- man1
|-- man3
|   `-- Math::Prime::XS.3pm
`-- script
Para construir el fichero .par usamos zip añadiendo los directorios arch y lib. los contenidos de
root@orion:~/.cpan/build/Math-Prime-XS-0.20/blib# zip -r /tmp/primexs.par arch/ lib/
  adding: arch/ (stored 0%)
  adding: arch/.exists (stored 0%)
  adding: arch/auto/ (stored 0%)
  adding: arch/auto/Math/ (stored 0%)
  adding: arch/auto/Math/Prime/ (stored 0%)
  adding: arch/auto/Math/Prime/XS/ (stored 0%)
  adding: arch/auto/Math/Prime/XS/.exists (stored 0%)
  adding: arch/auto/Math/Prime/XS/XS.so (deflated 59%)
  adding: arch/auto/Math/Prime/XS/XS.bs (stored 0%)
  adding: lib/ (stored 0%)
  adding: lib/Math/ (stored 0%)
  adding: lib/Math/Prime/ (stored 0%)
  adding: lib/Math/Prime/.exists (stored 0%)
  adding: lib/Math/Prime/XS.pm (deflated 59%)
  adding: lib/auto/ (stored 0%)
  adding: lib/auto/Math/ (stored 0%)
  adding: lib/auto/Math/Prime/ (stored 0%)
  adding: lib/auto/Math/Prime/XS/ (stored 0%)
  adding: lib/auto/Math/Prime/XS/.exists (stored 0%)
root@orion:~/.cpan/build/Math-Prime-XS-0.20/blib#
Es habitual que un fichero .par este fundamentalmente constituído por los contenidos del directorio blib/ construido a partir de una distribución CPAN.

Ahora transferimos el fichero /tmp/primexs.par a una máquina que carece de los módulos en dicho fichero, pero que es binario-compatible con la máquina en la que se realizó la construcción:

lhp@nereida:~/Lperl/src$ perldoc -l Math::Prime::XS
No documentation found for "Math::Prime::XS".
Después de la transferencia estamos en condiciones de usar el módulo Math::Prime::XS utilizando via PAR la distribucion primexs.par:
lhp@nereida:~/Lperl/src$ scp orion:/tmp/primexs.par .
primexs.par                             100%   11KB  11.4KB/s   00:00
lhp@nereida:~/Lperl/src$ vi prime3.pl
lhp@nereida:~/Lperl/src$ cat -n prime3.pl
     1  #!/usr/bin/perl -I../lib -w
     2  use PAR "primexs.par";
     3  use Math::Prime::XS qw{:all};
     4
     5  @all_primes   = primes(9);
     6  print "@all_primes\n";
     7
     8  @range_primes = primes(4, 9);
     9  print "@range_primes\n";
El programa se ejecuta sin errores produciendo la salida esperada:
lhp@nereida:~/Lperl/src$ prime3.pl
2 3 5 7
5 7
Por supuesto, el éxito de esta ejecución depende de la compatibilidad binaria de ambas plataformas (orion y nereida)

Uso de Módulos via Web

Es posible utilizar ficheros PAR cuya localización está en una máquina remota:

   use PAR "http://orion.pcg.ull.es/~casiano/primexs.par";
En este escenario PAR cargará los módulos solicitados desde el repositorio PAR situado en http://foo/bar/. Por supuesto debemos el fichero .par deberá estar en la máquina remota (en el ejemplo que sigue orion). Copiamos el .par construido anteriormente en el directorio que contiene nuestros HTML publicos:
casiano@orion:~/public_html$ cp /tmp/primexs.par .
casiano@orion:~/public_html$ pwd
/home/casiano/public_html
casiano@orion:~/public_html$ ls -ltr | tail -1
-rw-r--r--  1 casiano casiano         11685 2008-08-23 12:57 primexs.par
Ahora podemos ejecutar en la máquina cliente nereida un programa que hace uso del repositorio situado en orion:
lhp@nereida:~/Lperl/src$ cat -n prime4.pl
   1  #!/usr/bin/perl -I../lib -w
   2  use PAR "http://orion.pcg.ull.es/~casiano/primexs.par";
   3  use Math::Prime::XS qw{:all};
   4
   5  @all_primes   = primes(9);
   6  print "@all_primes\n";
   7
   8  @range_primes = primes(4, 9);
   9  print "@range_primes\n";
El programa se ejecuta normalmente:
lhp@nereida:~/Lperl/src$ prime4.pl
2 3 5 7
5 7



Subsecciones
Casiano Rodríguez León
2009-10-04