Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works

Random project

pxx

One from-scratch compiler for Pascal, C and Python: native static binaries for Linux (x86-64, i386, aarch64, arm32, riscv32), wasm32, and ESP32-S3/C3 firmware. Own RTL, ELF writer and linker; self-hosting. Beta 0.1 'Blaise'.

View on GitHub

Anyone may press Interesting, signed in or not. It helps others find this project.

Member rating

No ratings yet.

Sign in to rate this project.

README

PXX

One compiler, written from scratch, for Pascal, C and Python, producing native programs for Linux and the ESP32.

It has its own runtime, ELF writer and linker, so the output is a finished static executable with no assembler, no ld, no libc and no interpreter. It compiles itself to a byte-identical binary.

Save this as primes.py. It's plain Python, nothing PXX-specific:

python
def primes(n):
    sieve = [True] * (n + 1)
    out = []
    for i in range(2, n + 1):
        if sieve[i]:
            out.append(i)
            for j in range(i * i, n + 1, i):
                sieve[j] = False
    return out

ps = primes(100)
print(len(ps), "primes below 100, the last is", ps[-1])

Then, on x86-64 Linux, with the beta 0.1 release:

bash
sha256sum -c SHA256SUMS && tar xzf pxx-v0.1.0-beta.1.tar.gz
cd pxx-v0.1.0-beta.1 && ./install.sh --yes
./pxx ../primes.py ../primes && ../primes
text
25 primes below 100, the last is 97

