ab_contracts_tooling/
build.rs1use anyhow::Context;
4use cargo_metadata::MetadataCommand;
5use std::env;
6use std::path::{Path, PathBuf};
7use std::process::Command;
8use tracing::debug;
9
10#[derive(Debug)]
12pub struct BuildOptions<'a> {
13 pub package: Option<&'a str>,
17 pub features: Option<&'a str>,
19 pub profile: &'a str,
21 pub target_specification_path: &'a Path,
23 pub target_dir: Option<&'a Path>,
25}
26
27pub fn build_cdylib(options: BuildOptions<'_>) -> anyhow::Result<PathBuf> {
29 let BuildOptions {
30 package,
31 features,
32 profile,
33 target_specification_path,
34 target_dir,
35 } = options;
36
37 let mut command_builder = Command::new("cargo");
38 command_builder
39 .env_remove("RUSTFLAGS")
40 .env_remove("CARGO_ENCODED_RUSTFLAGS")
41 .args([
42 "rustc",
43 "-Z",
44 "build-std=core",
45 "--crate-type",
46 "cdylib",
47 "--target",
48 target_specification_path
49 .to_str()
50 .context("Path to target specification file is not valid UTF-8")?,
51 ]);
52
53 if env::var("MIRI_SYSROOT").is_ok() {
54 command_builder
55 .env_remove("RUSTC")
56 .env_remove("RUSTC_WRAPPER");
57 }
58
59 if let Some(package) = package {
60 command_builder.args([
61 "--package",
62 package,
63 "--features",
64 &format!("{package}/guest"),
65 ]);
66 } else {
67 command_builder.args(["--features", "guest"]);
68 }
69 if let Some(features) = features {
70 command_builder.args(["--features", features]);
71 }
72
73 command_builder.args(["--profile", profile]);
74
75 let metadata = MetadataCommand::new()
76 .exec()
77 .context("Failed to fetch cargo metadata")?;
78
79 let target_directory = if let Some(target_dir) = target_dir {
80 command_builder.args([
81 "--target-dir",
82 target_dir
83 .to_str()
84 .context("Path to target directory is not valid UTF-8")?,
85 ]);
86 target_dir
87 } else {
88 metadata.target_directory.as_std_path()
89 };
90
91 let cdylib_path = target_directory
92 .join("riscv64em-unknown-none-abundance")
93 .join(profile)
94 .join({
95 let package_name = if let Some(package) = package {
96 package
97 } else {
98 let current_dir = env::current_dir().context("Failed to get current directory")?;
99 let current_manifest = current_dir.join("Cargo.toml");
100 metadata
101 .packages
102 .iter()
103 .find_map(|package| {
104 if package.manifest_path == current_manifest {
105 Some(&package.name)
106 } else {
107 None
108 }
109 })
110 .context("Failed to find package name")?
111 };
112
113 format!("{}.contract.so", package_name.replace('-', "_"))
114 });
115
116 debug!(
117 ?package,
118 ?features,
119 ?profile,
120 ?target_specification_path,
121 cdylib_path = ?cdylib_path,
122 command = ?command_builder,
123 "Building ELF `cdylib` contract"
124 );
125
126 let status = command_builder
127 .status()
128 .context("Failed to build a contract")?;
129
130 if !status.success() {
131 return Err(anyhow::anyhow!("Failed to build a contract"));
132 }
133
134 Ok(cdylib_path)
135}