nexus_sdk/legacy/
compile.rs1use std::fmt::Display;
2use std::fs;
3use std::io;
4use std::io::Write;
5use std::path::PathBuf;
6use std::process::Command;
7use std::str::FromStr;
8use uuid::Uuid;
9
10pub use crate::error::BuildError;
11
12#[doc(hidden)]
13#[derive(Default)]
14pub enum ForProver {
15 #[default]
16 Default,
17 Jolt,
18}
19
20impl Display for ForProver {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 match self {
23 Self::Default => write!(f, "default"),
24 Self::Jolt => write!(f, "jolt"),
25 }
26 }
27}
28
29#[derive(Clone)]
33pub struct CompileOpts {
34 pub package: String,
36 pub binary: String,
38 debug: bool,
39 unique: bool,
41 pub(crate) memlimit: Option<usize>, }
43
44impl CompileOpts {
45 pub fn new(package: &str) -> Self {
47 Self {
48 package: package.to_string(),
49 binary: package.to_string(),
50 debug: false,
51 unique: false,
53 memlimit: None,
54 }
55 }
56
57 pub fn new_with_custom_binary(package: &str, binary: &str) -> Self {
59 Self {
60 package: package.to_string(),
61 binary: binary.to_string(),
62 debug: false,
63 unique: false,
65 memlimit: None,
66 }
67 }
68
69 pub fn set_debug_build(&mut self, debug: bool) {
71 self.debug = debug;
72 }
73
74 pub fn set_unique_build(&mut self, unique: bool) {
86 self.unique = unique;
87 }
88
89 pub fn set_memlimit(&mut self, memlimit: usize) {
95 self.memlimit = Some(memlimit);
96 }
97
98 fn set_linker(&mut self, prover: &ForProver) -> Result<PathBuf, BuildError> {
99 let linker_script = match prover {
100 ForProver::Jolt => {
101 if self.memlimit.is_some() {
102 return Err(BuildError::InvalidMemoryConfiguration);
103 }
104
105 include_str!("./linker-scripts/jolt.x").into()
106 }
107 ForProver::Default => {
108 if self.memlimit.is_none() {
109 return Err(BuildError::InvalidMemoryConfiguration);
110 }
111
112 include_str!("./linker-scripts/default.x").replace(
113 "{MEMORY_LIMIT}",
114 &format!(
115 "0x{:X}",
116 &(self.memlimit.unwrap() as u32).saturating_mul(0x100000)
117 ),
118 )
119 }
120 };
121
122 let linker_path =
123 PathBuf::from_str(&format!("/tmp/nexus-guest-linkers/{}.ld", prover)).unwrap();
124
125 if let Some(parent) = linker_path.parent() {
126 fs::create_dir_all(parent)?;
127 }
128
129 let mut file = fs::File::create(linker_path.clone())?;
130 file.write_all(linker_script.as_bytes())?;
131
132 Ok(linker_path)
133 }
134
135 pub(crate) fn build(&mut self, prover: &ForProver) -> Result<PathBuf, BuildError> {
136 let linker_path = self.set_linker(prover)?;
137
138 let rust_flags = [
139 "-C",
140 &format!("link-arg=-T{}", linker_path.display()),
141 "-C",
142 "panic=abort",
143 ];
144
145 let target = "riscv32im-unknown-none-elf";
153
154 let profile = if self.debug { "debug" } else { "release" };
155
156 let cargo_encoded_rustflags = rust_flags.join("\x1f");
157 let prog = self.binary.as_str();
158
159 let mut dest = match std::env::var_os("OUT_DIR") {
160 Some(path) => path.into_string().unwrap(),
161 None => "/tmp/nexus-target".into(),
162 };
163
164 if self.unique {
165 let uuid = Uuid::new_v4();
166 dest = format!("{}-{}", dest, uuid);
167 }
168
169 let cargo_bin = std::env::var("CARGO").unwrap_or_else(|_err| "cargo".into());
170 let mut cmd = Command::new(cargo_bin);
171
172 cmd.env("CARGO_ENCODED_RUSTFLAGS", cargo_encoded_rustflags)
173 .args([
174 "build",
175 "--package",
176 self.package.as_str(),
177 "--bin",
178 prog,
179 "--target-dir",
180 &dest,
181 "--target",
182 target,
183 "--profile",
184 profile,
185 ]);
186
187 let res = cmd.output()?;
188
189 if !res.status.success() {
190 io::stderr().write_all(&res.stderr)?;
191 return Err(BuildError::CompilerError);
192 }
193
194 let elf_path =
195 PathBuf::from_str(&format!("{}/{}/{}/{}", dest, target, profile, prog)).unwrap();
196
197 Ok(elf_path)
198 }
199}