Documentation Index
Fetch the complete documentation index at: https://mintlify.com/risc0/risc0/llms.txt
Use this file to discover all available pages before exploring further.
The risc0-build crate provides build-time tools for compiling RISC-V guest programs and embedding them into your host application. It automates the process of building guest code and generating the necessary constants for execution and verification.
Project Structure
A typical RISC Zero project has this structure:
my-project/
├── Cargo.toml
├── src/
│ └── main.rs # Host code
└── methods/
├── Cargo.toml # Methods crate manifest
├── build.rs # Build script
├── src/
│ └── lib.rs # Generated constants
└── guest/
├── Cargo.toml # Guest program manifest
└── src/
└── main.rs # Guest code
Setting Up build.rs
The build.rs file in your methods crate triggers the guest build:
fn main() {
risc0_build::embed_methods();
}
This single line does a lot:
- Compiles all guest programs specified in
Cargo.toml
- Generates ELF binaries for the RISC-V target
- Computes image IDs for verification
- Creates a
methods.rs file with constants
Configuring Methods in Cargo.toml
Specify which guest packages to build:
[package]
name = "hello-world-methods"
version = "0.1.0"
edition = "2021"
[build-dependencies]
risc0-build = { version = "1.0" }
[package.metadata.risc0]
methods = ["guest"]
The methods array lists relative paths to guest crates.
Generated Constants
After building, risc0-build generates constants in $OUT_DIR/methods.rs:
// Auto-generated - do not edit
pub const MULTIPLY_ELF: &[u8] = include_bytes!("...");
pub const MULTIPLY_PATH: &str = "/path/to/guest/binary";
pub const MULTIPLY_ID: [u32; 8] = [
0x12345678,
0x9abcdef0,
// ... 8 words total
];
Including Generated Code
In your methods/src/lib.rs:
include!(concat!(env!("OUT_DIR"), "/methods.rs"));
Using the Constants
In your host code:
use my_project_methods::{MULTIPLY_ELF, MULTIPLY_ID};
use risc0_zkvm::{ExecutorEnv, default_prover};
fn main() {
let env = ExecutorEnv::builder().build().unwrap();
let prover = default_prover();
// Use the ELF to execute
let receipt = prover.prove(env, MULTIPLY_ELF).unwrap().receipt;
// Use the ID to verify
receipt.verify(MULTIPLY_ID).unwrap();
}
Custom Guest Options
Configure individual guest packages with GuestOptions:
use risc0_build::{embed_methods_with_options, GuestOptions};
use std::collections::HashMap;
fn main() {
let mut opts = HashMap::new();
opts.insert(
"guest",
GuestOptions::builder()
.features(vec!["my-feature".to_string()])
.build()
.unwrap(),
);
embed_methods_with_options(opts);
}
Available Options
- Features - Enable Cargo features in the guest
- Docker build - Build in Docker for reproducibility
- Kernel ELF - Use a custom kernel
Docker Builds
For reproducible builds, use Docker:
use risc0_build::{
embed_methods_with_options,
GuestOptions,
DockerOptions,
};
use std::collections::HashMap;
fn main() {
let mut opts = HashMap::new();
let docker_opts = DockerOptions::builder()
.root_dir("/path/to/project")
.build()
.unwrap();
opts.insert(
"guest",
GuestOptions::builder()
.use_docker(docker_opts)
.build()
.unwrap(),
);
embed_methods_with_options(opts);
}
Docker builds require the RISC Zero Docker image to be available. The default tag is set in risc0-build.
Building Without Embedding
For faster iteration during development, skip embedding the full ELF:
use risc0_build::embed_method_metadata_with_options;
fn main() {
// Only embed metadata (name and path)
embed_method_metadata_with_options(HashMap::new());
}
This generates minimal constants:
pub const MULTIPLY_PATH: &str = "/path/to/guest/binary";
Environment Variables
risc0-build respects several environment variables:
RISC0_SKIP_BUILD
Skip building guest programs:
export RISC0_SKIP_BUILD=1
cargo build
RISC0_BUILD_DEBUG
Build guest programs in debug mode:
export RISC0_BUILD_DEBUG=1
cargo build
Debug builds are much larger and slower. Only use for debugging.
RISC0_BUILD_LOCKED
Use --locked when building guest programs:
export RISC0_BUILD_LOCKED=1
cargo build
RISC0_GUEST_LOGFILE
Redirect guest build output:
export RISC0_GUEST_LOGFILE=/tmp/guest-build.log
cargo build
RISC0_RUST_SRC
Build Rust std from source:
export RISC0_RUST_SRC=/path/to/rust/src
cargo build
Guest Program Configuration
Your guest Cargo.toml should target the zkVM:
[package]
name = "guest"
version = "0.1.0"
edition = "2021"
[dependencies]
risc0-zkvm = { version = "1.0", default-features = false, features = ["std"] }
Set default-features = false to avoid pulling in host-only features.
Optional: Enable std
For more Rust std functionality:
[dependencies]
risc0-zkvm = { version = "1.0", default-features = false, features = ["std"] }
With std enabled, you can omit #![no_std] and #![no_main].
The RISC Zero Rust toolchain must be installed:
curl -L https://risczero.com/install | bash
rzup install rust
risc0-build automatically uses the installed toolchain.
Advanced: cargo_command
For custom build workflows, use cargo_command directly:
use risc0_build::cargo_command;
fn main() {
let mut cmd = cargo_command(
"build",
&["--cfg".to_string(), "my_config".to_string()],
);
cmd.args(["--release"]);
let status = cmd.status().expect("Failed to run cargo");
assert!(status.success());
}
Advanced: Building Specific Packages
Build individual guest packages programmatically:
use risc0_build::{build_package, get_package, GuestOptions};
use std::path::Path;
fn main() {
let pkg = get_package("methods/guest");
let target_dir = Path::new("target/riscv-guest");
let opts = GuestOptions::default();
let guests = build_package(&pkg, target_dir, opts)
.expect("Failed to build guest");
for guest in guests {
println!("Built guest: {}", guest.name);
println!("Image ID: {:?}", guest.image_id);
}
}
Troubleshooting
Install the RISC Zero toolchain:
Linker Errors
Ensure you’re not using host-only features:
risc0-zkvm = { version = "1.0", default-features = false }
Out of Memory During Build
Reduce parallel builds:
C/C++ Compilation Issues
Install the C++ toolchain:
Image ID Computation
The image ID is a cryptographic hash of the guest binary:
use risc0_binfmt::compute_image_id;
fn compute_id(elf: &[u8]) -> Result<Digest> {
compute_image_id(elf)
}
risc0-build uses the r0vm tool for fast image ID computation. If r0vm is unavailable, it falls back to the slower method.
Best Practices
Use embed_methods() for Standard Projects
The default embed_methods() is sufficient for most use cases.
Version Lock Dependencies
Use RISC0_BUILD_LOCKED=1 in CI to ensure reproducible builds.
Guest builds are expensive. Use cargo’s incremental compilation and CI caching.
Verify that image IDs are deterministic across builds for production systems.
See Also