sp1_build/lib.rs
1mod build;
2mod command;
3mod utils;
4
5use std::env;
6
7use build::build_program_internal;
8pub use build::{execute_build_program, generate_elf_paths};
9pub use command::TOOLCHAIN_NAME;
10
11pub use sp1_primitives::types::Elf;
12
13use clap::{Parser, ValueEnum};
14
15const DEFAULT_DOCKER_TAG: &str = concat!("v", env!("CARGO_PKG_VERSION"));
16pub const DEFAULT_TARGET: &str = "riscv64im-succinct-zkvm-elf";
17const HELPER_TARGET_SUBDIR: &str = "elf-compilation";
18
19/// Controls the warning message verbosity in the build process.
20#[derive(Clone, Copy, ValueEnum, Debug, Default)]
21pub enum WarningLevel {
22 /// Show all warning messages (default).
23 #[default]
24 All,
25 /// Suppress non-essential warnings; show only critical stuff.
26 Minimal,
27}
28
29/// Compile an SP1 program.
30///
31/// Additional arguments are useful for configuring the build process, including options for using
32/// Docker, specifying binary and ELF names, ignoring Rust version checks, and enabling specific
33/// features.
34#[derive(Clone, Parser, Debug)]
35pub struct BuildArgs {
36 #[arg(
37 long,
38 action,
39 help = "Run compilation using a Docker container for reproducible builds."
40 )]
41 pub docker: bool,
42 #[arg(
43 long,
44 help = "The ghcr.io/succinctlabs/sp1 image tag to use when building with Docker.",
45 default_value = DEFAULT_DOCKER_TAG
46 )]
47 pub tag: String,
48 #[arg(
49 long,
50 action,
51 value_delimiter = ',',
52 help = "Space or comma separated list of features to activate"
53 )]
54 pub features: Vec<String>,
55 #[arg(
56 long,
57 action,
58 value_delimiter = ',',
59 help = "Space or comma separated list of extra flags to invokes `rustc` with"
60 )]
61 pub rustflags: Vec<String>,
62 #[arg(long, action, help = "Do not activate the `default` feature")]
63 pub no_default_features: bool,
64 #[arg(long, action, help = "Ignore `rust-version` specification in packages")]
65 pub ignore_rust_version: bool,
66 #[arg(long, action, help = "Assert that `Cargo.lock` will remain unchanged")]
67 pub locked: bool,
68 #[arg(
69 short,
70 long,
71 action,
72 help = "Build only the specified packages",
73 num_args = 1..
74 )]
75 pub packages: Vec<String>,
76 #[arg(
77 alias = "bin",
78 long,
79 action,
80 help = "Build only the specified binaries",
81 num_args = 1..
82 )]
83 pub binaries: Vec<String>,
84 #[arg(long, action, requires = "output_directory", help = "ELF binary name")]
85 pub elf_name: Option<String>,
86 #[arg(alias = "out-dir", long, action, help = "Copy the compiled ELF to this directory")]
87 pub output_directory: Option<String>,
88
89 #[arg(
90 alias = "workspace-dir",
91 long,
92 action,
93 help = "The top level directory to be used in the docker invocation."
94 )]
95 pub workspace_directory: Option<String>,
96
97 #[arg(long, value_enum, default_value = "all", help = "Control warning message verbosity")]
98 pub warning_level: WarningLevel,
99
100 #[arg(
101 long,
102 action,
103 help = "Disable Docker volume caching for cargo registry and git dependencies."
104 )]
105 pub no_docker_cache: bool,
106}
107
108// Implement default args to match clap defaults.
109impl Default for BuildArgs {
110 #[allow(clippy::uninlined_format_args)]
111 fn default() -> Self {
112 Self {
113 docker: false,
114 tag: DEFAULT_DOCKER_TAG.to_string(),
115 features: vec![],
116 rustflags: vec![],
117 ignore_rust_version: false,
118 packages: vec![],
119 binaries: vec![],
120 elf_name: None,
121 output_directory: None,
122 locked: false,
123 no_default_features: false,
124 workspace_directory: None,
125 warning_level: WarningLevel::All,
126 no_docker_cache: false,
127 }
128 }
129}
130
131/// Builds the program if the program at the specified path, or one of its dependencies, changes.
132///
133/// This function monitors the program and its dependencies for changes. If any changes are
134/// detected, it triggers a rebuild of the program.
135///
136/// # Arguments
137///
138/// * `path` - A string slice that holds the path to the program directory.
139///
140/// This function is useful for automatically rebuilding the program during development
141/// when changes are made to the source code or its dependencies.
142///
143/// Set the `SP1_SKIP_PROGRAM_BUILD` environment variable to `true` to skip building the program.
144pub fn build_program(path: &str) {
145 build_program_internal(path, None)
146}
147
148/// Builds the program with the given arguments if the program at path, or one of its dependencies,
149/// changes.
150///
151/// # Arguments
152///
153/// * `path` - A string slice that holds the path to the program directory.
154/// * `args` - A [`BuildArgs`] struct that contains various build configuration options.
155///
156/// Set the `SP1_SKIP_PROGRAM_BUILD` environment variable to `true` to skip building the program.
157pub fn build_program_with_args(path: &str, args: BuildArgs) {
158 build_program_internal(path, Some(args))
159}
160
161// /// Returns the verification key for the provided program.
162// ///
163// /// # Arguments
164// ///
165// /// * `path` - A string slice that holds the path to the program directory.
166// /// * `target_name` - A string slice that holds the binary target.
167// ///
168// /// Note: If used in a script `build.rs`, this function should be called *after*
169// [`build_program`] /// to returns the vkey corresponding to the latest program version which has
170// just been compiled. pub async fn vkey(path: &str, target_name: &str) -> String {
171// let program_dir = std::path::Path::new(path);
172// let metadata_file = program_dir.join("Cargo.toml");
173// let mut metadata_cmd = cargo_metadata::MetadataCommand::new();
174// let metadata = metadata_cmd.manifest_path(metadata_file).exec().unwrap();
175// let target_elf_paths =
176// generate_elf_paths(&metadata, None).expect("failed to collect target ELF paths");
177// let (_, path) =
178// target_elf_paths.iter().find(|(t, _)| t == target_name).expect("failed to find the
179// target"); let prover = Local
180// let mut file = File::open(path).unwrap();
181// let mut elf = Vec::new();
182
183// file.read_to_end(&mut elf).unwrap();
184// let (_, _, vk) = prover.core().setup(&elf).await;
185// vk.bytes32()
186// }
187
188// /// Returns the verification keys for the provided programs in a [`HashMap`] with the target
189// names /// as keys and vkeys as values.
190// ///
191// /// # Arguments
192// ///
193// /// * `path` - A string slice that holds the path to the program directory.
194// /// * `args` - A [`BuildArgs`] struct that contains various build configuration options.
195// ///
196// /// Note: If used in a script `build.rs`, this function should be called *after*
197// [`build_program`] /// to returns the vkey corresponding to the latest program version which has
198// just been compiled. pub fn vkeys(path: &str, args: BuildArgs) -> HashMap<String, String> {
199// let program_dir = std::path::Path::new(path);
200// let metadata_file = program_dir.join("Cargo.toml");
201// let mut metadata_cmd = cargo_metadata::MetadataCommand::new();
202// let metadata = metadata_cmd.manifest_path(metadata_file).exec().unwrap();
203// let target_elf_paths =
204// generate_elf_paths(&metadata, Some(&args)).expect("failed to collect target ELF paths");
205// let prover = SP1Prover::<CpuProverComponents>::new();
206
207// target_elf_paths
208// .into_iter()
209// .map(|(target_name, elf_path)| {
210// let mut file = File::open(elf_path).unwrap();
211// let mut elf = Vec::new();
212// file.read_to_end(&mut elf).unwrap();
213
214// let (_, _, _, vk) = prover.setup(&elf);
215// let vk = vk.bytes32();
216
217// (target_name, vk)
218// })
219// .collect()
220// }
221
222/// Returns the raw ELF bytes by the zkVM program target name.
223///
224/// Note that this only works when using `sp1_build::build_program` or
225/// `sp1_build::build_program_with_args` in a build script.
226///
227/// By default, the program target name is the same as the program crate name. However, this might
228/// not be the case for non-standard project structures. For example, placing the entrypoint source
229/// file at `src/bin/my_entry.rs` would result in the program target being named `my_entry`, in
230/// which case the invocation should be `include_elf!("my_entry")` instead.
231#[macro_export]
232macro_rules! include_elf {
233 ($arg:tt) => {{
234 // TODO: --all-features forces this branch. feature flags may not be the right solution here
235 $crate::Elf::Static(include_bytes!(env!(concat!("SP1_ELF_", $arg))))
236 }};
237}