A minimal template for building Solana BPF programs using standard C and sbpf-linker.
- ✅ Standard C (C11) with no custom toolchains
- ✅ Zero external dependencies (no Solana SDK needed)
- ✅ LLVM bitcode generation via Clang
- ✅ Direct syscall invocation via function pointers
- ✅ Automated build pipeline with
build.sh - ✅ Rust-based integration tests with
solana-program-test
# Install LLVM/Clang (macOS)
brew install llvm
# Install sbpf-linker
cargo install sbpf-linker
# Install Rust for testing
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh./build.shThis generates:
entrypoint.bc- LLVM bitcode from C sourcebuild/program.so- Final Solana program
cargo test -- --nocaptureTests will:
- Build the program
- Load the .so file into solana-program-test
- Execute and verify the entrypoint
Instead of linking against the Solana SDK, we call syscalls directly:
void (*sol_log_)(const uint8_t *, uint64_t) = (void *)0x207559bd;
sol_log_((const uint8_t *)message, sizeof(message));The constant 0x207559bd is the syscall hash that Solana VM resolves at runtime.
To prevent sbpf-linker from stripping .rodata, we inline string data:
const char message[] = {'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!'};sbpf-linker is an LTO compiler that requires LLVM IR:
clang -target bpfel -O2 -fno-builtin -emit-llvm -c -o entrypoint.bc entrypoint.c
sbpf-linker --cpu v3 --export entrypoint -o program.so entrypoint.bc.
├── build.sh # Automated build pipeline
├── Cargo.toml # Rust test dependencies
├── src/
│ └── entrypoint.c # Program entrypoint with inline syscalls
└── tests/
└── integration_test.rs # Rust integration tests
# Build first
./build.sh
# Deploy to devnet
solana program deploy build/program.so --url devnet
# Or deploy to local validator
solana-test-validator &
solana program deploy build/program.soMIT