Perl's PAR::Packer is a great way to write (albeit bloated) Win32 apps for clients in a short time. I find this useful for taking on jobs spec'd for Windows or a *nix project that you'd like obfuscated by virtue of distributing a binary.
PAR is actually neat for a lot of things. It creates a compressed archive of libraries for simple recall. The PAR that is generated is not all together too different then Java's notion of a JAR. PAR has surprisingly seamless integration with LWP::UserAgent, in that, you can include modules in a PAR from across the network by simply using it.
# Including a par in $INC
$ perl -MPAR=./foo -MHello
# Using PAR::Repository::Client to include a repo of PARS
use PAR { repository => 'http://example.com/foo/bar/' };
# Using PAR::Repository::Client to execute a PAR locally
use PAR { repository => 'http://example.com/', run => 'foo.par' }
# Include a specific PAR across the network.
use PAR;
use lib ('http://example.com/test.par');The Packer!!
This is my favorite part about PAR! The packer (albeit awfully named) is pretty much the coolest thing since... I got nothin.. It can be a pain in the ass to install, but is well worth it. Jump to "Tips" for installation tips and common issues.
Compiled on a Win32 platform we generate Win32 binaries! Compiled on a *nix platform we generate mostly-valid elf binaries! Observe..
$ cat par_test.pl #!/usr/bin/perl print "Hello World!\n"; $ ./par_test.pl Hello World! $ pp -o par_test par_test.pl $ file par_test par_test: Mach-O executable i386 $ ./par_test Hello World!
Note: YMMV, this example was generated on an Intel MAC. You will obviously recieve different `file` output based on your system.
The execution time is drastically increased based on the bloat of the executable. Notice the filesize diffs...
$ ls -lah par_test par_test.pl -rwxr-xr-x 1 ghettocode staff 3.8M Sep 3 13:56 par_test -rwxr-xr-x 1 ghettocode staff 41B Sep 3 13:55 par_test.pl
The reason for this bloat is parpacker is including the entire interpretter any needed LIBS into the executable. Including a lot more libs will increase the size of your binary as it literally follows the dependancy tree and packs everything needed into the binary. If your application is very performance oriented this may not be the best solution for you.
I'm assuming it's possible to leak code by running binutils against the executable, but good luck sifting through Interpretter code and par code.
PAR Inclusion. How it Works.
Including a .par will prepend a coderef into @INC allowing you to include modules as if they were in @INC.
$ perl -MPAR=./Hello.par -Mscript::World -e '$, = " \n"; print @INC;' CODE(0x8294e4) /opt/local/lib/perl5/site_perl/5.8.9/darwin-2level /opt/local/lib/perl5/site_perl/5.8.9 /opt/local/lib/perl5/site_perl /opt/local/lib/perl5/vendor_perl/5.8.9/darwin-2level /opt/local/lib/perl5/vendor_perl/5.8.9 /opt/local/lib/perl5/vendor_perl /opt/local/lib/perl5/5.8.9/darwin-2level /opt/local/lib/perl5/5.8.9 .
I'm still not entirely sure how this works. Dumping the code ref spits back a 'DUMMY' handler.
$ perl -MPAR=./Hello.par -MData::Dumper -e "print Dumper \@INC[0];"
$VAR1 = \sub { "DUMMY" };A Brief Example
$ pp -p -o Hello.par Hello/World.pm
$ ls
Hello Hello.par
$ unzip -l Hello.par
Archive: Hello.par
Length Date Time Name
-------- ---- ---- ----
434 09-03-09 14:17 MANIFEST
216 09-03-09 14:17 META.yml
66 09-03-09 14:17 script/World.pm
274 09-03-09 14:17 script/main.pl
-------- -------
990 4 filesThe PAR's directory structure is influenced by the way you create the par. Supplying the dir Hello/ to `pp` yields a different directory structure. Observe.
$ perl -MPAR=./Hello.par -Mscript::World -e "print Hello::World->hello();" Hello World
*NIX Tips
I've seen quite a few different error conditions while installing this module. Because I'm lazy, I'd rather fix up the problems and install via CPAN rather then installing by hand. The most common I've seen is supplying duplicate make options. I'm not entirely sure why this happens but if $CPAN::Config includes something tantamount to 'make_opts' => '-j3', proceeded by 'make_install_opts' => '-j3'
$ cat ~/.cpan/CPAN/MyConfig.pm
$CPAN::Config = {
'foo' => 'bar',
'make_opts' => '-j3',
'make_install_opts' => '-j3'
}This somehow translates into CPAN throwing make duplicate '-j3' opts, which results in epic failure.
SMUELLER/PAR-Packer-0.991.tar.gz /usr/bin/make -j3 -j3 -- NOT OK Running make test Can't test without successful make Running make install Make had returned bad status, install seems impossible Failed during this command: SMUELLER/PAR-Packer-0.991.tar.gz : make NO
Removing these options from the file and restarting CPAN, and *NOT* supplying -j3 when prompted will result in smooth sailing for installing PAR::Packer.
I'm also not sure what this shit is about, but it doesn't seem to be fatal. I'm assuming it has to do with special compile time options to add things to @INC. In my case I'm running the osX ports version of perl which compiles a whole bunch of /opt/ dirs into @INC. I guess my understanding of this error message would be better if I knew wtf 'taint mode' was.
*** You have extra Perl library paths set in your environment.
Please note that these paths (set with PERL5LIB or PERLLIB)
are not honored by perl when running under taint mode, which
may lead to problems. This is a limitation (by design) of
Perl, not of PAR::Packer; but some of the problems may
manifest here during installation.Win32 Tips
This process *REALLY* sucks!!! I sat down for quite awhile trying to figure out how to do this, and here's what I've come up with.
1. Don't use ActiveState perl.
- Building this module requires Dmake, which does not ship
with Active State. As an alternative, Strawberry Perl
Ships with Dmake and various other useful things.
2. Don't use this on a system with Cygwin.
- If you can get this working, you're god damn awesome.
Cygwin takes the liberty of installing a second build
of Perl in $PATH and completely fucks up your lib path.
Uninstalling Cygwin is not really an adventure in
awesome. Just don't do it.
3. Dmake is way hotter then Cygwin GCC.
- See Above.Thats it. I will revise this article as necessary.