mirror of
https://github.com/eth-act/ere.git
synced 2026-04-03 03:00:17 -04:00
Refactor stock rust compilation with crate compile-utils (#144)
This commit is contained in:
2
.github/workflows/test-common.yml
vendored
2
.github/workflows/test-common.yml
vendored
@@ -19,6 +19,8 @@ jobs:
|
||||
include:
|
||||
- crate: build-utils
|
||||
run_test: true
|
||||
- crate: compile-utils
|
||||
run_test: true
|
||||
- crate: test-utils
|
||||
run_test: true
|
||||
- crate: zkvm-interface
|
||||
|
||||
22
Cargo.lock
generated
22
Cargo.lock
generated
@@ -2537,6 +2537,15 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compile-utils"
|
||||
version = "0.0.12"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.19.2",
|
||||
"tempfile",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.11"
|
||||
@@ -3618,11 +3627,10 @@ dependencies = [
|
||||
name = "ere-jolt"
|
||||
version = "0.0.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ark-serialize 0.5.0",
|
||||
"build-utils",
|
||||
"cargo_metadata 0.19.2",
|
||||
"common",
|
||||
"compile-utils",
|
||||
"jolt",
|
||||
"jolt-core",
|
||||
"jolt-sdk",
|
||||
@@ -3630,7 +3638,6 @@ dependencies = [
|
||||
"tempfile",
|
||||
"test-utils",
|
||||
"thiserror 2.0.12",
|
||||
"toml 0.8.23",
|
||||
"zkvm-interface",
|
||||
]
|
||||
|
||||
@@ -3671,9 +3678,8 @@ dependencies = [
|
||||
name = "ere-openvm"
|
||||
version = "0.0.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"build-utils",
|
||||
"cargo_metadata 0.19.2",
|
||||
"compile-utils",
|
||||
"openvm-build",
|
||||
"openvm-circuit",
|
||||
"openvm-continuations",
|
||||
@@ -3695,7 +3701,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"bincode 1.3.3",
|
||||
"build-utils",
|
||||
"cargo_metadata 0.19.2",
|
||||
"compile-utils",
|
||||
"p3-field 0.1.0 (git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b)",
|
||||
"pico-vm",
|
||||
"serde",
|
||||
@@ -3714,7 +3720,7 @@ dependencies = [
|
||||
"borsh",
|
||||
"build-utils",
|
||||
"bytemuck",
|
||||
"cargo_metadata 0.19.2",
|
||||
"compile-utils",
|
||||
"risc0-binfmt",
|
||||
"risc0-build",
|
||||
"risc0-zkvm",
|
||||
@@ -3731,12 +3737,12 @@ version = "0.0.12"
|
||||
dependencies = [
|
||||
"bincode 1.3.3",
|
||||
"build-utils",
|
||||
"compile-utils",
|
||||
"serde",
|
||||
"sp1-sdk",
|
||||
"tempfile",
|
||||
"test-utils",
|
||||
"thiserror 2.0.12",
|
||||
"toml 0.8.23",
|
||||
"tracing",
|
||||
"zkvm-interface",
|
||||
]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/build-utils",
|
||||
"crates/compile-utils",
|
||||
"crates/test-utils",
|
||||
# zkVMs
|
||||
"crates/ere-jolt",
|
||||
@@ -95,6 +96,7 @@ zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren.git", tag = "v1.1.4" }
|
||||
# Local dependencies
|
||||
zkvm-interface = { path = "crates/zkvm-interface" }
|
||||
build-utils = { path = "crates/build-utils" }
|
||||
compile-utils = { path = "crates/compile-utils" }
|
||||
test-utils = { path = "crates/test-utils" }
|
||||
ere-cli = { path = "crates/ere-cli", default-features = false }
|
||||
ere-dockerized = { path = "crates/ere-dockerized" }
|
||||
|
||||
14
crates/compile-utils/Cargo.toml
Normal file
14
crates/compile-utils/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "compile-utils"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
cargo_metadata.workspace = true
|
||||
tempfile.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
23
crates/compile-utils/src/error.rs
Normal file
23
crates/compile-utils/src/error.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use std::{io, path::PathBuf, process::ExitStatus};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CompileError {
|
||||
#[error("`cargo metadata` in {manifest_dir} failed: {err}")]
|
||||
CargoMetadata {
|
||||
manifest_dir: PathBuf,
|
||||
err: cargo_metadata::Error,
|
||||
},
|
||||
#[error("Root package not found in {0}")]
|
||||
RootPackageNotFound(PathBuf),
|
||||
#[error("Failed to create temporary directory: {0}")]
|
||||
Tempdir(io::Error),
|
||||
#[error("Failed to create linker script: {0}")]
|
||||
CreateLinkerScript(io::Error),
|
||||
#[error("Failed to run `cargo build`: {0}")]
|
||||
CargoBuild(io::Error),
|
||||
#[error("`cargo build` failed: {0}")]
|
||||
CargoBuildFailed(ExitStatus),
|
||||
#[error("Failed to read built ELF: {0}")]
|
||||
ReadElf(io::Error),
|
||||
}
|
||||
7
crates/compile-utils/src/lib.rs
Normal file
7
crates/compile-utils/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
mod error;
|
||||
mod rust;
|
||||
|
||||
pub use {
|
||||
error::CompileError,
|
||||
rust::{CargoBuildCmd, cargo_metadata},
|
||||
};
|
||||
152
crates/compile-utils/src/rust.rs
Normal file
152
crates/compile-utils/src/rust.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
use crate::CompileError;
|
||||
use cargo_metadata::{Metadata, MetadataCommand};
|
||||
use std::{fs, iter, path::Path, process::Command};
|
||||
use tempfile::tempdir;
|
||||
|
||||
const CARGO_ENCODED_RUSTFLAGS_SEPARATOR: &str = "\x1f";
|
||||
|
||||
/// A builder for configuring `cargo build` invocation.
|
||||
#[derive(Clone)]
|
||||
pub struct CargoBuildCmd {
|
||||
toolchain: String,
|
||||
profile: String,
|
||||
rustflags: Vec<String>,
|
||||
build_options: Vec<String>,
|
||||
linker_script: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for CargoBuildCmd {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
toolchain: "stable".into(),
|
||||
profile: "release".into(),
|
||||
rustflags: Default::default(),
|
||||
build_options: Default::default(),
|
||||
linker_script: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CargoBuildCmd {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Toolchain to use.
|
||||
pub fn toolchain(mut self, toolchain: impl AsRef<str>) -> Self {
|
||||
self.toolchain = toolchain.as_ref().to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Profile to use.
|
||||
pub fn profile(mut self, profile: impl AsRef<str>) -> Self {
|
||||
self.profile = profile.as_ref().to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Environment variable `RUSTFLAGS`.
|
||||
pub fn rustflags(mut self, rustflags: &[impl AsRef<str>]) -> Self {
|
||||
self.rustflags = rustflags
|
||||
.iter()
|
||||
.map(|rustflag| rustflag.as_ref().to_string())
|
||||
.collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// Options after `cargo build`.
|
||||
pub fn build_options(mut self, build_options: &[impl AsRef<str>]) -> Self {
|
||||
self.build_options = build_options
|
||||
.iter()
|
||||
.map(|v| v.as_ref().to_string())
|
||||
.collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// Linker script to be saved into a file and pass to `RUSTFLAGS`.
|
||||
pub fn linker_script(mut self, linker_script: Option<impl AsRef<str>>) -> Self {
|
||||
self.linker_script = linker_script.map(|v| v.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Takes the path to the manifest directory and the target triple, then
|
||||
/// runs configured `cargo build` and returns built ELF.
|
||||
pub fn exec(
|
||||
&self,
|
||||
manifest_dir: impl AsRef<Path>,
|
||||
target: impl AsRef<str>,
|
||||
) -> Result<Vec<u8>, CompileError> {
|
||||
let metadata = cargo_metadata(manifest_dir.as_ref())?;
|
||||
|
||||
let package = metadata.root_package().unwrap();
|
||||
|
||||
let tempdir = tempdir().map_err(CompileError::Tempdir)?;
|
||||
let linker_script_path = tempdir
|
||||
.path()
|
||||
.join("linker_script")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
if let Some(linker_script) = &self.linker_script {
|
||||
fs::write(&linker_script_path, linker_script.as_bytes())
|
||||
.map_err(CompileError::CreateLinkerScript)?;
|
||||
}
|
||||
|
||||
let encoded_rustflags = iter::empty()
|
||||
.chain(self.rustflags.iter().cloned())
|
||||
.chain(
|
||||
self.linker_script
|
||||
.as_ref()
|
||||
.map(|_| ["-C".into(), format!("link-arg=-T{linker_script_path}")])
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
.join(CARGO_ENCODED_RUSTFLAGS_SEPARATOR);
|
||||
|
||||
let args = iter::empty()
|
||||
.chain([format!("+{}", &self.toolchain)])
|
||||
.chain(["build".into()])
|
||||
.chain(self.build_options.iter().cloned())
|
||||
.chain(["--profile".into(), self.profile.clone()])
|
||||
.chain(["--target".into(), target.as_ref().into()])
|
||||
.chain(["--manifest-path".into(), package.manifest_path.to_string()]);
|
||||
|
||||
let status = Command::new("cargo")
|
||||
.env("CARGO_ENCODED_RUSTFLAGS", encoded_rustflags)
|
||||
.args(args)
|
||||
.status()
|
||||
.map_err(CompileError::CargoBuild)?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(CompileError::CargoBuildFailed(status));
|
||||
}
|
||||
|
||||
let elf_path = metadata
|
||||
.target_directory
|
||||
.join(target.as_ref())
|
||||
.join(&self.profile)
|
||||
.join(&package.name);
|
||||
let elf = fs::read(elf_path).map_err(CompileError::ReadElf)?;
|
||||
|
||||
Ok(elf)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Metadata` of `manifest_dir` and guarantees the `root_package` can be resolved.
|
||||
pub fn cargo_metadata(manifest_dir: impl AsRef<Path>) -> Result<Metadata, CompileError> {
|
||||
let manifest_path = manifest_dir.as_ref().join("Cargo.toml");
|
||||
let metadata = MetadataCommand::new()
|
||||
.manifest_path(&manifest_path)
|
||||
.exec()
|
||||
.map_err(|err| CompileError::CargoMetadata {
|
||||
err,
|
||||
manifest_dir: manifest_dir.as_ref().to_path_buf(),
|
||||
})?;
|
||||
|
||||
if metadata.root_package().is_none() {
|
||||
return Err(CompileError::RootPackageNotFound(
|
||||
manifest_dir.as_ref().to_path_buf(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(metadata)
|
||||
}
|
||||
@@ -6,12 +6,9 @@ rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
cargo_metadata.workspace = true
|
||||
serde.workspace = true
|
||||
tempfile.workspace = true
|
||||
thiserror.workspace = true
|
||||
toml.workspace = true
|
||||
|
||||
# Jolt dependencies
|
||||
ark-serialize = { workspace = true, features = ["derive"] }
|
||||
@@ -21,6 +18,7 @@ jolt-core = { workspace = true, features = ["host"] }
|
||||
jolt-sdk = { workspace = true, features = ["host"] }
|
||||
|
||||
# Local dependencies
|
||||
compile-utils.workspace = true
|
||||
zkvm-interface.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
use crate::error::CompileError;
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use tempfile::TempDir;
|
||||
use compile_utils::CargoBuildCmd;
|
||||
use std::path::Path;
|
||||
|
||||
static CARGO_ENCODED_RUSTFLAGS_SEPARATOR: &str = "\x1f";
|
||||
const TARGET_TRIPLE: &str = "riscv32im-unknown-none-elf";
|
||||
// According to https://github.com/a16z/jolt/blob/55b9830a3944dde55d33a55c42522b81dd49f87a/jolt-core/src/host/mod.rs#L95
|
||||
const RUSTFLAGS: &[&str] = &[
|
||||
@@ -20,13 +14,9 @@ const RUSTFLAGS: &[&str] = &[
|
||||
"-C",
|
||||
"opt-level=z",
|
||||
];
|
||||
const CARGO_ARGS: &[&str] = &[
|
||||
"build",
|
||||
"--release",
|
||||
const CARGO_BUILD_OPTIONS: &[&str] = &[
|
||||
"--features",
|
||||
"guest",
|
||||
"--target",
|
||||
TARGET_TRIPLE,
|
||||
// For bare metal we have to build core and alloc
|
||||
"-Zbuild-std=core,alloc",
|
||||
];
|
||||
@@ -42,78 +32,24 @@ fn compile_program_stock_rust(
|
||||
guest_directory: &Path,
|
||||
toolchain: &String,
|
||||
) -> Result<Vec<u8>, CompileError> {
|
||||
let metadata = MetadataCommand::new().current_dir(guest_directory).exec()?;
|
||||
let package = metadata
|
||||
.root_package()
|
||||
.ok_or_else(|| CompileError::MissingPackageName {
|
||||
path: guest_directory.to_path_buf(),
|
||||
})?;
|
||||
let elf = CargoBuildCmd::new()
|
||||
.linker_script(Some(make_linker_script()))
|
||||
.toolchain(toolchain)
|
||||
.build_options(CARGO_BUILD_OPTIONS)
|
||||
.rustflags(RUSTFLAGS)
|
||||
.exec(guest_directory, TARGET_TRIPLE)?;
|
||||
|
||||
let plus_toolchain = format!("+{}", toolchain);
|
||||
let mut cargo_args = [plus_toolchain.as_str()].to_vec();
|
||||
cargo_args.append(&mut CARGO_ARGS.to_vec());
|
||||
|
||||
let mut encoded_rust_flags = RUSTFLAGS.to_vec();
|
||||
let temp_output_dir = TempDir::new_in(guest_directory).unwrap();
|
||||
let linker_script_path = make_linker_script(temp_output_dir.path(), &package.name)?;
|
||||
let linker_path = format!("link-arg=-T{}", linker_script_path.display());
|
||||
encoded_rust_flags.append(&mut ["-C", &linker_path].to_vec());
|
||||
|
||||
let encoded_rust_flags_str = encoded_rust_flags.join(CARGO_ENCODED_RUSTFLAGS_SEPARATOR);
|
||||
|
||||
let target_direcotry = guest_directory
|
||||
.join("target")
|
||||
.join(TARGET_TRIPLE)
|
||||
.join("release");
|
||||
|
||||
// Remove target directory.
|
||||
if target_direcotry.exists() {
|
||||
fs::remove_dir_all(&target_direcotry).unwrap();
|
||||
}
|
||||
|
||||
let result = Command::new("cargo")
|
||||
.current_dir(guest_directory)
|
||||
.env("CARGO_ENCODED_RUSTFLAGS", &encoded_rust_flags_str)
|
||||
.args(cargo_args)
|
||||
.stdout(std::process::Stdio::inherit())
|
||||
.stderr(std::process::Stdio::inherit())
|
||||
.status()
|
||||
.map_err(|source| CompileError::BuildFailure {
|
||||
source: source.into(),
|
||||
crate_path: guest_directory.to_path_buf(),
|
||||
});
|
||||
|
||||
if result.is_err() {
|
||||
return Err(result.err().unwrap());
|
||||
}
|
||||
|
||||
let elf_path = target_direcotry.join(&package.name);
|
||||
|
||||
fs::read(&elf_path).map_err(|e| CompileError::ReadFile {
|
||||
path: elf_path,
|
||||
source: e,
|
||||
})
|
||||
Ok(elf)
|
||||
}
|
||||
|
||||
const DEFAULT_MEMORY_SIZE: u64 = 10 * 1024 * 1024;
|
||||
const DEFAULT_STACK_SIZE: u64 = 4096;
|
||||
const LINKER_SCRIPT_TEMPLATE: &str = include_str!("template.ld");
|
||||
|
||||
fn make_linker_script(
|
||||
temp_output_dir_path: &Path,
|
||||
program_name: &String,
|
||||
) -> Result<PathBuf, CompileError> {
|
||||
let linker_path = temp_output_dir_path.join(format!("{}.ld", program_name));
|
||||
|
||||
let linker_script = LINKER_SCRIPT_TEMPLATE
|
||||
fn make_linker_script() -> String {
|
||||
LINKER_SCRIPT_TEMPLATE
|
||||
.replace("{MEMORY_SIZE}", &DEFAULT_MEMORY_SIZE.to_string())
|
||||
.replace("{STACK_SIZE}", &DEFAULT_STACK_SIZE.to_string());
|
||||
|
||||
let mut file = File::create(&linker_path).expect("could not create linker file");
|
||||
file.write_all(linker_script.as_bytes())
|
||||
.expect("could not save linker");
|
||||
|
||||
Ok(linker_path)
|
||||
.replace("{STACK_SIZE}", &DEFAULT_STACK_SIZE.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -27,33 +27,14 @@ pub enum JoltError {
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CompileError {
|
||||
#[error("Failed to find guest program name at {path}: {source}")]
|
||||
PackageNameNotFound {
|
||||
source: Box<dyn std::error::Error + Send + Sync + 'static>,
|
||||
path: PathBuf,
|
||||
},
|
||||
#[error("Failed to build guest")]
|
||||
BuildFailed,
|
||||
#[error("`jolt` build failure for {crate_path} failed: {source}")]
|
||||
BuildFailure {
|
||||
#[source]
|
||||
source: anyhow::Error,
|
||||
crate_path: PathBuf,
|
||||
},
|
||||
#[error("Failed to read elf at {path}: {source}")]
|
||||
ReadElfFailed { source: io::Error, path: PathBuf },
|
||||
#[error("Failed to set current directory to {path}: {source}")]
|
||||
SetCurrentDirFailed { source: io::Error, path: PathBuf },
|
||||
#[error("`cargo metadata` failed: {0}")]
|
||||
MetadataCommand(#[from] cargo_metadata::Error),
|
||||
#[error("Could not find `[package].name` in guest Cargo.toml at {path}")]
|
||||
MissingPackageName { path: PathBuf },
|
||||
#[error("Failed to read file at {path}: {source}")]
|
||||
ReadFile {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error(transparent)]
|
||||
CompileUtilError(#[from] compile_utils::CompileError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
|
||||
use crate::{
|
||||
error::{CompileError, JoltError, ProveError, VerifyError},
|
||||
utils::package_name_from_manifest,
|
||||
};
|
||||
use crate::error::{CompileError, JoltError, ProveError, VerifyError};
|
||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||
use compile_stock_rust::compile_jolt_program_stock_rust;
|
||||
use compile_utils::cargo_metadata;
|
||||
use jolt::{JoltHyperKZGProof, JoltProverPreprocessing, JoltVerifierPreprocessing};
|
||||
use jolt_core::host::Program;
|
||||
use jolt_methods::{preprocess_prover, preprocess_verifier, prove_generic, verify_generic};
|
||||
@@ -28,7 +26,6 @@ include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
mod compile_stock_rust;
|
||||
mod error;
|
||||
mod jolt_methods;
|
||||
mod utils;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct JOLT_TARGET;
|
||||
@@ -57,7 +54,12 @@ fn compile_jolt_program(guest_directory: &Path) -> Result<Vec<u8>, JoltError> {
|
||||
path: guest_directory.to_path_buf(),
|
||||
})?;
|
||||
|
||||
let package_name = package_name_from_manifest(Path::new("Cargo.toml"))?;
|
||||
let package_name = cargo_metadata(guest_directory)
|
||||
.map_err(CompileError::CompileUtilError)?
|
||||
.root_package()
|
||||
.unwrap()
|
||||
.name
|
||||
.clone();
|
||||
|
||||
// Note that if this fails, it will panic, hence we need to catch it.
|
||||
let elf_path = std::panic::catch_unwind(|| {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
use crate::JoltError;
|
||||
use crate::error::CompileError;
|
||||
use std::{fs, path::Path};
|
||||
use toml::Value;
|
||||
|
||||
/// Reads the `[package] name` out of a Cargo.toml.
|
||||
///
|
||||
/// * `manifest_path` – absolute or relative path to a Cargo.toml.
|
||||
/// * Returns → `String` with the package name (`fib`, `my_guest`, …).
|
||||
pub(crate) fn package_name_from_manifest(manifest_path: &Path) -> Result<String, JoltError> {
|
||||
let manifest =
|
||||
fs::read_to_string(manifest_path).map_err(|source| CompileError::PackageNameNotFound {
|
||||
source: source.into(),
|
||||
path: manifest_path.to_path_buf(),
|
||||
})?;
|
||||
let value: Value =
|
||||
manifest
|
||||
.parse::<Value>()
|
||||
.map_err(|source| CompileError::PackageNameNotFound {
|
||||
source: source.into(),
|
||||
path: manifest_path.to_path_buf(),
|
||||
})?;
|
||||
|
||||
Ok(value
|
||||
.get("package")
|
||||
.and_then(|pkg| pkg.get("name"))
|
||||
.and_then(Value::as_str)
|
||||
.map(|s| s.to_owned())
|
||||
.ok_or_else(|| CompileError::PackageNameNotFound {
|
||||
source: "[package.name] not found".into(),
|
||||
path: manifest_path.to_path_buf(),
|
||||
})?)
|
||||
}
|
||||
@@ -6,10 +6,8 @@ rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror.workspace = true
|
||||
cargo_metadata.workspace = true
|
||||
tracing.workspace = true
|
||||
toml.workspace = true
|
||||
|
||||
@@ -22,6 +20,7 @@ openvm-stark-sdk.workspace = true
|
||||
openvm-transpiler.workspace = true
|
||||
|
||||
# Local dependencies
|
||||
compile-utils.workspace = true
|
||||
zkvm-interface.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
use crate::OpenVMProgram;
|
||||
use crate::error::CompileError;
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use compile_utils::CargoBuildCmd;
|
||||
use openvm_sdk::config::{AppConfig, DEFAULT_APP_LOG_BLOWUP, DEFAULT_LEAF_LOG_BLOWUP, SdkVmConfig};
|
||||
use openvm_stark_sdk::config::FriParameters;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use tracing::info;
|
||||
|
||||
static CARGO_ENCODED_RUSTFLAGS_SEPARATOR: &str = "\x1f";
|
||||
const TARGET_TRIPLE: &str = "riscv32ima-unknown-none-elf";
|
||||
// Rust flags according to https://github.com/openvm-org/openvm/blob/v1.4.0/crates/toolchain/build/src/lib.rs#L291
|
||||
const RUSTFLAGS: &[&str] = &[
|
||||
@@ -32,11 +30,7 @@ const RUSTFLAGS: &[&str] = &[
|
||||
"--cfg",
|
||||
"getrandom_backend=\"custom\"",
|
||||
];
|
||||
const CARGO_ARGS: &[&str] = &[
|
||||
"build",
|
||||
"--target",
|
||||
TARGET_TRIPLE,
|
||||
"--release",
|
||||
const CARGO_BUILD_OPTIONS: &[&str] = &[
|
||||
// For bare metal we have to build core and alloc
|
||||
"-Zbuild-std=core,alloc",
|
||||
];
|
||||
@@ -55,51 +49,13 @@ fn compile_program_stock_rust(
|
||||
guest_directory: &Path,
|
||||
toolchain: &String,
|
||||
) -> Result<Vec<u8>, CompileError> {
|
||||
let metadata = MetadataCommand::new().current_dir(guest_directory).exec()?;
|
||||
let package = metadata
|
||||
.root_package()
|
||||
.ok_or_else(|| CompileError::MissingPackageName {
|
||||
path: guest_directory.to_path_buf(),
|
||||
})?;
|
||||
let elf = CargoBuildCmd::new()
|
||||
.toolchain(toolchain)
|
||||
.build_options(CARGO_BUILD_OPTIONS)
|
||||
.rustflags(RUSTFLAGS)
|
||||
.exec(guest_directory, TARGET_TRIPLE)?;
|
||||
|
||||
let plus_toolchain = format!("+{}", toolchain);
|
||||
let mut cargo_args = [plus_toolchain.as_str()].to_vec();
|
||||
cargo_args.append(&mut CARGO_ARGS.to_vec());
|
||||
|
||||
let encoded_rust_flags = RUSTFLAGS.to_vec().join(CARGO_ENCODED_RUSTFLAGS_SEPARATOR);
|
||||
|
||||
let target_direcotry = guest_directory
|
||||
.join("target")
|
||||
.join(TARGET_TRIPLE)
|
||||
.join("release");
|
||||
|
||||
// Remove target directory.
|
||||
if target_direcotry.exists() {
|
||||
fs::remove_dir_all(&target_direcotry).unwrap();
|
||||
}
|
||||
|
||||
let result = Command::new("cargo")
|
||||
.current_dir(guest_directory)
|
||||
.env("CARGO_ENCODED_RUSTFLAGS", &encoded_rust_flags)
|
||||
.args(cargo_args)
|
||||
.stdout(std::process::Stdio::inherit())
|
||||
.stderr(std::process::Stdio::inherit())
|
||||
.status()
|
||||
.map_err(|source| CompileError::BuildFailure {
|
||||
source: source.into(),
|
||||
crate_path: guest_directory.to_path_buf(),
|
||||
});
|
||||
|
||||
if result.is_err() {
|
||||
return Err(result.err().unwrap());
|
||||
}
|
||||
|
||||
let elf_path = target_direcotry.join(&package.name);
|
||||
|
||||
fs::read(&elf_path).map_err(|e| CompileError::ReadFile {
|
||||
path: elf_path,
|
||||
source: e,
|
||||
})
|
||||
Ok(elf)
|
||||
}
|
||||
|
||||
fn wrap_into_openvm_program(
|
||||
|
||||
@@ -34,12 +34,6 @@ pub enum OpenVMError {
|
||||
pub enum CompileError {
|
||||
#[error("Failed to build guest, code: {0}")]
|
||||
BuildFailed(i32),
|
||||
#[error("`openvm` build failure for {crate_path} failed: {source}")]
|
||||
BuildFailure {
|
||||
#[source]
|
||||
source: anyhow::Error,
|
||||
crate_path: PathBuf,
|
||||
},
|
||||
#[error("Guest building skipped (OPENVM_SKIP_BUILD is set)")]
|
||||
BuildSkipped,
|
||||
#[error("Missing to find unique elf: {0}")]
|
||||
@@ -50,16 +44,8 @@ pub enum CompileError {
|
||||
ReadConfigFailed { source: io::Error, path: PathBuf },
|
||||
#[error("Failed to deserialize OpenVM's config file: {0}")]
|
||||
DeserializeConfigFailed(toml::de::Error),
|
||||
#[error("`cargo metadata` failed: {0}")]
|
||||
MetadataCommand(#[from] cargo_metadata::Error),
|
||||
#[error("Could not find `[package].name` in guest Cargo.toml at {path}")]
|
||||
MissingPackageName { path: PathBuf },
|
||||
#[error("Failed to read file at {path}: {source}")]
|
||||
ReadFile {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error(transparent)]
|
||||
CompileUtilError(#[from] compile_utils::CompileError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
||||
@@ -8,7 +8,6 @@ license.workspace = true
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
bincode.workspace = true
|
||||
cargo_metadata.workspace = true
|
||||
sha2.workspace = true
|
||||
serde.workspace = true
|
||||
tempfile.workspace = true
|
||||
@@ -19,6 +18,7 @@ pico-p3-field.workspace = true
|
||||
pico-vm.workspace = true
|
||||
|
||||
# Local dependencies
|
||||
compile-utils.workspace = true
|
||||
zkvm-interface.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
use crate::error::CompileError;
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use std::fs;
|
||||
use compile_utils::CargoBuildCmd;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
static CARGO_ENCODED_RUSTFLAGS_SEPARATOR: &str = "\x1f";
|
||||
|
||||
const TARGET_TRIPLE: &str = "riscv32ima-unknown-none-elf";
|
||||
// According to https://github.com/brevis-network/pico/blob/v1.1.7/sdk/cli/src/build/build.rs#L104
|
||||
@@ -26,11 +22,7 @@ const RUSTFLAGS: &[&str] = &[
|
||||
"-C",
|
||||
"panic=abort",
|
||||
];
|
||||
const CARGO_ARGS: &[&str] = &[
|
||||
"build",
|
||||
"--target",
|
||||
TARGET_TRIPLE,
|
||||
"--release",
|
||||
const CARGO_BUILD_OPTIONS: &[&str] = &[
|
||||
// For bare metal we have to build core and alloc
|
||||
"-Zbuild-std=core,alloc",
|
||||
];
|
||||
@@ -46,51 +38,13 @@ fn compile_program_stock_rust(
|
||||
guest_directory: &Path,
|
||||
toolchain: &String,
|
||||
) -> Result<Vec<u8>, CompileError> {
|
||||
let metadata = MetadataCommand::new().current_dir(guest_directory).exec()?;
|
||||
let package = metadata
|
||||
.root_package()
|
||||
.ok_or_else(|| CompileError::MissingPackageName {
|
||||
path: guest_directory.to_path_buf(),
|
||||
})?;
|
||||
let elf = CargoBuildCmd::new()
|
||||
.toolchain(toolchain)
|
||||
.build_options(CARGO_BUILD_OPTIONS)
|
||||
.rustflags(RUSTFLAGS)
|
||||
.exec(guest_directory, TARGET_TRIPLE)?;
|
||||
|
||||
let plus_toolchain = format!("+{}", toolchain);
|
||||
let mut cargo_args = [plus_toolchain.as_str()].to_vec();
|
||||
cargo_args.append(&mut CARGO_ARGS.to_vec());
|
||||
|
||||
let encoded_rust_flags = RUSTFLAGS.to_vec().join(CARGO_ENCODED_RUSTFLAGS_SEPARATOR);
|
||||
|
||||
let target_direcotry = guest_directory
|
||||
.join("target")
|
||||
.join(TARGET_TRIPLE)
|
||||
.join("release");
|
||||
|
||||
// Remove target directory.
|
||||
if target_direcotry.exists() {
|
||||
fs::remove_dir_all(&target_direcotry).unwrap();
|
||||
}
|
||||
|
||||
let result = Command::new("cargo")
|
||||
.current_dir(guest_directory)
|
||||
.env("CARGO_ENCODED_RUSTFLAGS", &encoded_rust_flags)
|
||||
.args(cargo_args)
|
||||
.stdout(std::process::Stdio::inherit())
|
||||
.stderr(std::process::Stdio::inherit())
|
||||
.status()
|
||||
.map_err(|source| CompileError::BuildFailure {
|
||||
source: source.into(),
|
||||
crate_path: guest_directory.to_path_buf(),
|
||||
});
|
||||
|
||||
if result.is_err() {
|
||||
return Err(result.err().unwrap());
|
||||
}
|
||||
|
||||
let elf_path = target_direcotry.join(&package.name);
|
||||
|
||||
fs::read(&elf_path).map_err(|e| CompileError::ReadFile {
|
||||
path: elf_path,
|
||||
source: e,
|
||||
})
|
||||
Ok(elf)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -46,22 +46,8 @@ pub enum CompileError {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("Pico build failure for {crate_path} failed: {source}")]
|
||||
BuildFailure {
|
||||
#[source]
|
||||
source: anyhow::Error,
|
||||
crate_path: PathBuf,
|
||||
},
|
||||
#[error("Could not find `[package].name` in guest Cargo.toml at {path}")]
|
||||
MissingPackageName { path: PathBuf },
|
||||
#[error("Failed to read file at {path}: {source}")]
|
||||
ReadFile {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("`cargo metadata` failed: {0}")]
|
||||
MetadataCommand(#[from] cargo_metadata::Error),
|
||||
#[error(transparent)]
|
||||
CompileUtilError(#[from] compile_utils::CompileError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
||||
@@ -9,7 +9,6 @@ license.workspace = true
|
||||
anyhow.workspace = true
|
||||
borsh.workspace = true
|
||||
bytemuck.workspace = true
|
||||
cargo_metadata.workspace = true
|
||||
serde = { workspace = true, features = ["derive", "rc"] }
|
||||
thiserror.workspace = true
|
||||
tracing.workspace = true
|
||||
@@ -20,6 +19,7 @@ risc0-zkvm = { workspace = true, features = ["client", "unstable"] }
|
||||
risc0-binfmt.workspace = true
|
||||
|
||||
# Local dependencies
|
||||
compile-utils.workspace = true
|
||||
zkvm-interface.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::error::CompileError;
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use compile_utils::cargo_metadata;
|
||||
use risc0_build::GuestOptions;
|
||||
use risc0_zkvm::Digest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -15,12 +15,8 @@ pub struct Risc0Program {
|
||||
pub fn compile_risc0_program(guest_directory: &Path) -> Result<Risc0Program, CompileError> {
|
||||
info!("Compiling Risc0 program at {}", guest_directory.display());
|
||||
|
||||
let metadata = MetadataCommand::new().current_dir(guest_directory).exec()?;
|
||||
let package = metadata
|
||||
.root_package()
|
||||
.ok_or_else(|| CompileError::MissingPackageName {
|
||||
path: guest_directory.to_path_buf(),
|
||||
})?;
|
||||
let metadata = cargo_metadata(guest_directory)?;
|
||||
let package = metadata.root_package().unwrap();
|
||||
|
||||
// Use `risc0_build::build_package` to build package instead of calling
|
||||
// `cargo-risczero build` for the `unstable` features.
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
use crate::compile::Risc0Program;
|
||||
use crate::error::CompileError;
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use compile_utils::CargoBuildCmd;
|
||||
use risc0_binfmt::ProgramBinary;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use tracing::info;
|
||||
|
||||
static CARGO_ENCODED_RUSTFLAGS_SEPARATOR: &str = "\x1f";
|
||||
// TODO: Make this with `zkos` package building to avoid binary file storing in repo.
|
||||
// File taken from https://github.com/risc0/risc0/blob/v3.0.3/risc0/zkos/v1compat/elfs/v1compat.elf
|
||||
const V1COMPAT_ELF: &[u8] = include_bytes!("kernel_elf/v1compat.elf");
|
||||
@@ -26,11 +23,7 @@ const RUSTFLAGS: &[&str] = &[
|
||||
"--cfg",
|
||||
"getrandom_backend=\"custom\"",
|
||||
];
|
||||
const CARGO_ARGS: &[&str] = &[
|
||||
"build",
|
||||
"--target",
|
||||
TARGET_TRIPLE,
|
||||
"--release",
|
||||
const CARGO_BUILD_OPTIONS: &[&str] = &[
|
||||
// For bare metal we have to build core and alloc
|
||||
"-Zbuild-std=core,alloc",
|
||||
];
|
||||
@@ -46,51 +39,13 @@ fn compile_program_stock_rust(
|
||||
guest_directory: &Path,
|
||||
toolchain: &String,
|
||||
) -> Result<Vec<u8>, CompileError> {
|
||||
let metadata = MetadataCommand::new().current_dir(guest_directory).exec()?;
|
||||
let package = metadata
|
||||
.root_package()
|
||||
.ok_or_else(|| CompileError::MissingPackageName {
|
||||
path: guest_directory.to_path_buf(),
|
||||
})?;
|
||||
let elf = CargoBuildCmd::new()
|
||||
.toolchain(toolchain)
|
||||
.build_options(CARGO_BUILD_OPTIONS)
|
||||
.rustflags(RUSTFLAGS)
|
||||
.exec(guest_directory, TARGET_TRIPLE)?;
|
||||
|
||||
let plus_toolchain = format!("+{}", toolchain);
|
||||
let mut cargo_args = [plus_toolchain.as_str()].to_vec();
|
||||
cargo_args.append(&mut CARGO_ARGS.to_vec());
|
||||
|
||||
let encoded_rust_flags = RUSTFLAGS.to_vec().join(CARGO_ENCODED_RUSTFLAGS_SEPARATOR);
|
||||
|
||||
let target_direcotry = guest_directory
|
||||
.join("target")
|
||||
.join(TARGET_TRIPLE)
|
||||
.join("release");
|
||||
|
||||
// Remove target directory.
|
||||
if target_direcotry.exists() {
|
||||
fs::remove_dir_all(&target_direcotry).unwrap();
|
||||
}
|
||||
|
||||
let result = Command::new("cargo")
|
||||
.current_dir(guest_directory)
|
||||
.env("CARGO_ENCODED_RUSTFLAGS", &encoded_rust_flags)
|
||||
.args(cargo_args)
|
||||
.stdout(std::process::Stdio::inherit())
|
||||
.stderr(std::process::Stdio::inherit())
|
||||
.status()
|
||||
.map_err(|source| CompileError::BuildFailure {
|
||||
source: source.into(),
|
||||
crate_path: guest_directory.to_path_buf(),
|
||||
});
|
||||
|
||||
if result.is_err() {
|
||||
return Err(result.err().unwrap());
|
||||
}
|
||||
|
||||
let elf_path = target_direcotry.join(&package.name);
|
||||
|
||||
fs::read(&elf_path).map_err(|e| CompileError::ReadFile {
|
||||
path: elf_path,
|
||||
source: e,
|
||||
})
|
||||
Ok(elf)
|
||||
}
|
||||
|
||||
fn wrap_into_risc0_program(elf: Vec<u8>) -> Result<Risc0Program, CompileError> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{io, path::PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@@ -9,16 +9,6 @@ pub enum Risc0Error {
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CompileError {
|
||||
#[error("{context}: {source}")]
|
||||
Io {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
context: &'static str,
|
||||
},
|
||||
#[error("`cargo metadata` failed: {0}")]
|
||||
MetadataCommand(#[from] cargo_metadata::Error),
|
||||
#[error("Could not find `[package].name` in guest Cargo.toml at {path}")]
|
||||
MissingPackageName { path: PathBuf },
|
||||
#[error("`risc0_build::build_package` for {crate_path} failed: {source}")]
|
||||
BuildFailure {
|
||||
#[source]
|
||||
@@ -27,18 +17,8 @@ pub enum CompileError {
|
||||
},
|
||||
#[error("`risc0_build::build_package` succeeded but failed to find guest")]
|
||||
Risc0BuildMissingGuest,
|
||||
#[error("Failed to read file at {path}: {source}")]
|
||||
ReadFile {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("ELF binary image calculation failure : {0}")]
|
||||
ImageIDCalculationFailure(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
impl CompileError {
|
||||
pub fn io(e: io::Error, context: &'static str) -> Self {
|
||||
Self::Io { source: e, context }
|
||||
}
|
||||
#[error(transparent)]
|
||||
CompileUtilError(#[from] compile_utils::CompileError),
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
[package]
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
name = "ere-sp1"
|
||||
rust-version.workspace = true
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bincode.workspace = true
|
||||
serde.workspace = true
|
||||
tempfile.workspace = true
|
||||
thiserror.workspace = true
|
||||
toml.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
# SP1 dependencies
|
||||
sp1-sdk.workspace = true
|
||||
|
||||
# Local dependencies
|
||||
compile-utils.workspace = true
|
||||
zkvm-interface.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use crate::compile_stock_rust::stock_rust_compile;
|
||||
use crate::error::CompileError;
|
||||
use std::process::ExitStatus;
|
||||
use std::{fs, path::Path, path::PathBuf, process::Command};
|
||||
use tempfile::TempDir;
|
||||
use std::{fs, path::Path, process::Command};
|
||||
use tempfile::tempdir;
|
||||
use tracing::info;
|
||||
|
||||
fn get_guest_program_name(guest_directory: &Path) -> Result<String, CompileError> {
|
||||
fn sp1_compile(guest_directory: &Path) -> Result<Vec<u8>, CompileError> {
|
||||
info!("Compiling SP1 program at {}", guest_directory.display());
|
||||
|
||||
if !guest_directory.exists() || !guest_directory.is_dir() {
|
||||
return Err(CompileError::InvalidProgramPath(
|
||||
guest_directory.to_path_buf(),
|
||||
@@ -20,89 +21,39 @@ fn get_guest_program_name(guest_directory: &Path) -> Result<String, CompileError
|
||||
});
|
||||
}
|
||||
|
||||
// ── read + parse Cargo.toml ───────────────────────────────────────────
|
||||
let manifest_content =
|
||||
fs::read_to_string(&guest_manifest_path).map_err(|e| CompileError::ReadFile {
|
||||
path: guest_manifest_path.clone(),
|
||||
source: e,
|
||||
})?;
|
||||
// ── build into a temp dir ─────────────────────────────────────────────
|
||||
let temp_output_dir = tempdir()?;
|
||||
let temp_output_dir_path = temp_output_dir.path();
|
||||
|
||||
let manifest_toml: toml::Value =
|
||||
manifest_content
|
||||
.parse::<toml::Value>()
|
||||
.map_err(|e| CompileError::ParseCargoToml {
|
||||
path: guest_manifest_path.clone(),
|
||||
source: e,
|
||||
})?;
|
||||
|
||||
let program_name = manifest_toml
|
||||
.get("package")
|
||||
.and_then(|p| p.get("name"))
|
||||
.and_then(|n| n.as_str())
|
||||
.ok_or_else(|| CompileError::MissingPackageName {
|
||||
path: guest_manifest_path.clone(),
|
||||
})?;
|
||||
|
||||
Ok(program_name.into())
|
||||
}
|
||||
|
||||
fn sp1_compile(
|
||||
guest_directory: &Path,
|
||||
output_directory: &Path,
|
||||
) -> Result<(ExitStatus, PathBuf), CompileError> {
|
||||
info!(
|
||||
"Running `cargo prove build` → dir: {}",
|
||||
output_directory.display(),
|
||||
temp_output_dir_path.display(),
|
||||
);
|
||||
|
||||
let result = Command::new("cargo")
|
||||
let status = Command::new("cargo")
|
||||
.current_dir(guest_directory)
|
||||
.args([
|
||||
"prove",
|
||||
"build",
|
||||
"--output-directory",
|
||||
output_directory.to_str().unwrap(),
|
||||
temp_output_dir_path.to_str().unwrap(),
|
||||
"--elf-name",
|
||||
"guest.elf",
|
||||
])
|
||||
.stdout(std::process::Stdio::inherit())
|
||||
.stderr(std::process::Stdio::inherit())
|
||||
.status()
|
||||
.map_err(|e| CompileError::CargoProveBuild {
|
||||
cwd: guest_directory.to_path_buf(),
|
||||
source: e,
|
||||
});
|
||||
match result {
|
||||
Ok(status) => Ok((status, output_directory.join("guest.elf"))),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile(guest_directory: &Path, toolchain: &String) -> Result<Vec<u8>, CompileError> {
|
||||
let program_name = get_guest_program_name(guest_directory)?;
|
||||
info!("Parsed program name: {program_name}");
|
||||
|
||||
// ── build into a temp dir ─────────────────────────────────────────────
|
||||
let temp_output_dir = TempDir::new_in(guest_directory)?;
|
||||
let temp_output_dir_path = temp_output_dir.path();
|
||||
|
||||
let (status, elf_path) = match toolchain.as_str() {
|
||||
"succinct" => sp1_compile(guest_directory, temp_output_dir_path)?,
|
||||
_ => stock_rust_compile(
|
||||
guest_directory,
|
||||
temp_output_dir_path,
|
||||
&program_name,
|
||||
toolchain,
|
||||
)?,
|
||||
};
|
||||
})?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(CompileError::CargoBuildFailed {
|
||||
return Err(CompileError::CargoProveBuildFailed {
|
||||
status,
|
||||
path: guest_directory.to_path_buf(),
|
||||
});
|
||||
}
|
||||
|
||||
let elf_path = temp_output_dir_path.join("guest.elf");
|
||||
if !elf_path.exists() {
|
||||
return Err(CompileError::ElfNotFound(elf_path));
|
||||
}
|
||||
@@ -111,15 +62,18 @@ pub fn compile(guest_directory: &Path, toolchain: &String) -> Result<Vec<u8>, Co
|
||||
path: elf_path,
|
||||
source: e,
|
||||
})?;
|
||||
info!(
|
||||
"SP1 ({}) program compiled OK - {} bytes",
|
||||
toolchain,
|
||||
elf_bytes.len()
|
||||
);
|
||||
info!("SP1 program compiled OK - {} bytes", elf_bytes.len());
|
||||
|
||||
Ok(elf_bytes)
|
||||
}
|
||||
|
||||
pub fn compile(guest_directory: &Path, toolchain: &String) -> Result<Vec<u8>, CompileError> {
|
||||
match toolchain.as_str() {
|
||||
"succinct" => sp1_compile(guest_directory),
|
||||
_ => stock_rust_compile(guest_directory, toolchain),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::RV32_IM_SUCCINCT_ZKVM_ELF;
|
||||
|
||||
@@ -1,81 +1,41 @@
|
||||
use crate::error::CompileError;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, ExitStatus};
|
||||
use tracing::info;
|
||||
use compile_utils::CargoBuildCmd;
|
||||
use std::path::Path;
|
||||
|
||||
static CARGO_ENCODED_RUSTFLAGS_SEPARATOR: &str = "\x1f";
|
||||
const TARGET_TRIPLE: &str = "riscv32ima-unknown-none-elf";
|
||||
const RUSTFLAGS: &[&str] = &[
|
||||
"-C",
|
||||
"passes=lower-atomic", // Only for rustc > 1.81
|
||||
"-C",
|
||||
// Start of the code section
|
||||
"link-arg=-Ttext=0x00201000",
|
||||
"-C",
|
||||
// The lowest memory location that will be used when your program is loaded
|
||||
"link-arg=--image-base=0x00200800",
|
||||
"-C",
|
||||
"panic=abort",
|
||||
"--cfg",
|
||||
"getrandom_backend=\"custom\"",
|
||||
"-C",
|
||||
"llvm-args=-misched-prera-direction=bottomup",
|
||||
"-C",
|
||||
"llvm-args=-misched-postra-direction=bottomup",
|
||||
];
|
||||
|
||||
const CARGO_BUILD_OPTIONS: &[&str] = &[
|
||||
// For bare metal we have to build core and alloc
|
||||
"-Zbuild-std=core,alloc",
|
||||
];
|
||||
|
||||
pub fn stock_rust_compile(
|
||||
guest_directory: &Path,
|
||||
output_directory: &Path,
|
||||
program_name: &String,
|
||||
toolchain: &String,
|
||||
) -> Result<(ExitStatus, PathBuf), CompileError> {
|
||||
info!(
|
||||
"Running `cargo build` (toolchain `{}`) → dir: {}",
|
||||
toolchain,
|
||||
output_directory.display(),
|
||||
);
|
||||
) -> Result<Vec<u8>, CompileError> {
|
||||
let elf = CargoBuildCmd::new()
|
||||
.toolchain(toolchain)
|
||||
.build_options(CARGO_BUILD_OPTIONS)
|
||||
.rustflags(RUSTFLAGS)
|
||||
.exec(guest_directory, TARGET_TRIPLE)?;
|
||||
|
||||
let target_name = "riscv32ima-unknown-none-elf";
|
||||
let plus_toolchain = format!("+{toolchain}");
|
||||
|
||||
let args = [
|
||||
plus_toolchain.as_str(),
|
||||
"build",
|
||||
"--target-dir",
|
||||
output_directory.to_str().unwrap(),
|
||||
"--target",
|
||||
target_name,
|
||||
"--release",
|
||||
// For bare metal we have to build core and alloc
|
||||
"-Zbuild-std=core,alloc",
|
||||
];
|
||||
|
||||
let rust_flags = [
|
||||
"-C",
|
||||
"passes=lower-atomic", // Only for rustc > 1.81
|
||||
"-C",
|
||||
// Start of the code section
|
||||
"link-arg=-Ttext=0x00201000",
|
||||
"-C",
|
||||
// The lowest memory location that will be used when your program is loaded
|
||||
"link-arg=--image-base=0x00200800",
|
||||
"-C",
|
||||
"panic=abort",
|
||||
"--cfg",
|
||||
"getrandom_backend=\"custom\"",
|
||||
"-C",
|
||||
"llvm-args=-misched-prera-direction=bottomup",
|
||||
"-C",
|
||||
"llvm-args=-misched-postra-direction=bottomup",
|
||||
];
|
||||
|
||||
let encoded_rust_flags = rust_flags
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
.join(CARGO_ENCODED_RUSTFLAGS_SEPARATOR);
|
||||
|
||||
let result = Command::new("cargo")
|
||||
.current_dir(guest_directory)
|
||||
.env("CARGO_ENCODED_RUSTFLAGS", &encoded_rust_flags)
|
||||
.args(args)
|
||||
.stdout(std::process::Stdio::inherit())
|
||||
.stderr(std::process::Stdio::inherit())
|
||||
.status()
|
||||
.map_err(|e| CompileError::CargoProveBuild {
|
||||
cwd: guest_directory.to_path_buf(),
|
||||
source: e,
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(status) => Ok((
|
||||
status,
|
||||
output_directory
|
||||
.join(target_name)
|
||||
.join("release")
|
||||
.join(program_name),
|
||||
)),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
Ok(elf)
|
||||
}
|
||||
|
||||
@@ -36,32 +36,28 @@ pub enum CompileError {
|
||||
program_dir: PathBuf,
|
||||
manifest_path: PathBuf,
|
||||
},
|
||||
#[error("Failed to create temporary output directory: {0}")]
|
||||
TempDir(#[from] std::io::Error),
|
||||
#[error("Could not find `[package].name` in guest Cargo.toml at {path}")]
|
||||
MissingPackageName { path: PathBuf },
|
||||
#[error("Compiled ELF not found at expected path: {0}")]
|
||||
ElfNotFound(PathBuf),
|
||||
#[error("`cargo prove build` failed with status: {status} for program at {path}")]
|
||||
CargoBuildFailed { status: ExitStatus, path: PathBuf },
|
||||
#[error("Failed to read file at {path}: {source}")]
|
||||
ReadFile {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("Failed to parse guest Cargo.toml at {path}: {source}")]
|
||||
ParseCargoToml {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: toml::de::Error,
|
||||
},
|
||||
#[error("Failed to execute `cargo prove build` in {cwd}: {source}")]
|
||||
CargoProveBuild {
|
||||
cwd: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("Failed to create temporary output directory: {0}")]
|
||||
TempDir(#[from] std::io::Error),
|
||||
#[error("`cargo prove build` failed with status: {status} for program at {path}")]
|
||||
CargoProveBuildFailed { status: ExitStatus, path: PathBuf },
|
||||
#[error("Compiled ELF not found at expected path: {0}")]
|
||||
ElfNotFound(PathBuf),
|
||||
#[error("Failed to read file at {path}: {source}")]
|
||||
ReadFile {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error(transparent)]
|
||||
CompileUtilError(#[from] compile_utils::CompileError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
||||
Reference in New Issue
Block a user