PAR::Pa...hooting(3)

๐Ÿ’… PAR::Packer::Troubleshooting โ€” no wait, the whole manual name is PAR::Packer::Troubleshooting(3), bestie

okay so real talk: this is the User Contributed Perl Documentation page for PAR::Packer::Troubleshooting, and it is literally the "why is my packed script crying" survival guide. ๐Ÿซถ

โœจ NAME โœจ

PAR::Packer::Troubleshooting โ€” Common Problems Packing Scripts with pp ๐Ÿ’–

๐ŸŒธ SYNOPSIS ๐ŸŒธ

It explains some common problems and their remedies when you're packing scripts with pp. That's the whole vibe. โœจ

๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

๐ŸŽ€ Missing modules ๐ŸŽ€

So you run the packed executable and it just aborts on you with a message that looks like this:

Can't locate Foo/Bar.pm in @INC (you may need to install the Foo::Bar module)
  (@INC contains: ...) at script/pp5yBDq.pl line 1.
BEGIN failed--compilation aborted at script/pp5yBDq.pl line 1.

What happened: your script requires the module Foo::Bar (maybe indirectly, through some other module), but pp did not pack it into the executable. ๐Ÿ˜ญ

Here's the tea: pp uses Module::ScanDeps to recursively scan your script for required modules. But sometimes that scan comes up incomplete โ€” because Perl gives you, like, so many ways to say "I want to load a module." It's giving main character energy with the options.

Try packing with the options --compile or --execute to resolve the problem. If that fails, explicitly add the indicated module with option -M, i.e.

% pp -M Foo::Bar ...

Ngl you may have to keep repeating the "add modules" step, and the wildcard variants of -M will absolutely come in handy here. ๐Ÿ‘‘

๐Ÿ’€ Missing native DLLs ๐Ÿ’€

The packed executable runs fine on the machine where it was generated, but then it aborts with a message similar to the following when you run it on another machine (one that may not even have Perl installed):

Can't load 'C:\Users\myuser\AppData\Local\Temp\3\par-74686f6b65\temp-1772\inc\lib/auto/Net/SSLeay/SSLeay.dll' for module Net::SSLeay:
  load_file:The specified module could not be found at <embedded>/DynaLoader.pm line 206. at <embedded>/PAR/Heavy.pm line 95.

So what's happening here? The DLL part (.../auto/Net/SSLeay/SSLeay.dll) of an XS module (Net::SSLeay) has been packed โ€” but it's linked against a native DLL that has not been packed. ๐Ÿ™ˆ The native DLL is obviously present on the machine used to pack, just not on the other machine. And note: pp (or rather Module::ScanDeps) does not detect that kind of non-Perl dependency, so it won't pack the native DLL โ€” you'd have to add it by hand (using option --link).

TL;DR use pp_autolink from App::PP::Autolink to automate packing in native DLLs and be done with it, or read on for the gory details. ๐Ÿ“

Inspecting .../auto/Net/SSLeay/SSLeay.dll (using tools like objdump) shows that it's linked against the native DLLs libssl*.dll and libcrypto*.dll. Those DLLs come from OpenSSL. Note the wildcards in the filenames above โ€” they stand for version numbers. Once you have the exact filenames, you can add these DLLs to the pp command line with --link .... But bestie, we're not done: libcrypto*.dll is typically linked against libz*.dll, so you have to --link ... that one too. ๐Ÿ˜ฎโ€๐Ÿ’จ

Also note: this example uses the Windows-specific suffix .dll, but the problem also exists on Linux or macOS. โœจ

๐ŸŒˆ "Attempt to reload ... aborted. Compilation failed in require ..." ๐ŸŒˆ

There are several scenarios where Attempt to reload ... can be emitted. It's just an indication that a previous require of something failed, but that error got suppressed, and then something got required again. The original error would have told us the actual reason, but it's gone. ๐Ÿ’€

Here's an example, foo.pl:

use strict;
use warnings;
use feature qw( say state );

eval {
    say "first Foo";
    require Foo;
};
#say "require failed: $@" if $@;   # <---

say "Text::ParseWords ...";
require Text::ParseWords;

say "second Foo";
require Foo;

Now run

