Skip to main content

build_javm/
lib.rs

1use std::path::PathBuf;
2
3use build_crate::{BuildKind, GuestBuild};
4use ssz::Encode;
5
6/// PVM2 target spec: RV64EMC + Zbb/Zba/Zbs/Zicond/Zicclsm. Used by [`build`].
7const TARGET_JSON: &str = include_str!("riscv64emc-pvm2.json");
8const TARGET_NAME: &str = "riscv64emc-pvm2";
9
10/// Emit `cargo:rerun-if-changed` for transpiler + javm sources so the blob
11/// is rebuilt when the transpiler or PVM format changes.
12fn watch_transpiler_sources() {
13    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
14    let crates_dir = PathBuf::from(&manifest_dir)
15        .parent()
16        .expect("build-javm must be inside crates/")
17        .to_path_buf();
18
19    build_crate::emit_rerun_for_dir(&crates_dir.join("javm-transpiler/src"));
20}
21
22/// Build a PVM2 blob from a service crate. The guest is built for the
23/// RV64EMC + Zbb/Zba/Zbs/Zicond/Zicclsm target and the ELF is linked via
24/// [`javm_transpiler::linker::link_elf`] — `Image::code` holds raw
25/// RV+C+custom-0 bytes consumed directly by the recompiler / interpreter.
26pub fn build(manifest_dir: &str, bin_name: &str) -> PathBuf {
27    watch_transpiler_sources();
28    let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
29    let blob_path = PathBuf::from(&out_dir).join(format!("{bin_name}.pvm"));
30
31    if std::env::var("SKIP_GUEST_BUILD").is_ok() {
32        if !blob_path.exists() {
33            std::fs::write(&blob_path, b"").ok();
34        }
35        return blob_path;
36    }
37
38    let resolved = build_crate::resolve_manifest_dir(manifest_dir);
39    let target_json_path = build_crate::write_target_json("riscv64emc-pvm2.json", TARGET_JSON);
40
41    let extra_rustflags = vec!["-Cllvm-args=--inline-threshold=265".to_string()];
42    let guest = GuestBuild {
43        manifest_dir: resolved,
44        target_json_path,
45        target_dir_name: TARGET_NAME.to_string(),
46        build_kind: BuildKind::Bin(bin_name.to_string()),
47        extra_rustflags,
48        extra_rustc_args: vec![],
49        env_overrides: vec![
50            (
51                "CARGO_PROFILE_RELEASE_OPT_LEVEL".to_string(),
52                "3".to_string(),
53            ),
54            ("CARGO_PROFILE_RELEASE_LTO".to_string(), "true".to_string()),
55            (
56                "CARGO_PROFILE_RELEASE_CODEGEN_UNITS".to_string(),
57                "1".to_string(),
58            ),
59        ],
60        rustc_bootstrap: true,
61    };
62
63    let elf_path = guest.build();
64    let elf_data = std::fs::read(&elf_path).expect("failed to read ELF");
65    let image = javm_transpiler::linker::link_elf(&elf_data).expect("failed to link ELF to Image");
66    let encoded = image.as_ssz_bytes();
67
68    std::fs::write(&blob_path, &encoded).expect("failed to write Image blob");
69    blob_path
70}