tags:

views:

174

answers:

2

I'm currently using the PAR Packer (pp) to package a couple of pl scripts such that they can be copied to a machine and "just work" without my client having to muck with CPAN.

Unfortunately, the PAR Packer doesn't work for deep dependencies. For example, a script imports CHI::Driver::File but does not explicitly import Log::Any::Adapter::Null which CHI::Driver::File requires. PAR does not pick up this dependency and running the generated script will crash with the following error message:

Can't locate Log/Any/Adapter/Null.pm in @INC (@INC contains: CODE(0x874aab8) /tmp/par-apache/cache-7b4508ab92efb43271da1629e8eb654c1572cc55/inc/lib /tmp/par-apache/cache-7b4508ab92efb43271da1629e8eb654c1572cc55/inc CODE(0x87e8f54) CODE(0x87e9194)) at (eval 215) line 3.
Compilation failed in require at CHI/Driver/File.pm line 11.
BEGIN failed--compilation aborted at CHI/Driver/File.pm line 11.

My work-around is to explicitly import "Log::Any::Adapter::Null" but there must be a better way. Perhaps this is a bug with the PAR Packer? I have installed the latest version (0.994).

+3  A: 

Well, have you read the documentation? It gives a number of command-line options to include dependencies, and even the option to manually force modules to be included.

AmbroseChapel
Thank you Brad. I have indeed read the documentation and nowhere in the documentation does the PAR Packer specify that any particular flags are required in order to generate a stand-alone script.In fact, the documentation clearly states: "pp creates standalone executables from Perl programs, using the compressed packager provided by PAR, and dependency detection heuristics offered by Module::ScanDeps. Source files are compressed verbatim without compilation."This is exactly what I'm looking for but unfortunately it doesn't work. Any ideas?
Jono
+1  A: 

If you want a stand-alone script as opposed to a stand-alone binary (which is the default mode for pp), then add the -P option. I'd advise against it, though. It's the least-tested mode of operation.

Note also that PAR::Packer DOES work for deep dependencies. The subject of your question is a bit pretentious. In fact, PAR::Packer doesn't really check any dependencies itself but delegates this to Module::ScanDeps. Now, Module::ScanDeps is a heuristic approach to dependency scanning and it can be broken by ugly fuzzing with dynamic loading of dependencies. (i.e. generating module names at run time and then using them in an eval).

Indeed, if you look at the sources for Log::Any (which is used by CHI::Driver::File), you'll quickly see that it uses dynamic loading of modules. This is why the ::Adapter::Null module isn't being picked up.

Generally, we fix these issues by adding a special case to Module::ScanDeps for such modules whose author thought it'd be a good idea to defeat any sort of static analysis. Until you get a fixed version of Module::ScanDeps, you can use the -c or -x options to pp to have the dependency resolution use compilation or execution of the program instead of only relying on static analysis. The augmented Module::ScanDeps has version 0.95 and should be available from CPAN within the day.

tsee
Module::ScanDeps 0.95 has arrived on CPAN. Cf. http://search.cpan.org/dist/Module-ScanDeps/
tsee
Thanks very much Steffen, this is quite clear.
Jono
I would also like to point out that pp -c must be execute in the same directory as the script being package or you will end up with an incorrect @INC (presupposing you are including your own perl modules that exist in another directory and are using either a BEGIN block to push @INC or the "use lib" module).This was giving me no end of trouble in attempting to use pp -c to package my script.
Jono