1mod build;
2mod command;
3mod utils;
4use std::{collections::HashMap, fs::File, io::Read};
5
6use build::build_program_internal;
7pub use build::{execute_build_program, generate_elf_paths};
8pub use command::TOOLCHAIN_NAME;
9
10use clap::{Parser, ValueEnum};
11use sp1_prover::{components::CpuProverComponents, HashableKey, SP1Prover};
12
13const DEFAULT_DOCKER_TAG: &str = concat!("v", env!("CARGO_PKG_VERSION"));
14const BUILD_TARGET: &str = "riscv32im-succinct-zkvm-elf";
15const HELPER_TARGET_SUBDIR: &str = "elf-compilation";
16
17#[derive(Clone, Copy, ValueEnum, Debug, Default)]
19pub enum WarningLevel {
20 #[default]
22 All,
23 Minimal,
25}
26
27#[derive(Clone, Parser, Debug)]
33pub struct BuildArgs {
34 #[arg(
35 long,
36 action,
37 help = "Run compilation using a Docker container for reproducible builds."
38 )]
39 pub docker: bool,
40 #[arg(
41 long,
42 help = "The ghcr.io/succinctlabs/sp1 image tag to use when building with Docker.",
43 default_value = DEFAULT_DOCKER_TAG
44 )]
45 pub tag: String,
46 #[arg(
47 long,
48 action,
49 value_delimiter = ',',
50 help = "Space or comma separated list of features to activate"
51 )]
52 pub features: Vec<String>,
53 #[arg(
54 long,
55 action,
56 value_delimiter = ',',
57 help = "Space or comma separated list of extra flags to invokes `rustc` with"
58 )]
59 pub rustflags: Vec<String>,
60 #[arg(long, action, help = "Do not activate the `default` feature")]
61 pub no_default_features: bool,
62 #[arg(long, action, help = "Ignore `rust-version` specification in packages")]
63 pub ignore_rust_version: bool,
64 #[arg(long, action, help = "Assert that `Cargo.lock` will remain unchanged")]
65 pub locked: bool,
66 #[arg(
67 short,
68 long,
69 action,
70 help = "Build only the specified packages",
71 num_args = 1..
72 )]
73 pub packages: Vec<String>,
74 #[arg(
75 alias = "bin",
76 long,
77 action,
78 help = "Build only the specified binaries",
79 num_args = 1..
80 )]
81 pub binaries: Vec<String>,
82 #[arg(long, action, requires = "output_directory", help = "ELF binary name")]
83 pub elf_name: Option<String>,
84 #[arg(alias = "out-dir", long, action, help = "Copy the compiled ELF to this directory")]
85 pub output_directory: Option<String>,
86
87 #[arg(
88 alias = "workspace-dir",
89 long,
90 action,
91 help = "The top level directory to be used in the docker invocation."
92 )]
93 pub workspace_directory: Option<String>,
94
95 #[arg(long, value_enum, default_value = "all", help = "Control warning message verbosity")]
96 pub warning_level: WarningLevel,
97}
98
99impl Default for BuildArgs {
101 fn default() -> Self {
102 Self {
103 docker: false,
104 tag: DEFAULT_DOCKER_TAG.to_string(),
105 features: vec![],
106 rustflags: vec![],
107 ignore_rust_version: false,
108 packages: vec![],
109 binaries: vec![],
110 elf_name: None,
111 output_directory: None,
112 locked: false,
113 no_default_features: false,
114 workspace_directory: None,
115 warning_level: WarningLevel::All,
116 }
117 }
118}
119
120pub fn build_program(path: &str) {
134 build_program_internal(path, None)
135}
136
137pub fn build_program_with_args(path: &str, args: BuildArgs) {
147 build_program_internal(path, Some(args))
148}
149
150pub fn vkey(path: &str, target_name: &str) -> String {
160 let program_dir = std::path::Path::new(path);
161 let metadata_file = program_dir.join("Cargo.toml");
162 let mut metadata_cmd = cargo_metadata::MetadataCommand::new();
163 let metadata = metadata_cmd.manifest_path(metadata_file).exec().unwrap();
164 let target_elf_paths =
165 generate_elf_paths(&metadata, None).expect("failed to collect target ELF paths");
166 let (_, path) =
167 target_elf_paths.iter().find(|(t, _)| t == target_name).expect("failed to find the target");
168 let prover = SP1Prover::<CpuProverComponents>::new();
169 let mut file = File::open(path).unwrap();
170 let mut elf = Vec::new();
171
172 file.read_to_end(&mut elf).unwrap();
173 let (_, _, _, vk) = prover.setup(&elf);
174 vk.bytes32()
175}
176
177pub fn vkeys(path: &str, args: BuildArgs) -> HashMap<String, String> {
188 let program_dir = std::path::Path::new(path);
189 let metadata_file = program_dir.join("Cargo.toml");
190 let mut metadata_cmd = cargo_metadata::MetadataCommand::new();
191 let metadata = metadata_cmd.manifest_path(metadata_file).exec().unwrap();
192 let target_elf_paths =
193 generate_elf_paths(&metadata, Some(&args)).expect("failed to collect target ELF paths");
194 let prover = SP1Prover::<CpuProverComponents>::new();
195
196 target_elf_paths
197 .into_iter()
198 .map(|(target_name, elf_path)| {
199 let mut file = File::open(elf_path).unwrap();
200 let mut elf = Vec::new();
201 file.read_to_end(&mut elf).unwrap();
202
203 let (_, _, _, vk) = prover.setup(&elf);
204 let vk = vk.bytes32();
205
206 (target_name, vk)
207 })
208 .collect()
209}
210
211#[macro_export]
221macro_rules! include_elf {
222 ($arg:tt) => {{
223 include_bytes!(env!(concat!("SP1_ELF_", $arg)))
224 }};
225}