That primes is a 515 KB static ELF executable with the same output as CPython. Download: v0.1.0-beta.1 "Blaise".

  • Three languages, one backend: Pascal (the Free Pascal dialect, solid), C (solid: SQLite, Lua, QuickJS, zlib, the Tiny C Compiler and BusyBox compile unmodified and match GCC's build), and Nil Python (ordinary Python compiled ahead of time; best effort).
  • Targets: x86-64, i386, aarch64, arm32, riscv32 and wasm32, plus native firmware for the ESP32-S3 and ESP32-C3. On real C3 and S3 boards every example passed, Python calling Pascal ran on the C3, and 300 HTTP fetches over real Wi-Fi on the S3 ran with 0 errors.
  • How it was made: one person's architecture, decisions and hardware testing; the code was written by AI coding agents under that direction, and every commit says so.

The Pascal side covers a tested Object Pascal subset: classes, generics, overloads, operators, exceptions, RTTI and C interop, with experimental BASIC, Rust and Zig frontends beside the main three. The long-term direction is a multi-language native compiler sharing one IR and backend.

Home: https://pxxc.org, the documentation site, published from this repository. Source: https://github.com/yoctobyte/pxx. Those two are the only official sources; nothing else distributes PXX. (PXX is a provisional name; the compiler binary is still compiler/pascal26. Naming things is the one compiler problem not solved by recursion.)

Looking for sponsors

Development is ongoing. The first beta, 0.1 "Blaise", is published; work continues on master. We are looking for sponsors to help sustain it. What exists today: a self-hosting Pascal compiler, mostly on par with Free Pascal's dialect, for the common Linux CPU targets and the ESP32, with C and Nil Python frontends alongside. What continued development would bring: memory-leak hardening across every target, Nil Python maturity, and more platforms. If you or your organisation would fund that, open an issue at https://github.com/yoctobyte/pxx/issues titled "Sponsorship".

⚠️ Security warning — do not expose to a network

PXX is early, unaudited, experimental software. The compiler, its runtime, and its networking code almost certainly contain bugs — including ones that could be exploited over a network connection, whether the program acts as a server or a client, and whether the input comes from a remote peer or a file it fetches.

Do not build or run any publicly reachable network service with software compiled by PXX, and do not point a PXX-built client at untrusted remote hosts. Treat anything it produces as suitable only for local experimentation on inputs you fully control.

This restriction stands until the compiler, runtime, and networking stack have been independently tested, hardened, and reach a mature, reviewed state — and even then the software is provided without any warranty and with no liability on the authors (see License and LICENSE.md). If you choose to ignore this, you do so entirely at your own risk.

Highlights

  • Self-hosting: make rebuilds the compiler through the checked-in PXX seed and requires a byte-identical fixedpoint — at the default optimisation level — before replacing it.
  • Small direct ELF output: benchmarks report Pascal Hello World in both the managed-default string mode and the frozen -uPXX_MANAGED_STRING compatibility mode; see the newest run in the benchmarks directory.
  • Fast pipeline: one in-memory frontend-to-ELF path, no assembler or linker subprocess. See the newest run in the benchmarks directory.
  • Pascal + C interop: local C files can be compiled into the same output, and supported C headers can be imported directly.
  • Wrapper-free Nil Python C calls: .npy can import sqlite3 directly and run SQLite CRUD without a Pascal wrapper.
  • ESP32, in Pascal and in Python: PXX compiles Pascal, and Nil Python (Python written the MicroPython way, compiled ahead of time with no interpreter on the chip), to native code for the ESP32. The output is an ESP-IDF component, so it builds against Espressif's own SDK. On silicon, the examples have run on an ESP32-S3, an ESP32-C3 and a classic ESP32. Nil Python gets MicroPython's module names (machine, time.sleep_ms, network, urequests, ssl), and micropython-lib's own umqtt compiles unchanged; the C3 has joined Wi-Fi and made HTTPS requests with a checked certificate. Memory stays level over long network soaks, each checked against a deliberate leak. ./espide.sh is a small IDE that detects the chip, builds, flashes and monitors. Start at ESP32 and MicroPython code on PXX.

Quick Start

Prerequisites: Linux x86-64 and GNU make. FPC is needed only for bootstrap or recovery builds.

From a release tarball (pxx-<version>.tar.gz), unpack it and set up in place. There is no stable_linux_amd64/ in a tarball; its compilers are compiler/pxx-<arch>, one per host, and compiler/pascal26 is the x86-64 one:

bash
tar xzf pxx-<version>.tar.gz && cd pxx-<version>
./install.sh --yes          # writes ./pxx: the compiler plus the library roots
./pxx test/hello.pas /tmp/hello && /tmp/hello
./selfcheck.sh              # rebuilds every shipped binary; must match MANIFEST.sha256

make and make test work in the tarball as they do in a checkout. The rest of this section is for a git checkout.

A fresh checkout already ships a working compiler at stable_linux_amd64/default/pinned, so you can compile something before you build anything. ./install.sh is the friendly setup path — it checks that a compiler runs on this host and writes a ready-to-use ./pxx wrapper in the project root (--yes to skip the prompts, --no-path to skip the PATH offer); the documentation's Install page leads with it. The recipes below are the from-source path, and ./pxx in the documentation's examples is the wrapper that script writes — this README uses ./compiler/pascal26, which is the same compiler after make.

During the 0.x beta there is no stable tag yet. Use the Current recipe below; the stable-tag one is what to use once tags exist. The command is written to be a no-op rather than an error in the meantime, because a bare git checkout "" fails with "empty string is not a valid pathspec" — which reads as a typo and sends a first-time reader hunting for one.

Latest stable (recommended, once a stable tag exists) — clone, then check out the newest stable release tag:

bash
git clone https://github.com/yoctobyte/pxx
cd pxx
TAG="$(git tag -l 'v*.*.*' | awk '!/-/' | sort -V | tail -n1)"   # newest stable tag
if [ -n "$TAG" ]; then git checkout "$TAG"; else echo 'no stable tag yet — staying on master'; fi
cp stable_linux_amd64/default/pinned compiler/pascal26   # seed: make refuses without it
make
make test

Current — the tip of master is the live tree (passes its gates; ahead of the last stable tag, and during the beta it is the only tree there is). Skip the checkout to track it:

bash
git clone https://github.com/yoctobyte/pxx && cd pxx
cp stable_linux_amd64/default/pinned compiler/pascal26   # seed: make refuses without it
make && make test

A fresh clone has no compiler/pascal26; make stops with "self-hosted compiler seed missing" until it is copied from the pin as above (or built by FPC with make bootstrap). Accept the build once make prints converged after N round(s).

Bootstrap from FPC (first build on a fresh machine, or recovery):

bash
sudo apt install fpc
git clone https://github.com/yoctobyte/pxx
cd pxx
make bootstrap
make test
make test-nilpy
make fpc-check

The bootstrap path reseats compiler/pascal26 only after the self-built compiler reaches byte-identical fixedpoint. That build passes no -O flag, so the property proved is "it reproduces itself at the default optimisation level" — a narrower and more accurate claim than "it reproduces itself".

A release is a git tag plus a prebuilt tarball (full source + RTL/PCL + host binaries + docs in one archive). Tags mark the stable points; the tarballs exist mainly for offline use, packaging, and distro repackaging — cloning is the primary path.

Using The Compiler

Compile and run a Pascal source file:

bash
./compiler/pascal26 test/hello.pas /tmp/hello
/tmp/hello

Enable compiler tracing:

bash
./compiler/pascal26 --debug source.pas /tmp/out

Optional PATH symlink for active development:

bash
mkdir -p "$HOME/.local/bin"
ln -sfn "$PWD/compiler/pascal26" "$HOME/.local/bin/pxx"

Optional PATH symlink for the latest recorded stable compiler (git checkout only; from a tarball, run ./install.sh and answer yes to the PATH offer):

bash
mkdir -p "$HOME/.local/bin"
ln -sfn "$PWD/stable_linux_amd64/default/latest" "$HOME/.local/bin/pxx"

Demo: build busybox with pxx

pxx builds busybox as one translation unit and links it itself: a static binary, no libc. busybox is GPL-2.0 and is not in this repository or the tarball. Fetch it yourself; the version this is tested against is 1.36.1 (git commit 1a64f6a20aaf6ea4dbba68bbfa8cc1ab7e5c57c4):

bash
curl -LO https://busybox.net/downloads/busybox-1.36.1.tar.bz2   # sha256 b8cc24c9...de314
tar xjf busybox-1.36.1.tar.bz2
# or: git clone https://git.busybox.net/busybox && git -C busybox checkout 1a64f6a20aaf

PXX_BUSYBOX_DIR=$PWD/busybox-1.36.1 tools/busybox_diff.sh --build-only \
    --applets "cat echo ls wc" --out ./busybox-pxx
./busybox-pxx/busybox_x86_64 echo hello

--build-only prints the applet list, runs one smoke applet, and leaves the binary in --out. Configuring the tree needs gcc on the host. That step is busybox's own make, which builds kconfig and the link map the unity's file list is read from, and busybox's Makefile calls gcc. It runs once per applet list; after that, --build-only needs no gcc at all. Without --build-only the script is the full differential test against a gcc build of the same source. In a git checkout, tools/install_lib_candidates.sh busybox fetches the pinned commit to the default location.

Documentation

  • Public documentation — install, getting started, language, features, targets, library, and reference pages. Published at https://pxxc.org/docs/; the Markdown here is the source it renders.
  • Internal documentation — plans, progress tickets, legacy command-line and dialect notes, developer docs — is in the repository's devdocs/. It is not part of a release bundle.
  • Agent instructions — guidelines and workflow for AI agents working on this repo (repository only).

Repository Layout

  • agents/ - shared AI-agent instructions (agents/AGENTS.md) and generated code map.
  • benchmarks/ - dated benchmark snapshots.
  • compiler/ - compiler source, the checked-in seed, and builtin/ (the compiler-specific runtime unit auto-included into compiled programs: heap allocator, Str/Val, variant helpers).
  • docs/ - public website documentation.
  • devdocs/ - project state, plans, progress tickets, and historic handovers (repository only; not in a release bundle).
  • lib/ - Pascal library units used by tests and demos (rtl/, pcl/).
  • stable_linux_amd64/ - stable/recovery compiler binaries. The default channel uses managed AnsiString; historical managed/frozen channels may remain for compatibility.
  • test/ - regression tests, fixtures, and manual harnesses.
  • tools/ - repository maintenance helpers.

License

  • Compiler and tools: Mozilla Public License 2.0.
  • Runtime and libraries (lib/rtl, lib/pcl, lib/crtl, lib/asmcore, compiler/builtin): zlib — the code embedded in binaries the compiler produces places no obligations on your programs.
  • Examples: 0BSD. Docs: CC BY 4.0.

See LICENSE.md for the per-directory map and CONTRIBUTING.md for the DCO sign-off required on contributions.

The compiler remains experimental: do not use it for security-sensitive, safety-sensitive, financial, legal, medical, or infrastructure work, and do not expose software built with it to a network (see the Security warning near the top of this README).

Acknowledgements

PXX depends on Free Pascal for bootstrap and on the Lazarus/FPC ecosystem as a compatibility reference.