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