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 = "riscv32i-unknown-none-elf";
153
154 let profile = if self.debug { "debug" } else { "release" };
155
156 let envs = vec![("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.envs(envs).args([
173 "build",
174 "--package",
175 self.package.as_str(),
176 "--bin",
177 prog,
178 "--target-dir",
179 &dest,
180 "--target",
181 target,
182 "--profile",
183 profile,
184 ]);
185
186 let res = cmd.output()?;
187
188 if !res.status.success() {
189 io::stderr().write_all(&res.stderr)?;
190 return Err(BuildError::CompilerError);
191 }
192
193 let elf_path =
194 PathBuf::from_str(&format!("{}/{}/{}/{}", dest, target, profile, prog)).unwrap();
195
196 Ok(elf_path)
197 }
198}