This guide covers how to develop Perry on macOS while compiling and deploying to Linux/Ubuntu targets.
Template workflow files are provided in templates/github-actions/:
ci.yml- Runs tests on Ubuntu and macOS, uploads build artifactsrelease.yml- Builds release binaries when you push a version tag
To use them, copy to .github/workflows/ in your repository:
mkdir -p .github/workflows
cp templates/github-actions/*.yml .github/workflows/Then push your code and GitHub Actions will automatically:
- Run tests on both Ubuntu and macOS
- Build release binaries for Linux (x86_64) and macOS (x86_64, aarch64)
- Upload artifacts that can be downloaded
To create a release:
git tag v0.2.77
git push origin v0.2.77Build and test for Linux locally:
# Build the Perry compiler Docker image
docker compose build perry
# Compile a TypeScript file to a Linux binary
docker compose run --rm perry myfile.ts -o myfile
# The compiled binary is now in your current directory
./myfile # (run on Linux or in Docker)Install cross-compilation toolchain:
# Install cross-rs for easier cross-compilation
cargo install cross
# Build for Linux
cross build --release --target x86_64-unknown-linux-gnu-
Develop and test locally on macOS:
cargo build cargo test cargo run -- test.ts -o test_mac ./test_mac # Test on macOS
-
Build Linux binary via Docker:
# One-liner to compile for Linux docker compose run --rm perry test.ts -o test_linux # Or build inside a dev container docker compose run --rm perry-dev cargo build --release
-
Copy to Ubuntu server:
scp test_linux user@ubuntu-server:/path/to/app scp target/release/libperry_runtime.a user@ubuntu-server:/path/to/app
The docker-compose includes test databases:
# Start services
docker compose up -d mysql redis postgres
# Wait for services to be healthy
docker compose ps
# Run tests with database connectivity
docker compose run --rm perry-dev cargo test
# Or run specific integration tests
docker compose run --rm perry-dev bash -c "
cargo run --release -- test_mysql.ts -o test_mysql
./test_mysql
"# Enter a dev shell with full Rust toolchain
docker compose run --rm perry-dev bash
# Inside container:
cargo build --release
cargo test
cargo run -- /app/myfile.ts -o /app/myfileTemplate workflows are in templates/github-actions/. Copy them to .github/workflows/ to activate.
ci.yml - Runs on every push/PR:
- Checks formatting (
cargo fmt) - Runs linter (
cargo clippy) - Builds and tests on Ubuntu and macOS
- Uploads build artifacts
release.yml - Runs on version tags:
- Builds release binaries for all platforms
- Creates GitHub Release with downloadable archives
- Generates release notes automatically
# 1. Update version in Cargo.toml and CLAUDE.md
# 2. Commit changes
git add -A && git commit -m "Release v0.2.77"
# 3. Create and push tag
git tag v0.2.77
git push origin main --tagsCreate a .devcontainer/devcontainer.json:
{
"name": "Perry Dev",
"image": "mcr.microsoft.com/devcontainers/rust:1",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"postCreateCommand": "cargo build"
}Use VS Code Remote - SSH to develop directly on an Ubuntu machine:
- Install "Remote - SSH" extension
- Connect to your Ubuntu server
- Clone and work on the code directly
# Install multipass
brew install multipass
# Create Ubuntu VM
multipass launch --name perry-dev --cpus 4 --memory 8G --disk 50G
# Mount your code
multipass mount /path/to/perry perry-dev:/home/ubuntu/perry
# SSH into VM
multipass shell perry-dev
# Inside VM: install Rust and build
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cd ~/perry && cargo build --release# Install lima
brew install lima
# Start Ubuntu VM
limactl start --name=perry template://ubuntu
# Run commands in VM
lima cargo build --releaseCreate a flake.nix for reproducible builds across platforms:
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }: {
packages.x86_64-linux.default =
nixpkgs.legacyPackages.x86_64-linux.callPackage ./default.nix {};
packages.x86_64-darwin.default =
nixpkgs.legacyPackages.x86_64-darwin.callPackage ./default.nix {};
};
}The Dockerfile provides multiple stages:
| Stage | Use Case | Size |
|---|---|---|
builder |
Building Perry from source | Large |
compiler |
Compiling TypeScript files | ~500MB |
runtime |
Running compiled binaries only | ~100MB |
# In your app's Dockerfile
FROM perry:compiler AS builder
COPY app.ts /app/app.ts
RUN perry /app/app.ts -o /app/app
FROM perry:runtime
COPY --from=builder /app/app /app/app
CMD ["/app/app"]Ensure libperry_runtime.a is in the library path:
export PERRY_RUNTIME_LIB=/path/to/libperry_runtime.aCheck glibc compatibility:
ldd ./myprogramIf missing libc.so.6, the binary was compiled against a newer glibc. Use an older base image (e.g., debian:bullseye instead of bookworm).
Install CA certificates:
apt-get install ca-certificates