Skip to main content

build_javm/
lib.rs

1use std::path::PathBuf;
2
3use build_crate::{BuildKind, GuestBuild};
4use ssz::Encode;
5
6const TARGET_JSON: &str = include_str!("riscv64em-javm.json");
7const TARGET_NAME: &str = "riscv64em-javm";
8
9/// Emit `cargo:rerun-if-changed` for transpiler + javm sources so the blob
10/// is rebuilt when the transpiler or PVM format changes.
11fn watch_transpiler_sources() {
12    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
13    let crates_dir = PathBuf::from(&manifest_dir)
14        .parent()
15        .expect("build-javm must be inside crates/")
16        .to_path_buf();
17
18    // Watch transpiler source (affects blob encoding)
19    build_crate::emit_rerun_for_dir(&crates_dir.join("javm-transpiler/src"));
20    // Watch javm program (affects blob format)
21    let javm_src = crates_dir.join("javm/src");
22    println!(
23        "cargo:rerun-if-changed={}",
24        javm_src.join("program.rs").display()
25    );
26}
27
28/// Build a PVM blob from a service crate (standard program, single entry point).
29pub fn build(manifest_dir: &str, bin_name: &str) -> PathBuf {
30    watch_transpiler_sources();
31    let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
32    let blob_path = PathBuf::from(&out_dir).join(format!("{bin_name}.pvm"));
33
34    if std::env::var("SKIP_GUEST_BUILD").is_ok() {
35        if !blob_path.exists() {
36            std::fs::write(&blob_path, b"").ok();
37        }
38        return blob_path;
39    }
40
41    let resolved = build_crate::resolve_manifest_dir(manifest_dir);
42    let target_json_path = build_crate::write_target_json("riscv64em-javm.json", TARGET_JSON);
43
44    let extra_rustflags = vec!["-Cllvm-args=--inline-threshold=275".to_string()];
45    let guest = GuestBuild {
46        manifest_dir: resolved,
47        target_json_path,
48        target_dir_name: TARGET_NAME.to_string(),
49        build_kind: BuildKind::Bin(bin_name.to_string()),
50        extra_rustflags,
51        extra_rustc_args: vec![],
52        env_overrides: vec![
53            (
54                "CARGO_PROFILE_RELEASE_OPT_LEVEL".to_string(),
55                "3".to_string(),
56            ),
57            ("CARGO_PROFILE_RELEASE_LTO".to_string(), "true".to_string()),
58            (
59                "CARGO_PROFILE_RELEASE_CODEGEN_UNITS".to_string(),
60                "1".to_string(),
61            ),
62        ],
63        rustc_bootstrap: true,
64    };
65
66    let elf_path = guest.build();
67    let elf_data = std::fs::read(&elf_path).expect("failed to read ELF");
68    let image =
69        javm_transpiler::link_elf(&elf_data).expect("failed to transpile ELF to Cap::Image");
70    let encoded = image.as_ssz_bytes();
71
72    std::fs::write(&blob_path, &encoded).expect("failed to write Image blob");
73    blob_path
74}
75
76/// Build a PVM service blob (single entrypoint, size-optimized profile).
77pub fn build_service(manifest_dir: &str, bin_name: &str) -> PathBuf {
78    watch_transpiler_sources();
79    let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
80    let blob_path = PathBuf::from(&out_dir).join(format!("{bin_name}.pvm"));
81
82    if std::env::var("SKIP_GUEST_BUILD").is_ok() {
83        if !blob_path.exists() {
84            std::fs::write(&blob_path, b"").ok();
85        }
86        return blob_path;
87    }
88
89    let resolved = build_crate::resolve_manifest_dir(manifest_dir);
90    let target_json_path = build_crate::write_target_json("riscv64em-javm.json", TARGET_JSON);
91
92    let extra_rustflags = vec!["-Cllvm-args=--inline-threshold=275".to_string()];
93    let guest = GuestBuild {
94        manifest_dir: resolved,
95        target_json_path,
96        target_dir_name: TARGET_NAME.to_string(),
97        build_kind: BuildKind::Bin(bin_name.to_string()),
98        extra_rustflags,
99        extra_rustc_args: vec![],
100        env_overrides: vec![
101            (
102                "CARGO_PROFILE_RELEASE_OPT_LEVEL".to_string(),
103                "s".to_string(),
104            ),
105            ("CARGO_PROFILE_RELEASE_LTO".to_string(), "false".to_string()),
106        ],
107        rustc_bootstrap: true,
108    };
109
110    let elf_path = guest.build();
111    let elf_data = std::fs::read(&elf_path).expect("failed to read ELF");
112    let image =
113        javm_transpiler::link_elf(&elf_data).expect("failed to transpile ELF to Cap::Image");
114    let encoded = image.as_ssz_bytes();
115
116    std::fs::write(&blob_path, &encoded).expect("failed to write Image blob");
117    blob_path
118}