PAR::Intro - Introduction to Perl Archive Toolkit
# This is a presentation, not a module.
Do what JAR (Java Archive) does for Perl
Benefits of using PAR:
par@perl.org
You can also turn a PAR file into a self-contained script
pp
to compile the script...
First, generate a PAR file with modules in it:
% zip foo.par Hello.pm % zip -r foo.par lib/ # grab all modules in lib/
Using modules stored inside a PAR file:
% perl -MPAR=./foo.par -MHello % perl -MPAR=./foo -MHello # the .par part is optional
Or put it in @INC and use it just like a directory:
% perl -MPAR -Ifoo.par -MHello % perl -MPAR -Ifoo -MHello # ditto
Use pp
to scan scripts and store dependencies as a PAR file:
% pp -p source.pl # makes 'source.par' % pp -B -p source.pl # bundles core modules too
Use par.pl
to run files from a Perl Archive:
% par.pl foo.par # looks for 'main.pl' by default % par.pl foo.par test.pl # runs script/test.pl in foo.par
Use parl
or parl.exe
to run files from a Perl Archive:
% parl foo.par % parl foo.par test.pl
The pp
utility can also generate binary executables:
% pp -o packed.exe source.pl # self-contained .exe % packed.exe # runs anywhere with the same OS
You can also bundle additional modules:
# packs CGI + its dependencies, too % pp -o packed.exe -M CGI source.pl
Or pack one-liners:
# turns one-liner into executable % pp -o packed.exe -e 'print "Hi!"'
Some notes:
pp
are almost identical to perlcc
's
Modules can reside in different directories in a PAR file:
/lib/ # standard location /arch/ # for creating from blib/ /i386-freebsd/ # i.e. $Config{archname} /5.8.0/ # i.e. Perl version number /5.8.0/i386-freebsd/ # combination of the two above / # casual packaging only
Scripts are stored in one of the two locations:
/script/ # standard location / # casual packaging only
Shared libraries are currently stored in a single location: /shlib/ # standard location =item *
Special files:
/MANIFEST # index of the PAR's contents /SIGNATURE # digital signature(s) /META.yml # dependency, license info, etc. /Build.PL # self-contained installer
PAR::read_file($filename)
to read file contents inside PAR
Apache::PAR
App::Packer::Backend::PAR
CPANPLUS::Dist::PAR
In httpd.conf
:
<VirtualHost *> <IfDefine MODPERL2> PerlModule Apache::ServerUtil </IfDefine> PerlModule Apache::PAR PARDir /opt/myapp PARFile /opt/myapp/myapp.par </VirtualHost>
In web.conf
inside myapp.par
:
Alias /myapp/static/ ##PARFILE##/ <Location /myapp/static> SetHandler perl-script PerlHandler Apache::PAR::Static PerlAddVar PARStaticDirectoryIndex index.html PerlSetVar PARStaticDefaultMIME text/html </Location>
Alias /myapp/cgi-perl/ ##PARFILE##/ <Location /myapp/cgi-perl> Options +ExecCGI SetHandler perl-script PerlHandler Apache::PAR::Registry </Location>
Polish pp
's features
Learning from JAR
Learning from FreeBSD Bento
Here begins the scary part
PAR invokes five areas of Perl arcana:
The first two only works on 5.6 or later
On 1999-07-19, Ken Fox submitted a patch to P5P
Code references in @INC may return a filehandle, or undef to 'pass':
push @INC, \&my_sub; sub my_sub { my ($coderef, $filename) = @_; # $coderef is \&my_sub open my $fh, "wget http://example.com/$filename |"; return $fh; # using remote modules, indeed! }
Perl 5.8 let you open a file handle to a string, so we just use that:
open my $fh, '<', \($zip->memberNamed($filename)->contents); return $fh;
... Undocumented features to the rescue!
This is how Acme::use::strict::with::pride
works:
# Force all modules used to use strict and warnings open my $fh, "<", $filename or return; my @lines = ("use strict; use warnings;\n", "#line 1 \"$full\"\n"); return ($fh, sub { return 0 unless @lines; push @lines, $_; $_ = shift @lines; return length $_; });
But we don't really have a filehandle for anything
We can actually omit the first return value altogether:
# Return all contents line-by-line from the file inside PAR my @lines = split /(?<=\n)/, $zip->memberNamed($filename)->contents; return (sub { $_ = shift(@lines); return length $_ });
The @INC filter stops when it sees __END__
or __DATA__
eval
the main.pl script
Therefore, we insert a line before the final token to fake *DATA
Here is what I came up with (but no longer needed in recent versions):
$DATACache{$file} = $1 if ($program =~ s/^__DATA__\n?(.*)//ms); if (eval {require PerlIO::scalar; 1}) { "use PerlIO::scalar". " ( open(*DATA, '<:scalar', \\\$PAR::DATACache{'$key'}) ? () : () )"; } elsif (eval {require IO::Scalar; 1}) { # This will first load IO::Scalar, *then* tie the handles. "use IO::Scalar". " ( tie(*DATA, 'IO::Scalar', \\\$PAR::DATACache{'$key'}) ? () : () )"; } else { # only dies when it's used "use PAR (tie(*DATA, 'PAR::_data') ? () : ())\n"; } sub PAR::_data::TIEHANDLE { return bless({}, shift) } sub PAR::_data::AUTOLOAD { die "Please install IO::Scalar first!\n" }
XS modules have dynamically loaded libraries (.so
or .dll
)
auto/
directories
Module names are passed to bootstrap
for XS loading
dl_findfile
to locate the file
So we wrap around both functions:
no strict 'refs'; no warnings 'redefine'; $bootstrap = \&DynaLoader::bootstrap; $dl_findfile = \&DynaLoader::dl_findfile; *{'DynaLoader::bootstrap'} = \&_bootstrap; *{'DynaLoader::dl_findfile'} = \&_dl_findfile;
Our _bootstrap
just checks if the library is in PARs
If yes, extract it to a File::Temp temp file
$bootstrap
_dl_findfile
intercepts known filenames and return it
The par script ($0) itself
Any number of embedded files
One PAR file
"PK\003\004"
Ending section
"\012PAR.pm\012"
All we can expect is a working perl interpreter
Solution: bundle all module and object files needed by PAR.pm
FILE
section in the previous slide is for
We want to minimize the amount of temporary files
First, try getting PerlIO::scalar loaded
tempfile()
This can be so much easier if we have a pure-perl inflate()
http://www.autrijus.org/par-intro/ (English version)
http://www.autrijus.org/par-intro.zh/ (Chinese version)
ex::lib::zip, Acme::use::strict::with::pride
App::Packer, Apache::PAR, CPANPLUS, Module::Install
Autrijus Tang <autrijus@autrijus.org>
PAR has a mailing list, <par@perl.org>, that you can write to; send an empty mail to <par-subscribe@perl.org> to join the list and participate in the discussion.
Please send bug reports to <bug-par@rt.cpan.org>.
Copyright 2002, 2003 by Autrijus Tang <autrijus@autrijus.org>.
This document is free documentation; you can redistribute it and/or modify it under the same terms as Perl itself.