PAX Update: One Binary, Real Applications and the Hard Parts of Compiling Perl
2026-04-30
The first PAX post asked whether the project had crossed the line from compiler talk into something Perl developers should actually pay attention to.
This follow-up is about the next, more practical question: what has improved now that the project is spending more time on application reality than on compiler rhetoric?
If you missed the first post, start here:
PAX: Compiling Perl Again, This Time for Real
If you want the public project surface first:
- MetaCPAN: https://metacpan.org/pod/PAX
- GitHub: https://github.com/manif3station/PAX
What Changed In Practice
PAX is now further along in three areas that matter to working Perl developers:
- packaging real applications into one executable
- keeping those executables working without the source tree
- proving real speedups on supported hot-path shapes
That does not mean every Perl program is suddenly fast. It does mean the project is now past the stage where it only talks about the idea.
The Goal Has Not Moved
The direction is still the same:
keep Perl, compile what can be compiled, preserve compatibility where Perl stays dynamic, package everything into one executable and push supported hot paths toward native speed
That remains the right target because it is ambitious without pretending Perl has stopped being Perl.
What changed is not the mission. What changed is that more of the system is now holding together as a deployment story instead of a collection of interesting parts.
The Real Breakthrough Is Application Closure
The hard problem here was never just native code generation. The harder problem was closure.
It is easy to demo something that "compiles" a Perl script while still quietly depending on:
- the original source tree
- a nearby
lib/ - framework assets on disk
- helper scripts that only exist in development
- a system Perl that happens to look like the build machine
That is not single-binary deployment. That is a wrapper wearing a compiler badge.
Recent PAX work pushed directly at that boundary. The current standalone path now handles:
- application code
- Perl dependency closure
- bundled runtime payloads
- embedded static assets
- helper-command dispatch
- multi-stage container deployment
That matters because real Perl systems are often operational CLIs, web applications or command families with helper entrypoints and runtime support files. If the binary cannot survive those shapes, it is not ready for serious use.
What "Real Application Support" Means
The important shift is that PAX is no longer only proving synthetic kernels. It is now packaging and running larger shapes that look like actual shipped Perl:
- command-oriented applications with helper subcommands
- applications installed from CPAN-style layouts
- real web applications with templates, CSS, JavaScript and framework runtime
- multi-stage container builds where the final image contains only the finished executable
That last point is the cleanest operational test.
The target model is no longer "ship a source tree and hope the runtime guesses the rest."
The target model is simpler and stricter: build once, copy one executable into the runtime image and run it.
That is the standard PAX now looks like it is trying to meet.
The Hard Problems Were Mostly Operational
When people hear "compile Perl," they usually jump straight to parsing, op trees or native lowering.
Those matter, but the recent work looks harder in more practical places.
Installed-layout correctness
Programs behave differently when they run from an installed layout instead of a live checkout.
Imports, runtime discovery, helper wrappers, version lookup and framework support code all get more fragile once the source tree disappears. PAX had to get stricter about dependency discovery, imported-class resolution, runtime closure and helper execution paths to make that survivable.
Helper-command behavior
Many real applications are not one-command tools. They expose helper commands and subcommand families that users expect to behave like the original application.
That is why this point matters so much: PAX needed to make standalone helper dispatch behave like the original application, not like a reduced demo runtime.
Mixed execution modes
A believable compiler for Perl cannot assume the whole program belongs to one execution model.
Some regions are strong native candidates. Some are not. Some are still better carried as packaged Perl. PAX is moving toward a mixed model:
- compile aggressively where the semantics are structurally clear
- keep a compatibility floor where Perl remains dynamic
- package both into one coherent runtime
That model is harder to build, but it is much more realistic than pretending the only winning state is "everything compiles cleanly."
Shebang Mode Matters More Than It Sounds
One practical improvement is interpreter-style execution through a built PAX binary.
That means a Perl script can use the PAX executable as its shebang interpreter and still behave like a Perl-facing runtime rather than like a detached artifact.
In practice, that gives PAX two roles:
- builder
- executable Perl-facing runtime entrypoint
That makes the system easier to fit into normal Unix workflows instead of forcing everything through one packaging command.
The Performance Story Is Now Real
The honest answer on speed has not changed in spirit:
- some workloads do very well
- some do not
- the result depends on whether PAX can recognize and lower the hot path safely
But the size of the wins is now much harder to dismiss.
PAX has measured cases where stock Perl spends roughly two minutes in a supported arithmetic workload and the standalone binary completes in around one second.
That is not a small startup improvement. That is a real execution-mode change.
The headline range now looks like this:
- stock Perl around
116sto120s - standalone around
1.16sto1.27s - roughly
91xto100xfaster
These are not "all Perl is fast now" examples. They are supported hot-path cases. But they are real, measured and public.
Five Proven Examples
The current public PAX material includes five benchmarked examples. The point is not to claim universal optimization. The point is to show that the current compiler can already produce wins too large to explain away as benchmark noise.
| Example | Stock Perl | Standalone | Speedup |
|---|---|---|---|
| Invoice rollup | 120.35s |
1.26s |
95.4x |
| Retry budget planning | 116.70s |
1.27s |
91.6x |
| Shard weight planning | 117.49s |
1.19s |
98.4x |
| Backfill window checksum | 117.31s |
1.23s |
95.1x |
| Cohort retention counting | 117.10s |
1.16s |
100.7x |
If you want one concrete anchor: Invoice rollup lands at speedup: about 95.4x.
Why The Results Are Still Shape-Driven
PAX is not special-casing one workload name. That would be pointless.
But it is still selective by supported code shape.
Today the strongest candidates are things like:
- tight integer loops
- predictable numeric kernels
- structurally stable hot regions
The weaker cases are still what you would expect:
- dynamic metaprogramming
- framework-heavy startup
- subprocess-heavy helper commands
- irregular control flow that stays deep in Perl semantics
That is why the project still has two jobs at once:
- make standalone packaging correct for broad Perl applications
- keep expanding the region classes that can be compiled and dispatched natively
The first job makes PAX usable. The second job makes PAX fast.
Both matter.
Why This Matters Beyond Benchmarks
The point is not only "make a loop go fast."
The bigger point is that Perl can have a more modern systems path again:
- one-binary deployment
- smaller runtime assumptions
- more controlled packaging
- room for real performance engineering
- a compiler/runtime project the community can extend
Perl still has real expressive power and a lot of operational history behind it. What it has lacked for a long time is momentum around deployment and runtime infrastructure. PAX is trying to build some of that missing layer.
What Still Needs Work
There is no reason to fake maturity here.
The next hard problems are obvious:
- broaden native shape coverage
- cut more startup overhead for complex application commands
- improve performance on workloads that are not simple arithmetic kernels
- keep making dependency and runtime closure more robust across more CPAN ecosystems
- reduce the gap between "packages correctly" and "runs much faster"
That is where the real engineering work still is.
Why Open Contribution Matters
This is the stage where outside contribution starts becoming useful in a concrete way.
There is now something real to push on:
- packaging behavior
- standalone runtime behavior
- compiler limits
- benchmark cases
- correctness gaps when a workload does not fit yet
That is a much better community entry point than the usual compiler-concept phase.
How To Try It
If you want to try the packaging flow directly, the simplest shape looks like this:
pax build -o ./my-app ./bin/my-app
./my-app
For script-style use:
pax run ./script.pl
The current sweet spot is:
- supported arithmetic-heavy hot paths
- applications that benefit from one-binary packaging
- container deployment where you want the final runtime image to contain only the built executable
What Feedback Helps Most
The most useful reports are not "it felt slow."
The useful reports usually include:
- what command or script was run
- stock Perl timing
- standalone timing
- whether the workload is startup-heavy, CPU-heavy, IO-heavy or dynamic
- whether the binary was built and run in the same runtime family
The most valuable cases are:
- a real application that packaged correctly but ran much slower than expected
- a hot loop that looks structurally simple but did not accelerate
- a helper command or application subcommand that behaves differently after packaging
- a deployment shape that still needs the source tree when it should not
That is the kind of feedback that moves a project like this from interesting to reliable.
Closing
The long-term aim is still blunt:
- Perl-level ergonomics
- native-speed hot paths
- Go-like single-binary mobility
That is ambitious. It should be.
The useful thing now is that PAX is no longer only a statement of intent. It is turning into a working answer to a question Perl has been carrying for a long time:
can Perl applications be compiled, packaged and deployed like a modern systems language without giving up Perl itself?
The answer is not complete yet.
But it is real now.