nexus_sdk/compile/
cargo.rs

1use crypto_common::generic_array::typenum::{ToInt, U32};
2use std::io;
3use std::io::Write;
4use std::marker::PhantomData;
5use std::path::PathBuf;
6use std::process::Command;
7use std::str::FromStr;
8use uuid::Uuid;
9
10pub use crate::error::BuildError;
11
12use super::{Compile, Compiler, Packager};
13
14/// The Cargo guest program packager, used for Rust.
15pub enum CargoPackager {}
16impl Packager for CargoPackager {
17    type DigestSize = U32;
18
19    fn digest_len() -> usize {
20        let sz: u32 = Self::DigestSize::to_int();
21        sz as usize
22    }
23}
24
25impl Compile for Compiler<CargoPackager> {
26    /// Configure dynamic compilation.
27    fn new(package: &str) -> Self {
28        Self {
29            package: package.to_string(),
30            binary: package.to_string(),
31            debug: false,
32            native: false,
33            unique: false,
34            _packager: PhantomData,
35        }
36    }
37
38    /// Configure dynamic compilation, using non-default binary name.
39    fn new_with_custom_binary(package: &str, binary: &str) -> Self {
40        Self {
41            package: package.to_string(),
42            binary: binary.to_string(),
43            debug: false,
44            native: false,
45            unique: false,
46            _packager: PhantomData,
47        }
48    }
49
50    /// Set dynamic compilation to build the guest program in a debug profile.
51    fn set_debug_build(&mut self, debug: bool) {
52        self.debug = debug;
53    }
54
55    /// Set dynamic compilation to build for the native (host machine) target, rather than for the zkVM.
56    fn set_native_build(&mut self, native: bool) {
57        self.native = native;
58    }
59
60    /// Set dynamic compilation to run a unique build that neither overwrites prior builds nor will be overwritten by future builds. May be used to concurrently build different versions of the same binary.
61    ///
62    /// Note: the SDK does not automatically clean or otherwise manage the resultant builds in the output directory.
63    fn set_unique_build(&mut self, unique: bool) {
64        self.unique = unique;
65    }
66
67    /// Compile and build the guest binary.
68    fn build(&mut self) -> Result<PathBuf, BuildError> {
69        let linker_path = Compiler::set_linker()?;
70
71        let rust_flags = [
72            "-C",
73            "relocation-model=pic",
74            "-C",
75            &format!("link-arg=-T{}", linker_path.display()),
76            "-C",
77            "panic=abort",
78        ];
79
80        let target = if self.native {
81            "native"
82        } else {
83            "riscv32i-unknown-none-elf"
84        };
85
86        let profile = if self.debug { "debug" } else { "release" };
87
88        let envs = vec![("CARGO_ENCODED_RUSTFLAGS", rust_flags.join("\x1f"))];
89        let prog = self.binary.as_str();
90
91        let mut dest = match std::env::var_os("OUT_DIR") {
92            Some(path) => path.into_string().unwrap(),
93            None => "/tmp/nexus-target".into(),
94        };
95
96        if self.unique {
97            let uuid = Uuid::new_v4();
98            dest = format!("{}-{}", dest, uuid);
99        }
100
101        let cargo_bin = std::env::var("CARGO").unwrap_or_else(|_err| "cargo".into());
102        let mut cmd = Command::new(cargo_bin);
103
104        cmd.envs(envs).args([
105            "build",
106            "--package",
107            self.package.as_str(),
108            "--bin",
109            prog,
110            "--target-dir",
111            &dest,
112            "--target",
113            target,
114            "--profile",
115            profile,
116        ]);
117
118        let res = cmd.output()?;
119
120        if !res.status.success() {
121            io::stderr().write_all(&res.stderr)?;
122            return Err(BuildError::CompilerError);
123        }
124
125        let elf_path =
126            PathBuf::from_str(&format!("{}/{}/{}/{}", dest, target, profile, prog)).unwrap();
127
128        Ok(elf_path)
129    }
130}