Skip to main content

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}