Skip to content

DaviRain-Su/solana-program-sdk-zig

 
 

Repository files navigation

solana-program-sdk-zig

Write Solana on-chain programs in Zig.

This branch (solana-zig-fork-0.16) supports two build paths so one SDK serves both audiences:

Path Compiler Linker CU Install size
PrimarybuildProgram solana-zig fork (Zig 0.16-dev) built-in lld best (matches solana-zig baseline) ~200 MB
FallbackbuildProgramElf2sbpf stock Zig 0.16 elf2sbpf worse than baseline (no CU optimizer) stock Zig + ~2 MB

Which to pick:

  • have solana-zig fork installed → use buildProgram (fork path) — one call, direct .so, optimal CU.
  • only have stock Zig → use buildProgramElf2sbpf — slightly more CU, zero extra dependencies beyond the elf2sbpf binary.

Quick start

./scripts/bootstrap.sh
zig build test --summary all
./program-test/test.sh

bootstrap.sh detects both toolchains and prints the environment variables to export:

export SOLANA_ZIG_BIN=/path/to/solana-zig-bootstrap/out-smoke/host/bin/zig
export ELF2SBPF_BIN=/path/to/elf2sbpf

Using the SDK from your build.zig

Primary path (fork Zig, best CU)

const std = @import("std");
const solana = @import("solana_program_sdk");

pub fn build(b: *std.Build) void {
    _ = solana.buildProgram(b, .{
        .name = "my_program",
        .root_source_file = b.path("src/main.zig"),
        .optimize = .ReleaseFast,
    });
}

Run with the fork Zig:

"$SOLANA_ZIG_BIN" build

One step. The SDK sets sbf_target, installs the bpf.ld linker script, and writes zig-out/lib/my_program.so.

Fallback path (stock Zig + elf2sbpf)

const std = @import("std");
const solana = @import("solana_program_sdk");

pub fn build(b: *std.Build) void {
    const target = b.resolveTargetQuery(solana.bpf_target);
    const optimize = .ReleaseFast;
    const elf2sbpf_bin = b.option(
        []const u8,
        "elf2sbpf-bin",
        "Path to the elf2sbpf executable",
    );

    _ = solana.buildProgramElf2sbpf(b, .{
        .name = "my_program",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .elf2sbpf_bin = elf2sbpf_bin,
    });
}

Run with stock Zig:

zig build  # elf2sbpf auto-resolved from ELF2SBPF_BIN / .tools / PATH

For CU-optimal Zig programs, use the solana-zig fork path (primary) instead — the elf2sbpf fallback path is for users who can't install the fork. A --peephole rewriter existed in earlier elf2sbpf versions but was rolled back 2026-04-19 (miscompile on escrow-class programs).

Prerequisites

Stock Zig 0.16 (host tests + fallback program builds)

zig version
# -> 0.16.x

solana-zig fork (primary program builds)

Clone & build:

git clone -b solana-1.52-zig0.16 \
  https://github.com/DaviRain-Su/solana-zig-bootstrap \
  ../solana-zig-bootstrap
cd ../solana-zig-bootstrap
git submodule update --init --recursive
./build native-macos-none baseline   # or native-linux-musl baseline

When done:

export SOLANA_ZIG_BIN=$(pwd)/out-smoke/host/bin/zig

bootstrap.sh in this repo also auto-detects a sibling ../solana-zig-bootstrap checkout.

Exported targets

  • sbf_target.cpu_arch = .sbf, .os_tag = .solana, .cpu_model = v2. Only recognized by the fork Zig.
  • bpf_target.cpu_arch = .bpfel, .os_tag = .freestanding, .cpu_model = v2. Works on stock Zig (kernel-BPF-flavored output, then run through elf2sbpf).

Unit tests

Stock Zig is fine:

zig build test --summary all

Integration tests

./program-test/test.sh

See program-test/test.sh for CLI options.

Branch layout

  • main — original upstream solana-zig based SDK (legacy reference).
  • dev / elf2sbpf-from-4589040 — stock Zig + elf2sbpf only (simpler, narrower scope).
  • solana-zig-fork-0.16 (this branch) — dual path, recommended default.

About

Write Solana programs in Zig.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Zig 80.5%
  • Shell 17.2%
  • Rust 2.3%