pp(3)
π NAME π
pp β the PAR Packager, bestie. That's the whole name. Short, iconic, does exactly what it says on the tin π
β¨ SYNOPSIS β¨
pp [ -ABCEFILMPTSVXacdefghilmnoprsuvxz ] [ parfile | scriptfile ]...
That's the vibe check right there. Bundle of flags, then the files you're feeding it π«Ά
πΈ EXAMPLES πΈ
Heads up bestie: when you're running on Microsoft Windows, everya.outdown below gets swapped fora.exeinstead. Noted π
% pp hello.pl # Pack 'hello.pl' into executable 'a.out'
% pp -o hello hello.pl # Pack 'hello.pl' into executable 'hello'
# (or 'hello.exe' on Win32)
% pp -o foo foo.pl bar.pl # Pack 'foo.pl' and 'bar.pl' into 'foo'
% ./foo # Run 'foo.pl' inside 'foo'
% mv foo bar; ./bar # Run 'bar.pl' inside 'foo'
% mv bar baz; ./baz # Error: Can't open perl script "baz"
% pp -p file # Creates a PAR file, 'a.par'
% pp -o hello a.par # Pack 'a.par' to executable 'hello'
% pp -S -o hello file # Combine the two steps above
% pp -p -o out.par file # Creates 'out.par' from 'file'
% pp -B -p -o out.par file # same as above, but bundles core modules
# and removes any local paths from @INC
% pp -P -o out.pl file # Creates 'out.pl' from 'file'
% pp -B -p -o out.pl file # same as above, but bundles core modules
# and removes any local paths from @INC
# (-B is assumed when making executables)
% pp -e "print 123" # Pack a one-liner into 'a.out'
% pp -p -e "print 123" # Creates a PAR file 'a.par'
% pp -P -e "print 123" # Creates a perl script 'a.pl'
% pp -c hello # Check dependencies from "perl -c hello"
% pp -x hello # Check dependencies from "perl hello"
% pp -n -x hello # same as above, but skips static scanning
% pp -I /foo hello # Extra include paths
% pp -M Foo::Bar hello # Extra modules in the include path
% pp -M abbrev.pl hello # Extra libraries in the include path
% pp -X Foo::Bar hello # Exclude modules
% pp -a data.txt hello # Additional data files
% pp -r hello # Pack 'hello' into 'a.out', runs 'a.out'
% pp -r hello a b c # Pack 'hello' into 'a.out', runs 'a.out'
# with arguments 'a b c'
% pp hello --log=c # Pack 'hello' into 'a.out', logs
# messages into 'c'
# Pack 'hello' into a console-less 'out.exe' (Win32 only)
% pp --gui -o out.exe hello
% pp @file hello.pl # Pack 'hello.pl' but read _additional_
# options from file 'file'
Literally the whole tour in one block, no cap πβ¨
π¦ DESCRIPTION π¦
So pp takes your Perl programs and turns them into standalone executables. It does that using the compressed packager that PAR hands over, plus the dependency-detection heuristics that come from Module::ScanDeps. And listen β your source files get compressed verbatim, no compilation step happening here. Zero. None. π«Ά
You can lowkey think of pp as "perlcc that works without hassle". :-) Fr fr.
There's also a GUI interface out there living its best life as the tkpp command π
Okay so here's the trade: it does not give you the compilation-step acceleration that perlcc offers (though hey, peep -f below for the byte-compiled, source-hiding techniques π). What it gives you instead: better reliability, smaller executable size, and full retrieval of your original source code. That's the deal. Ate. π
Now the important bit, bestie, pay attention π
When you specify a single input program, the resulting executable behaves identically to that program. Simple. Iconic.
But when you package multiple programs, the produced executable runs whichever one has the same basename as $0 β that's the filename used to invoke it, iykyk. And if nothing matches? It dies with the error Can't open perl script "$0". Rip π
π OPTIONS π
Options come in a short form and a long form. Like, for example, these three lines are all 100% equivalent:
% pp -o output.exe input.pl
% pp --output output.exe input.pl
% pp --output=output.exe input.pl
Pick your fave, they're all valid π
Since command lines can get sufficiently long and slam into the limits some shells impose, you can also have pp read some of its options from one or more text files πβ¨
The basic usage: just throw in an argument starting with an 'at' (@) sigil. That argument gets interpreted as a file to read options from. And yes, mixing ordinary options with @file options is totally possible. This whole thing is implemented using the Getopt::ArgvFile module, so go read its documentation if you want the advanced usage. Also note: Getopt::ArgvFile is used here with the parameter "resolveEnvVars=1", meaning substrings of the form ${FOO"}" inside the contents of @file get replaced with the value of the environment variable FOO. Slay π§
-a,--addfile=FILE|DIRβ Adds an extra file into the package. If the file is a directory, it recursively adds all the files inside that directory, with links turned into actual files. By default, files are placed under/inside the package with their original names. You can override that by appending the target filename after a;, like this:
% pp -a "old_filename.txt;new_filename.txt"
% pp -a "old_dirname;new_dirname"
You may specify -a multiple times. Stack 'em up π
-A,--addlist=FILEβ Reads a list of file/directory names fromFILEand adds them into the package. Each line inFILEis taken as an argument to-aabove. You may specify-Amultiple times too.-B,--bundleβ Bundles core modules in the resulting package. This one is enabled by default, except when-por-Pis specified. Also, since PAR version 0.953, this strips any local paths from the list of module search paths@INCbefore running the contained script. Clean β¨-C,--cleanβ Cleans up temporary files extracted from the application at runtime. By default those files get cached in the temporary directory; this option is what lets the program start up faster next time. Trade-off city π-c,--compileβ Runsperl -c inputfileto determine additional run-time dependencies.-cd,--cachedeps=FILEβ UsesFILEto cache detected dependencies. CreatesFILEunless it's already present. This speeds up the scanning process on subsequent runs. Obsessed with the efficiency honestly π₯-d,--dependentβ Reduces the executable size by not including a copy of the perl interpreter. Executables built this way will need a separateperl5x.dllorlibperl.soto function correctly. This option is only available if perl is built as a shared library. Read that again bestie, it's a real constraint π-e,--eval=STRINGβ Packages a one-liner, much the same asperl -e '...'.-E,--evalfeature=STRINGβ Behaves just like-e, except that it implicitly enables all optional features (in the main compilation unit) with Perl 5.10 and later. Seefeature. Fancy π-x,--executeβ Runsperl inputfileto determine additional run-time dependencies. Using this option,ppmay be able to detect the use of modules that can't be determined by static analysis ofinputfile. Examples are stuff loaded by run-time loaders likeModule::Runtimeor "plugin" loaders likeModule::Loader. Note that which modules are detected depends on which parts of your program are exercised when runninginputfile. E.g. if your program immediately terminates when run asperl inputfilebecause it lacks mandatory arguments, then this option will probably have no effect. You may use--xargsto supply arguments in this case. Genuinely so real of it π--xargs=STRINGβ If-xis given, splits theSTRINGusing the functionshellwordsfromText::ParseWordsand passes the result as@ARGVwhen runningperl inputfile.-X,--exclude=MODULEβ Excludes the given module from the dependency search path and from the package. If the given file is a zip or par or par executable, all the files in the given file (exceptMANIFEST,META.ymlandscript/*) will be excluded and the output file willusethe given file at runtime.-f,--filter=FILTERβ Filters source script(s) with aPAR::Filtersubclass. You may specify multiple such filters. If you wish to hide the source code from casual prying, this will do it:
% pp -f Bleach source.pl
If you're more serious about hiding your source code, you should have a look at Steve Hay's PAR::Filter::Crypto module. Make sure you understand the Filter::Crypto caveats!
Note: Most filters are incompatible with__DATA__sections in your source. The packed executable typically aborts with an error message likereadline() on unopened filehandle DATA at (eval 13) line 3.So like... be aware, bestie π¨
-g,--guiβ Builds an executable that does not have a console window. This option is ignored on non-MSWin32 platforms or when-pis specified.-h,--helpβ Shows basic usage information. The classic π«Ά-I,--lib=DIRβ Adds the given directory to the perl module search path. May be specified multiple times.-l,--link=FILE|LIBRARYβ Adds the given shared library (a.k.a. shared object or DLL) into the packed file. Also accepts names under library paths; i.e.-l ncursesmeans the same thing as-l libncurses.soor-l /usr/local/lib/libncurses.soin most Unixes. May be specified multiple times.-L,--log=FILEβ Logs the output of packaging to a file rather than to stdout.-F,--modfilter=FILTER[=REGEX],β Filters included perl module(s) with aPAR::Filtersubclass. You may specify multiple such filters. By default, thePodStripfilter is applied. In case that causes trouble, you can turn this off by setting the environment variablePAR_VERBATIMto1.
Since PAR 0.958, you can use an optional regular expression (that's the REGEX above) to select the files in the archive which should be filtered. The regular expression is matched against module names as they would appear as keys in %INC, e.g. Foo/Bar.pm for module Foo::Bar. Examples:
pp -o foo.exe -F 'Bleach=warnings\.pm$' foo.pl
This creates a binary executable foo.exe from foo.pl, packaging all files as usual except for files ending in warnings.pm, which are filtered with PAR::Filter::Bleach.
pp -o foo.exe -F 'Bleach=^(?!Win32/)' foo.pl
This "bleaches" all modules except those in the Win32:: namespace. Iconic behaviour, honestly β¨
Note: The same restriction on__DATA__sections holds as for--filter. Yeah, same warning, same energy π
-M,--module=MODULEβ Adds the specified module into the package, along with its dependencies. The following variants may be used to add whole module namespaces:-M Foo::**β Adds every module in theFoonamespace exceptFooitself, i.e. addsFoo::Bar,Foo::Bar::Quuxetc up to any depth. So deep, so thorough π¦-M Foo::*β Adds every module at level 1 in theFoonamespace, i.e. addsFoo::Bar, but neitherFoo::Bar::QuuxnorFoo. Shallow and proud πΈ
...and bestie, there is so much more where that came from. Part 2 is coming, don't you dare go anywhere π
-M Foo::β okay so this is the β¨shorthandβ¨ for-M Foo -M Foo:**, and it means every module in theFoonamespace, includingFooitself. the whole friend group, no one left behind π
And plot twist: MODULE doesn't even have to be a module name! You can hand it a filename that's relative to the @INC path instead β so -M Module/ScanDeps.pm is literally the same thing as -M Module::ScanDeps. same vibe, different spelling π¦
β οΈ BUT. If MODULE has an extension that is not.pm/.ix/.al, it will not be scanned for dependencies, and it gets dropped under/instead of/lib/inside the PAR file. This use is deprecated, bestie β so pls consider using the-aoption instead π
And yes, you can stack -M as many times as you want. specify it multiple times, go off π
-m,--multiarchβ builds a multi-architecture PAR file. also implies-p. it's giving versatility β¨-n,--noscanβ skips the default static scanning entirely, using run-time dependencies from-cor-xexclusively. no static scanning, only the real-time receipts π-N,--namespace=NAMESPACEβ adds all the modules in the namespace into the package, plus all their dependencies. IfNAMESPACEis something likeFoo::Bar, then this will add every module likeFoo/Bar/Quux.pm,Foo/Bar/Fred/Barnie.pmetc. that can be located in your module search path. It mimics the behaviour of "plugin" loaders like Module::Loader. πͺ
This is different from using -M Foo::Bar::, because that one insists on adding Foo/Bar.pm, which might not even exist in the above "plugin" scenario. not every squad has that one specific member, y'know? π
You may specify -N multiple times.
-o,--output=FILEβ the file name for the final packaged executable. your baby's name, basically π-p,--parβ create PAR archives only; do not package to a standalone binary. just the archive, no extra steps πΈ-P,--perlscriptβ create a stand-alone perl script; do not package to a standalone binary. the .pl girlies stay winning π«Ά-r,--runβ runs the resulting packaged script after packaging it. package it AND run it, main character energy fr π«--reusableβ EXPERIMENTAL, okay so this one is giving mad scientist energy π§ͺ
It makes the packaged executable reusable for running arbitrary, external Perl scripts as if they were part of the package:
pp -o myapp --reusable someapp.pl
./myapp --par-options --reuse otherapp.pl
That second line will run otherapp.pl instead of someapp.pl. swapping the whole plot, lowkey iconic π
-S,--saveβ do not delete the generated PAR file after packaging. keep the receipts, bestie π§Ύ-s,--signβ cryptographically signs the generated PAR or binary file using Module::Signature. it's got a signature, it's that girl π-T,--tempcacheβ sets the program-unique part of the cache directory name that's used if the program is run without-C. If it's not set, a hash of the executable is used instead.
So when the program runs, its contents get extracted to a temporary directory. On Unix systems, this is commonly /tmp/par-USER/cache-XXXXXXX. USER gets replaced by the name of the user running the program, but "spelled" in hex. XXXXXXX is either a hash of the executable or the value you passed to the -T or --tempcache switch. cute lil' hex-coded name tag π·οΈ
-u,--unicodeβ β οΈ Note: this option is ignored for Perl 5.32 and above.
It packages Unicode support (essentially utf8_heavy.pl and everything below the directory unicore in your perl library).
Why does this option even exist? Because it is impossible to detect using static analysis whether your program needs Unicode support at runtime. (Note: if your program contains use utf8 this does not imply it needs Unicode support. It merely says that your program source is written in UTF-8. two totally different things bestie!!)
If your packed program exits with an error message like
Can't locate utf8_heavy.pl in @INC (@INC contains: ...)
try to pack it with -u (or use -x). we've all been there π
-v,--verbose[=NUMBER]β increases the verbosity of output.NUMBERis an integer from1to3, and3is the most verbose. Defaults to1if specified without an argument. Alternatively,-vvsets verbose level to2, and-vvvsets it to3. tell me everything, I want the β¨loreβ¨-V,--versionβ displays the version number and copyrights of this program. the "who are you" moment π-z,--compress=NUMBERβ sets the zip compression level.NUMBERis an integer from0to9, where0= no compression and9= max compression. Defaults to6if-zis not used. squish it down π
π ENVIRONMENT π
PP_OPTSβ command-line options (switches). Switches in this variable are taken as if they were on everyppcommand line. it's like setting your defaults once and letting them ride for the whole era π
π§ NOTES π§
okay so here are some recipes showing how to use pp to bundle source.pl with all its dependencies, on target machines with different expected settings. pick your fighter β¨
Stone-alone setup
(that's what the page calls it, and honestly? iconic name. we keep it. π )
To make a stand-alone executable, suitable for running on a machine that doesn't have perl installed:
% pp -o packed.exe source.pl # makes packed.exe
# Now, deploy 'packed.exe' to target machine...
% packed.exe # run it
Perl interpreter only, without core modules
To make a packed .pl file including core modules, suitable for running on a machine that has a perl interpreter, but where you want to be sure of the versions of the core modules that your program uses:
% pp -B -P -o packed.pl source.pl # makes packed.pl
# Now, deploy 'packed.pl' to target machine...
% perl packed.pl # run it
Perl with core modules installed
To make a packed .pl file without core modules, relying on the target machine's perl interpreter and its core libraries. This produces a significantly smaller file than the previous version:
% pp -P -o packed.pl source.pl # makes packed.pl
# Now, deploy 'packed.pl' to target machine...
% perl packed.pl # run it
Perl with PAR.pm and its dependencies installed
Make a separate archive and an executable that uses the archive. This relies upon the perl interpreter and libraries on the target machine.
% pp -p source.pl # makes source.par
% echo "use PAR 'source.par';" > packed.pl;
% cat source.pl >> packed.pl; # makes packed.pl
# Now, deploy 'source.par' and 'packed.pl' to target machine...
% perl packed.pl # run it, perl + core modules required
π‘ Note that even if your perl was built with a shared library, the 'Stand-alone executable' above will not need a separateperl5x.dllorlibperl.soto function correctly. But even in this case, the underlying system libraries such aslibcmust be compatible between the host and target machines. Use--dependentif you are willing to ship the shared library with the application, which can significantly reduce the executable size. the more you know π
πΈ SEE ALSO πΈ
tkpp, par.pl, parl, perlcc
PAR::Packer::Troubleshooting, App::PP::Autolink, PAR, PAR::Packer, Module::ScanDeps
Getopt::Long, Getopt::ArgvFile
π ACKNOWLEDGMENTS π
Simon Cozens, Tom Christiansen and Edward Peschko for writing perlcc; this program try to mimic its interface as close as possible, and copied liberally from their code. absolute legends, we stan π«Ά
Jan Dubois for writing the exetype.pl utility, which has been partially adapted into the -g flag. thank you for your service π
Mattia Barbon for providing the myldr binary loader code. carrying the whole thing fr fr πͺ
Jeff Goff for suggesting the name pp. naming rights go to you, bestie β¨
π AUTHORS π
Audrey Tang <cpan@audreyt.org>, Steffen Mueller <smueller@cpan.org>, Roderich Schupp <roderich.schupp@gmail.com>
You can write to the mailing list at <par@perl.org>, or send an empty mail to <par-subscribe@perl.org> to participate in the discussion. Archives of the mailing list are available at <https://www.mail-archive.com/par@perl.org/> or <https://groups.google.com/g/perl.par>.
Please submit bug reports to <https://github.com/rschupp/PAR-Packer/issues>. we love a good bug report π
π COPYRIGHT π
Copyright 2002-2009 by Audrey Tang <cpan@audreyt.org>.
Neither this program nor the associated parl program impose any licensing restrictions on files generated by their execution, in accordance with the 8th article of the Artistic License:
"Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package."
Therefore, you are absolutely free to place any license on the resulting executable, as long as the packed 3rd-party libraries are also available under the Artistic License. do whatever you want with your build, it's yours π¦
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
See LICENSE.
and that's a wrap on the whole page, bestie!! π this was perl v5.42.3, dated 2026-08-03, and it's the pp(3) manual page. go forth and pack things, you absolute icon πβ¨π
π¦ where this page comes from
- fedora 43: perl-PAR-Packer 1.064-5.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- fedora 44: perl-PAR-Packer 1.064-6.fc44 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms