- Rust toolchain (stable, ≥ 1.94): rustup.rs. The
workspace pins no toolchain file, so an older
stablefails with asqlx@0.9.0 requires rustc 1.94.0MSRV error from deep in the dependency graph.rustup update stableresolves it. - System C compiler (
ccon macOS/Linux, MSVC on Windows) - libclang — the
libsqlite3-sysbuild script runsbindgen. Missing it aborts the build withUnable to find libclang. Installlibclang-dev(Debian/Ubuntu),clang-devel(Fedora) orclang(Arch). For a non-standard location setLIBCLANG_PATHto the directory holdinglibclang.so; if bindgen then reports'stdarg.h' file not found, also setBINDGEN_EXTRA_CLANG_ARGS="-isystem <clang-resource-dir>/include". - LLVM 22 development files — required by Perry's default in-process
codegen backend.
llvm-config --versionmust report LLVM 22. Ifllvm-configis not onPATH, setLLVM_SYS_221_PREFIXto the LLVM 22 prefix. On Windows this variable is mandatory and must point at the extracted LLVM 22 development archive used by the build.
An external clang is not part of the normal in-process codegen path. Install a
matching clang only when working on a path that explicitly invokes it (for
example Windows host --embed) or when building with
--no-default-features to bisect the textual-IR backend.
git clone https://github.com/PerryTS/perry.git
cd perry
# Build the default product and its dependency closure
cargo build --releaseThe binary is at target/release/perry.
The workspace deliberately defaults to the perry CLI. Bindings, platform
adapters, test support, and release-only archives are selected explicitly by
their CI/release jobs. Workspace-wide host commands must use the centralized
platform exclusions described in the crate policy.
Perry has three build profiles, each tuned for a different job (#5422):
| Goal | Command | Profile |
|---|---|---|
| Fastest correctness feedback | cargo check -p perry |
— |
| Optimized local development | cargo build --profile perry-dev -p perry |
perry-dev |
| Release-compatible build | cargo build --release |
release |
| Official distribution artifacts | cargo build --profile dist ... |
dist |
perry-devinheritsreleasebut disables the expensive distribution settings (lto = false,codegen-units = 16,opt-level = 1,incremental = true, no strip) so the edit/build loop stays short. Output is attarget/perry-dev/perry.distmirrorsreleaseexactly (ThinLTO,codegen-units = 1,opt-level = 3, strip) and is the explicit, named profile the release workflows use for shipped artifacts. Output is attarget/dist/.
After a --timings build, scripts/cargo_timing_summary.py prints the slowest
units so build-time regressions are visible.
Short-lived worktrees and coding agents can opt into a compiler cache shared
outside the repository. Install sccache in your user environment, then run
Cargo through the wrapper:
./scripts/cargo_cached.sh check -p perry
# Slim, optimized developer CLI
./scripts/cargo_cached.sh build --profile perry-dev -p perry \
--no-default-features --features dev-cliThe wrapper disables Cargo incremental compilation because sccache cannot
cache incremental artifacts. It stores compiler objects under
${XDG_CACHE_HOME:-$HOME/.cache}/perry/sccache by default, not in the worktree;
set SCCACHE_DIR or SCCACHE_CACHE_SIZE to override its 12G cache policy.
It does not install or configure sccache globally.
In a long-lived worktree, use ordinary cargo commands instead so the local
incremental cache remains available. Cache benefit depends on the compiler,
flags, dependencies, and how much prior work the cache can reuse.
# Runtime only (must rebuild stdlib too!)
cargo build --release -p perry-runtime -p perry-stdlib
# The .a static archives are emitted by separate wrapper crates (#5422), so a
# plain `cargo build` no longer produces them as a side effect. Build them
# explicitly when you need libperry_runtime.a / libperry_stdlib.a (e.g. to link
# compiled programs without the auto-optimize rebuild):
cargo build --release -p perry-runtime-static -p perry-stdlib-static
# Codegen only
cargo build --release -p perry-codegenImportant: When rebuilding
perry-runtime, you must also rebuildperry-stdlibbecauselibperry_stdlib.aembeds perry-runtime as a static dependency.
The default build is the full official CLI. For compiler work you can build a slimmer CLI that omits the publish / mobile / updater / native / audit commands and the non-native codegen backends (#5422):
cargo build -p perry --no-default-features --features dev-clidev-cli keeps compile / run / check / types / cache / dev. Disabled
commands drop out of --help, and disabled --target backends report a clear
"built without the <feature> feature" error. See crates/perry/Cargo.toml for
the full feature list (full-cli, publish-cli, backend-wasm, …).
# Product unit targets
cargo test -p perry --bins
# Inspect the nightly CI test scope (all Linux-compatible test crates)
python3 scripts/ci_test_scope.py --full </dev/null
# Specific crate
cargo test -p perry-hir
cargo test -p perry-codegen# Compile a TypeScript file
cargo run --release -- hello.ts -o hello
./hello
# Debug: print HIR
cargo run --release -- hello.ts --print-hir- Make changes to the relevant crate
cargo check -p perryfor fast product feedback- Run tests for the crates affected by the change
- Test with a real TypeScript file:
cargo run --release -- test.ts -o test && ./test
perry/
├── crates/
│ ├── perry/ # CLI driver
│ ├── perry-parser/ # SWC TypeScript parser
│ ├── perry-hir/ # HIR types, data structures, and lowering
│ ├── perry-transform/ # IR passes
│ ├── perry-codegen/ # LLVM native codegen
│ ├── perry-codegen-wasm/ # WebAssembly codegen (--target web / --target wasm)
│ ├── perry-codegen-js/ # JS minifier (formerly the web target's codegen)
│ ├── perry-codegen-swiftui/ # Widget codegen
│ ├── perry-runtime/ # Runtime library
│ ├── perry-stdlib/ # npm package implementations
│ ├── perry-ui/ # Shared UI types
│ ├── perry-ui-macos/ # macOS AppKit UI
│ ├── perry-ui-ios/ # iOS UIKit UI
│ └── perry-ext-*/ # Selectively linked native bindings
├── docs/ # This documentation (mdBook)
├── CLAUDE.md # Detailed implementation notes
└── CHANGELOG.md # Version history
- Architecture — Crate map and pipeline overview
- See
CLAUDE.mdfor detailed implementation notes and pitfalls