% echo "use Bar; 1;" > Foo.pm
% echo "use Quux; 1;" > Bar.pm

% perl -I. foo.pl
first Foo
Text::ParseWords ...
second Foo
Attempt to reload Foo.pm aborted.
Compilation failed in require at foo.pl line 28.

Uncomment the line with the arrow to see the actual reason: Can't locate Quux.pm in @INC ... at Bar.pm line 1. โ€” i.e. Quux.pm is missing. And note that the original error message doesn't mention Quux.pm. ๐Ÿ˜ญ

Now try this:

% echo "{" > Quux.pm        # yes, that's a syntax error
% perl -I. foo.pl
first Foo
Text::ParseWords ...
second Foo
Attempt to reload Foo.pm aborted.
Compilation failed in require at foo.pl line 28.

Same output as above. Again, uncomment the line with the arrow to see the actual reason: Missing right curly or square bracket at Quux.pm line 1 ... syntax error at Quux.pm line 1, at EOF. So Quux.pm exists, but it could not be loaded because of a syntax error. There are other reasons why loading a module might fail, e.g. Missing native DLLs.

Here's a recipe to narrow down the problem. Add the following before the first Perl statement of foo.pl:

BEGIN {
    my $required;
    unshift @INC, sub {
        (undef, $required) = @_;
        my (undef, $filename, $line) = caller();
        print STDERR "require $required from ${filename}:${line}\n";
        return;
    };
    push @INC, sub { print STDERR "MISSING $required\n"; return; };
}

This logs any attempt to require something, including the call site. It can't record whether the require succeeded, nor the error in case it failed. But if the failure is simply a missing module, it will print MISSING something. ๐Ÿ•ต๏ธโ€โ™€๏ธ

Now try the two variants above again. Here's the "missing module" case (showing only stderr):

require strict.pm from foo.pl:14
require warnings.pm from foo.pl:15
require feature.pm from foo.pl:16
require Foo.pm from foo.pl:22
require Bar.pm from Foo.pm:1
require Quux.pm from Bar.pm:1
MISSING Quux.pm
require Text/ParseWords.pm from foo.pl:27
require Exporter.pm from /usr/lib/x86_64-linux-gnu/perl-base/Text/ParseWords.pm:8
Attempt to reload Foo.pm aborted.
Compilation failed in require at foo.pl line 28.

and the "failing to load" case:

require strict.pm from foo.pl:14
require warnings.pm from foo.pl:15
require feature.pm from foo.pl:16
require Foo.pm from foo.pl:22
require Bar.pm from Foo.pm:1
require Quux.pm from Bar.pm:1
require Text/ParseWords.pm from foo.pl:27
require Exporter.pm from /usr/lib/x86_64-linux-gnu/perl-base/Text/ParseWords.pm:8
Attempt to reload Foo.pm aborted.
Compilation failed in require at foo.pl line 28.

So the strategy to find the cause for Attempt to reload something is:

  • Find the first occurrence of require something in the output.
  • Walk down the "call chain" of nested requires while staying "below" something. The culprit is typically the last module mentioned on a require ... from ... line.
  • If the next line is MISSING something then it's a case of Missing modules, with something as the culprit. Otherwise it's a failure to load something, probably Missing native DLLs.

In the above example the "call chain" is

foo.pl -> Foo.pm -> Bar.pm -> Quux.pm

(Text/ParseWords.pm is required from foo.pl, hence "above" Foo.pm). This would implicate Quux.pm. Note that the "call chain" doesn't have to look regular like above โ€” that's only the case if all requires stem from use statements that are executed at compile time. The picture may be skewed if runtime require statements are used. ๐ŸŒ€


๐Ÿ‘€ SEE ALSO ๐Ÿ‘€

pp, App::PP::Autolink, PAR, PAR::Packer

Copyright 2025 by Roderich Schupp <roderich.schupp@gmail.com>.

This document is free documentation; you can redistribute it and/or modify it under the same terms as Perl itself.

See LICENSE.


mwah ๐Ÿ’‹ that was perl v5.42.3, dated 2026-11-03, from the PAR::Pa...hooting(3) page โ€” go pack something iconic bestie ๐Ÿ‘‘โœจ

๐Ÿ“ฆ where this page comes from