NAME
PAX - Perl Adaptive eXecution compiler and standalone binary packager
VERSION
Current release version is kept in our $VERSION in this module and mirrored to every lib/PAX/*.pm module before release.
SYNOPSIS
perl bin/pax help
perl bin/pax build
perl bin/pax build -o ./build/my-app bin/my-app
perl bin/pax run -- version
perl bin/pax run bin/my-app -- version
DESCRIPTION
PAX turns a Perl entrypoint plus its repeatable build inputs into a standalone executable. The executable can include compiled code units, native artifacts where supported, asset payloads, dependency payloads, and a runtime launcher.
The project is deliberately neutral. Core compiler, packaging, loader, runtime, and dispatch code must not embed assumptions about one application, company, or module namespace.
INTRODUCTION
PAX exists to change the deployment shape of a Perl application.
Without PAX, a Perl application commonly depends on some mix of the original source tree, a host Perl installation, host CPAN modules, asset directories next to the app, and local bootstrap scripts or container images that carry the whole working tree.
PAX aims to turn that into one executable that can carry compiled code units, runtime payloads, embedded assets, and native artifacts where a region can be proven safe to specialize.
In bundled-runtime mode that includes the packaged helper programs and the linked shared libraries and SONAME aliases required by bundled XS modules, so helper commands and query/runtime helpers still work after the original source tree and CPAN installation are gone.
The goal is not to pretend every Perl feature can become a native binary with no trade-offs. The real goal is:
keep Perl correctness
keep fallback execution explicit
package applications into one binary
move eligible hot paths toward native speed
stay neutral across arbitrary Perl projects
WHAT YOU GET
one public command surface with
pax buildandpax runa repeatable build contract through
paxfile.ymlone standalone executable output
embedded asset packaging for web applications and static payloads
runtime payload packaging for source-tree-free execution
packaged helper commands plus linked XS shared libraries and SONAME aliases for source-tree-free execution
self-hosted build capability, including building
bin/paxitselfDocker-friendly multi-stage packaging
MAIN CONCEPTS
Public Facade
PAX::CLI owns the public operator contract behind pax build and pax run.
Manifest Loading
PAX::Paxfile loads repeatable build inputs from paxfile.yml.
Standalone Image Builder
PAX::StandaloneImage collects dependencies, packages runtime payloads, embeds assets, and writes the standalone launcher.
Code Unit Compilation
PAX::CodeUnitCompiler lowers supported Perl source shapes into PAX code unit records. Unsupported regions remain on explicit fallback paths instead of being silently miscompiled.
Packaged Runtime
PAX::StandaloneRuntime provides the packaged helper runtime used after the standalone executable starts.
Native Dispatch
PAX::StandaloneDispatch and related runtime pieces execute packaged native regions and deopt fallback behavior under the standalone model.
SOW-03 PUBLIC COMMAND SURFACE
PAX exposes only two public commands through bin/pax:
buildCompile and package the source tree behind an entrypoint into one standalone executable.
runRun the same build flow and then execute the resulting binary with arguments after
--.
The canonical usage is:
pax build ...
pax run ...
Common CLI switches include:
--paxfile,--no-paxfile-I, to prepend Perl library directories for inline builds/runs-M, to load and import Perl modules for inline builds/runs-e, to synthesize an entrypoint from inline Perl code--lib,--source-root,--cpanfile,--asset,--asset-dir--output/-o--runtime-mode--compact
Internal diagnostics and validation modules remain available as Perl APIs for the test suite and release gates. They are not public bin/pax subcommands.
PAXFILE CONTRACT
When no positional entrypoint is supplied, build and run read paxfile.yml by default. --paxfile selects a different manifest and --no-paxfile disables manifest loading. When a positional entrypoint is supplied on the CLI, PAX treats that target as an isolated build and does not silently inherit libs, source_roots, assets, asset_dirs, cpanfiles, or app metadata from the ambient paxfile.yml. An explicit --paxfile still applies its manifest defaults.
Supported manifest keys:
nameentrypointlibssource_rootsassetsasset_dirscpanfilesoutputruntime_modeapp_name,app_namespace,app_entrypoint_env,app_entrypoint_fallback,app_command
CLI flags override file values. Output path precedence is:
MANUAL
Installation
For development from a repository checkout:
cpanm --installdeps .
perl bin/pax help
For release packaging:
cpanm Dist::Zilla
First Build
The simplest workflow is a local paxfile.yml:
name: example-app
entrypoint: bin/example-app
output: build/example-app
libs:
- lib
cpanfiles:
- cpanfile
runtime_mode: bundled_perl
Then build:
perl bin/pax build
Long builds print a DD-style task rundown on stderr by default. On a real terminal the board redraws live; in non-interactive runs it prints a static rundown while the machine-readable build payload stays on stdout. The build path is broken into concrete checkpoints such as code-unit compilation, application metadata inference, dependency analysis, native artifact analysis, manifest writing, and launcher compilation. The code-unit phase is further split into source discovery, entrypoint compilation, application unit compilation, and dependency unit compilation so long builds keep moving visibly. Application unit compilation includes the current file name, so a slow module no longer looks like a frozen counter. Set PAX_PROGRESS=0 to suppress the rundown.
And run the result directly:
./build/example-app
Build Without paxfile.yml
When the CLI provides the required shape, paxfile.yml is optional:
perl bin/pax build -o ./build/example-app bin/example-app
That keeps one-off builds and self-hosting neutral even inside repositories that ship their own paxfile.yml. Extra roots, assets, and CPAN policy files must be declared explicitly on the CLI in that mode.
Inline entrypoints use the same public surface. -I adds Perl library roots, -M loads/imports modules before execution, and -e supplies the entrypoint code directly:
perl bin/pax build \
-I lib \
-MDateTime \
-e 'print DateTime->now'
pax run accepts the same switches:
perl bin/pax run \
-I lib \
-MDateTime \
-e 'print DateTime->now'
Self Compile
PAX can build itself:
perl bin/pax build -o /tmp/pax bin/pax
/tmp/pax help
That self-built binary can then build another standalone application from its own paxfile.yml. A self-built standalone pax binary can also rebuild from another standalone pax binary input after the original source tree has been removed, because the rebuild path carries an embedded source snapshot for the application units it needs to rebuild.
ARCHITECTURE
Entrypoint and Build Configuration
PAX::CLI is a small public facade. It resolves build and run inputs from CLI arguments plus PAX::Paxfile, then delegates to the standalone image builder.
Compilation and Code Units
PAX::CodeUnitCompiler compiles supported Perl source shapes into PCU records. Unsupported or partially supported module shapes use hybrid or fallback payloads so correctness is preserved while reusable compiler support expands.
Dependency Discovery
PAX::StandaloneImage follows entrypoints, library directories, source roots, and cpanfile inputs to collect application modules and dependency payloads. The mechanism is structural and path/module based, not tied to a project name.
Asset Embedding
Individual assets and asset directories are embedded into the executable payload. The generated runtime extracts them into a private runtime directory and exposes that location to the packaged program.
Native and Fallback Dispatch
PAX can package native artifacts for supported hot regions. Runtime dispatch uses native execution when assumptions hold and falls back to bundled Perl payloads when they do not.
Standalone Launcher
The final output is an executable launcher containing package metadata, code units, dependency payloads, optional native artifacts, assets, and runtime helper code.
EXAMPLES
Build from paxfile.yml:
perl bin/pax build
Build a specific entrypoint:
perl bin/pax build -o ./build/example bin/example
Run after building:
perl bin/pax run -- status
Embed application assets:
perl bin/pax build \
--name webapp \
--lib lib \
--source-root lib \
--asset-dir share \
--cpanfile cpanfile \
--runtime-mode bundled_perl \
--output ./build/webapp \
bin/webapp
Build PAX itself:
perl bin/pax build -o /tmp/pax bin/pax
/tmp/pax help
Web Applications
PAX supports the single-binary packaging shape for framework applications that combine Perl modules, PSGI or web framework code, templates, CSS, JavaScript, and other static assets.
The validated SOW-03 proof includes a Dancer2 + Plack/Starman + Template Toolkit web application packaged as one executable.
DOCKER DEPLOYMENT MODEL
PAX supports a minimal multi-stage image pattern:
FROM perl:5.42 AS builder
WORKDIR /workspace
COPY . /workspace
RUN cpanm --installdeps .
RUN perl bin/pax build --output /out/app
FROM debian:bookworm-slim
COPY --from=builder /out/app /usr/local/bin/app
CMD ["/usr/local/bin/app"]
The final image contains only the executable. The source tree, assets, cpanfile, and framework installation are builder-stage inputs.
For an external application, the validated packaging pattern is:
build a standalone
paxbinarycopy that
paxbinary into the application build stagecompile the application into its own standalone binary
copy only that final binary into the runtime stage
ADAPTIVE COMPILATION RULE
When a module or framework fails under PAX, fixes should improve a reusable compiler, packaging, loader, or runtime path for arbitrary modules of the same class. A project-specific branch is not complete when a neutral generalized implementation is locally actionable.
RELEASE GATES
Release readiness requires:
Changes,README.md,cpanfile,dist.ini, andlib/PAX.pm.canonical version synchronization across all PAX modules.
POD and README parity for public behavior.
make test.make release-gate.a deliberate version-bump step such as
make cpan-bump-version VERSION=<next-version>followed by a meaningful top entry inChanges.make cpan-buildandmake cpan-gate.
cpan-gate also verifies that release tarballs and the git index exclude temporary probes, generated workspaces, planning artifacts, and other non-release paths.
make cpan-release follows the DD-style PAUSE flow: run the repo gates, locate the built tarball in the repository root, and upload it with cpan-upload using the local uploader configuration.
The version bump happens before dzil build, for example with make cpan-bump-version VERSION=<next-version> or make cpan-auto-bump. After the bump, the operator must write a meaningful top Changes entry for that version and commit the release-preparation changes. make cpan-dist and make cpan-build then enforce the version gate, the Changes gate, and the documentation gate for README.md plus this module POD without mutating tracked source files during the packaging step.
TESTING AND COVERAGE
Primary validation from a repository checkout is:
make tdd-gate
make bdd-gate
make atdd-gate
make qa-gate
make test
make release-gate
make cpan-build
make cpan-gate
Completion requires the full chain, not a partial subset. release-gate, cpan-gate, or git-gate alone are not sufficient. In project rules, "all gates" means the full closure sequence from TDD through git gate. make all-gates is only the convenience target for replaying the final committed-tree verification set. Treat the change set as complete only when the full gate chain has closed and the committed tree passes git gate.
KNOWN LIMITATIONS
Dynamic loading and runtime mutation can require fallback paths.
Native speed depends on region selection and guard validity.
Bundled runtime executables are larger than wrappers because they carry runtime payloads needed to run without the source tree.
Bundled-perl binaries are validated for builder and runtime environments from the same libc family; arbitrary host-built cross-distro portability is not a release guarantee, so multi-stage Docker deployment should build inside the target container family.
Docker validation requires local Docker access.
FAQ
Is PAX tied to one specific project?
No. Example applications are validation corpora. Core compiler and runtime logic are expected to stay neutral and reusable.
Does PAX guarantee Rust-like speed for all Perl code?
No. PAX packages the whole application correctly and accelerates hot paths that it can safely specialize. Dynamic regions continue to use fallback execution.
Does pax run require a separate app server?
No. Under SOW-03, pax run builds the standalone executable and then executes that binary directly.
Can PAX package web applications with embedded static assets?
Yes. The validated packaging path includes templates, CSS, JavaScript, and framework code embedded into one standalone executable.
FILES
bin/pax- public command entrypoint.lib/PAX/- compiler, packaging, runtime, and validation modules.paxfile.yml- neutral build manifest.README.md- operator documentation.Changes,cpanfile,dist.ini- release metadata.
SEE ALSO
The repository README.md mirrors the public command contract and operator workflow documented here.
The internal documentation rule for DD-style parity is recorded in docs/pax-doc-parity.md.