.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "PAR::Packer::Troubleshooting 3" .TH PAR::Packer::Troubleshooting 3 2025-07-14 "perl v5.42.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME PAR::Packer::Troubleshooting \- Common Problems Packing Scripts with pp .SH SYNOPSIS .IX Header "SYNOPSIS" Explain some common problems and remedies when packing scripts with \fIpp\fR. .SH DESCRIPTION .IX Header "DESCRIPTION" .SS "Missing modules" .IX Subsection "Missing modules" When you run the packed executable, it aborts with a message similar to .PP .Vb 3 \& Can\*(Aqt 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. .Ve .PP Your script \f(CW\*(C`require\*(C'\fRs module \f(CW\*(C`Foo::Bar\*(C'\fR (perhaps indirectly from another module), but \fIpp\fR did not pack it into the executable. \&\fIpp\fR uses Module::ScanDeps to recursively scan your script for \&\f(CW\*(C`require\*(C'\fRed modules. Sometimes this scan is incomplete due to the many ways Perl allows you to express your desire to load a module. .PP Try to pack with options \fB\-\-compile\fR or \fB\-\-execute\fR to resolve the problem. If this fails, explicitly add the indicated module with option \fB\-M\fR, i.e. .PP .Vb 1 \& % pp \-M Foo::Bar ... .Ve .PP You may have to repeat adding modules, the wildcard variants of \&\fB\-M\fR may come in handy here. .SS "Missing native DLLs" .IX Subsection "Missing native DLLs" The packed executable runs fine on the machine where it was generated, but aborts with a message similar to the following when run on another machine (that may not have Perl installed) .PP .Vb 2 \& Can\*(Aqt load \*(AqC:\eUsers\emyuser\eAppData\eLocal\eTemp\e3\epar\-74686f6b65\etemp\-1772\einc\elib/auto/Net/SSLeay/SSLeay.dll\*(Aq for module Net::SSLeay: \& load_file:The specified module could not be found at /DynaLoader.pm line 206. at /PAR/Heavy.pm line 95. .Ve .PP Here the DLL part (\fI.../auto/Net/SSLeay/SSLeay.dll\fR) of an XS module (Net::SSLeay) \&\fBhas\fR been packed, but it\*(Aqs linked against a native DLL that has \fBnot\fR been packed. The native DLL is obviously present on the machine used to pack, but not on the other machine. Note that \fIpp\fR (or rather Module::ScanDeps) does \fBnot\fR detect such a non\-Perl dependency and hence won\*(Aqt pack the native DLL, you would have to add it by hand (using option \fB\-\-link\fR). .PP \&\fBTL;DR\fR Use \fIpp_autolink\fR from \f(CW\*(C`App::PP::Autolink\*(C'\fR to automate packing in native DLLs and be done with it or read on for the gory details. .PP Inspecting \fI.../auto/Net/SSLeay/SSLeay.dll\fR (using tools like \fIobjdump\fR) shows that it\*(Aqs linked against native DLLs \fIlibssl*.dll\fR and \fIlibcrypto*.dll\fR. These DLLs come from \fIOpenSSL\fR. Note the wildcards in the above filenames, they stand for version numbers. Once you have the exact filenames, you can add theses DLLs to the \fIpp\fR command line with \f(CW\*(C`\-\-link ...\*(C'\fR. But we\*(Aqre not done: \fIlibcrypto*.dll\fR is typically linked against \fIlibz*.dll\fR, so you have to \f(CW\*(C`\-\-link ...\*(C'\fR that one, too. Note that this example uses the Windows specific suffix ".dll", but the problem also exists on Linux or macOS. .SS """Attempt to reload ... aborted. Compilation failed in require ...""" .IX Subsection """Attempt to reload ... aborted. Compilation failed in require ...""" There are several scenarios where "Attempt to reload ..." can be emitted: it\*(Aqs just an indication that a previous \f(CW\*(C`require\*(C'\fR of \fIsomething\fR failed, but this error was suppressed, and then \fIsomething\fR was \f(CW\*(C`require\*(C'\fRd again. The original error would have told us the actual reason, but it\*(Aqs gone. .PP Here\*(Aqs an example, \fIfoo.pl\fR. .PP .Vb 3 \& 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; .Ve .PP Now run .PP .Vb 2 \& % 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. .Ve .PP Uncomment the line with the arrow to see the actual reason: "Can\*(Aqt locate Quux.pm in \f(CW@INC\fR ... at Bar.pm line 1.", i.e. \fIQuux.pm\fR is missing. Note that the original error message doesn\*(Aqt mention "Quux.pm". .PP Now try this: .PP .Vb 7 \& % echo "{" > Quux.pm # yes, that\*(Aqs 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. .Ve .PP 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 \fIQuux.pm\fR exists, but could not be loaded due to a syntax error. There are other reason why loading a module might fail, e.g. "Missing native DLLs". .PP Here\*(Aqs a recipe to narrow down the problem. Add the following \&\fBbefore the first Perl statement\fR of \fIfoo.pl\fR: .PP .Vb 10 \& BEGIN { \& my $required; \& unshift @INC, sub { \& (undef, $required) = @_; \& my (undef, $filename, $line) = caller(); \& print STDERR "require $required from ${filename}:${line}\en"; \& return; \& }; \& push @INC, sub { print STDERR "MISSING $required\en"; return; }; \& } .Ve .PP This logs any attempt to \f(CW\*(C`require\*(C'\fR \fIsomething\fR including the call site. It can\*(Aqt record whether the \f(CW\*(C`require\*(C'\fR succeeded nor the error in case it failed. But if the failure is simply a missing module, it will print "MISSING \fIsomething\fR". .PP Now try the two variants above again. Here\*(Aqs the "missing module" case (showing only \f(CW\*(C`stderr\*(C'\fR): .PP .Vb 11 \& 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. .Ve .PP and the "failing to load" case: .PP .Vb 10 \& 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. .Ve .PP So the strategy to find the cause for "Attempt to reload \fIsomething\fR" is: .IP \(bu 4 Find the first occurence of "require> \fIsomething\fR" in the ouput. .IP \(bu 4 Walk down the "call chain" of nested \f(CW\*(C`require\*(C'\fRs while staying "below" \fIsomething\fR. The culprit is typically the last module mentioned on a "require ... from ..." line. .IP \(bu 4 If the next line is "MISSING \fIsomething\fR" then it\*(Aqs a case of "Missing modules" with \fIsomething\fR the culprit. Otherwise it\*(Aqs a failure to load \fIsomething\fR, probably "Missing native DLLs". .PP In the above example the "call chain" is .PP .Vb 1 \& foo.pl \-> Foo.pm \-> Bar.pm \-> Quux.pm .Ve .PP (\fIText/ParseWords.pm\fR is \f(CW\*(C`require\*(C'\fRd from \fIfoo.pl\fR, hence "above" \fIFoo.pm\fR). This would implicate \fIQuux.pm\fR. Note that the "call chain" doesn\*(Aqt have to look regular like above, that\*(Aqs only the case if all \f(CW\*(C`require\*(C'\fRs stem from \f(CW\*(C`use\*(C'\fR statements that are executed at \fBcompile\fR time. The picture may be skewed if \fBruntime\fR \f(CW\*(C`require\*(C'\fR statement are used. .SH "SEE ALSO" .IX Header "SEE ALSO" pp, App::PP::Autolink, PAR, PAR::Packer .SH COPYRIGHT .IX Header "COPYRIGHT" Copyright 2025 by Roderich Schupp . .PP This document is free documentation; you can redistribute it and/or modify it under the same terms as Perl itself. .PP See \fILICENSE\fR.