sp1_cli/commands/
build_toolchain.rs1use anyhow::{Context, Result};
2use clap::Parser;
3use std::{
4 path::PathBuf,
5 process::{Command, Stdio},
6};
7
8use crate::{get_target, LATEST_SUPPORTED_TOOLCHAIN_VERSION_TAG, RUSTUP_TOOLCHAIN_NAME};
9
10trait CommandExecutor {
13 fn run(&mut self) -> Result<()>;
14}
15
16impl CommandExecutor for Command {
17 fn run(&mut self) -> Result<()> {
18 self.stderr(Stdio::inherit())
19 .stdout(Stdio::inherit())
20 .stdin(Stdio::inherit())
21 .output()
22 .with_context(|| format!("while executing `{:?}`", self))
23 .map(|_| ())
24 }
25}
26
27#[derive(Parser)]
28#[command(name = "build-toolchain", about = "Build the cargo-prove toolchain.")]
29pub struct BuildToolchainCmd {}
30
31impl BuildToolchainCmd {
32 pub fn run(&self) -> Result<()> {
33 let github_access_token = std::env::var("GITHUB_ACCESS_TOKEN");
35 let build_dir = std::env::var("SP1_BUILD_DIR");
36
37 let rust_dir = match build_dir {
39 Ok(build_dir) => {
40 println!("Detected SP1_BUILD_DIR, skipping cloning rust.");
41 PathBuf::from(build_dir).join("rust")
42 }
43 Err(_) => {
44 let temp_dir = std::env::temp_dir();
45 let dir = temp_dir.join("sp1-rust");
46 if dir.exists() {
47 std::fs::remove_dir_all(&dir)?;
48 }
49
50 println!("No SP1_BUILD_DIR detected, cloning rust.");
51 let repo_url = match github_access_token {
52 Ok(github_access_token) => {
53 println!("Detected GITHUB_ACCESS_TOKEN, using it to clone rust.");
54 format!("https://{github_access_token}@github.com/succinctlabs/rust")
55 }
56 Err(_) => {
57 println!("No GITHUB_ACCESS_TOKEN detected. If you get throttled by Github, set it to bypass the rate limit.");
58 "ssh://git@github.com/succinctlabs/rust".to_string()
59 }
60 };
61 Command::new("git")
62 .args([
63 "clone",
64 &repo_url,
65 "--depth=1",
66 "--single-branch",
67 &format!("--branch={LATEST_SUPPORTED_TOOLCHAIN_VERSION_TAG}"),
68 "sp1-rust",
69 ])
70 .current_dir(&temp_dir)
71 .run()?;
72 Command::new("git").args(["reset", "--hard"]).current_dir(&dir).run()?;
73 Command::new("git")
74 .args(["submodule", "update", "--init", "--recursive", "--progress"])
75 .current_dir(&dir)
76 .run()?;
77 dir
78 }
79 };
80
81 let bootstrap_toml = include_str!("bootstrap.toml");
83 let bootstrap_file = rust_dir.join("bootstrap.toml");
84 std::fs::write(&bootstrap_file, bootstrap_toml)
85 .with_context(|| format!("while writing configuration to {bootstrap_file:?}"))?;
86
87 let temp_dir = std::env::temp_dir().join("rustc-targets");
90 if !temp_dir.exists() {
91 std::fs::create_dir_all(&temp_dir)?;
92 }
93 std::fs::File::create(temp_dir.join("riscv32im-succinct-zkvm-elf.json"))?;
94
95 Command::new("python3")
97 .env("RUST_TARGET_PATH", &temp_dir)
98 .env("CARGO_TARGET_RISCV32IM_SUCCINCT_ZKVM_ELF_RUSTFLAGS", "-Cpasses=lower-atomic")
99 .env("CARGO_TARGET_RISCV64IM_SUCCINCT_ZKVM_ELF_RUSTFLAGS", "-Cpasses=lower-atomic")
100 .args([
101 "x.py",
102 "build",
103 "--stage",
104 "2",
105 "compiler/rustc",
106 "library",
107 "--target",
108 &format!(
109 "riscv32im-succinct-zkvm-elf,riscv64im-succinct-zkvm-elf,{}",
110 get_target()
111 ),
112 ])
113 .current_dir(&rust_dir)
114 .run()?;
115
116 match Command::new("rustup").args(["toolchain", "remove", RUSTUP_TOOLCHAIN_NAME]).run() {
118 Ok(_) => println!("Successfully removed existing toolchain."),
119 Err(_) => println!("No existing toolchain to remove."),
120 }
121
122 let mut toolchain_dir = None;
124 for wentry in std::fs::read_dir(rust_dir.join("build"))? {
125 let entry = wentry?;
126 let toolchain_dir_candidate = entry.path().join("stage2");
127 if toolchain_dir_candidate.is_dir() {
128 toolchain_dir = Some(toolchain_dir_candidate);
129 break;
130 }
131 }
132 let toolchain_dir = toolchain_dir.unwrap();
133 println!(
134 "Found built toolchain directory at {}.",
135 toolchain_dir.as_path().to_str().unwrap()
136 );
137
138 Command::new("rustup")
140 .args(["toolchain", "link", RUSTUP_TOOLCHAIN_NAME])
141 .arg(&toolchain_dir)
142 .run()?;
143 println!("Successfully linked the toolchain to rustup.");
144
145 let target = get_target();
147 let tar_gz_path = format!("rust-toolchain-{target}.tar.gz");
148 Command::new("tar")
149 .args([
150 "--exclude",
151 "lib/rustlib/src",
152 "--exclude",
153 "lib/rustlib/rustc-src",
154 "-hczvf",
155 &tar_gz_path,
156 "-C",
157 toolchain_dir.to_str().unwrap(),
158 ".",
159 ])
160 .run()?;
161 println!("Successfully compressed the toolchain to {tar_gz_path}.");
162
163 Ok(())
164 }
165}