1use std::{env, path::{PathBuf, Path}, process};
19
20fn get_manifest_dir() -> PathBuf {
22 env::var("CARGO_MANIFEST_DIR")
23 .expect("`CARGO_MANIFEST_DIR` is always set for `build.rs` files; qed")
24 .into()
25}
26
27pub struct WasmBuilderSelectProject {
29 _ignore: (),
32}
33
34impl WasmBuilderSelectProject {
35 pub fn with_current_project(self) -> WasmBuilder {
42 WasmBuilder {
43 rust_flags: Vec::new(),
44 file_name: None,
45 project_cargo_toml: get_manifest_dir().join("Cargo.toml"),
46 }
47 }
48
49 pub fn with_project(
53 self,
54 path: impl Into<PathBuf>,
55 ) -> Result<WasmBuilder, &'static str> {
56 let path = path.into();
57
58 if path.ends_with("Cargo.toml") && path.exists() {
59 Ok(WasmBuilder {
60 rust_flags: Vec::new(),
61 file_name: None,
62 project_cargo_toml: path,
63 })
64 } else {
65 Err("Project path must point to the `Cargo.toml` of the project")
66 }
67 }
68}
69
70pub struct WasmBuilder {
82 rust_flags: Vec<String>,
84 file_name: Option<String>,
88 project_cargo_toml: PathBuf,
91}
92
93impl WasmBuilder {
94 pub fn new() -> WasmBuilderSelectProject {
96 WasmBuilderSelectProject {
97 _ignore: (),
98 }
99 }
100
101 pub fn export_heap_base(mut self) -> Self {
105 self.rust_flags.push("-Clink-arg=--export=__heap_base".into());
106 self
107 }
108
109 pub fn set_file_name(mut self, file_name: impl Into<String>) -> Self {
115 self.file_name = Some(file_name.into());
116 self
117 }
118
119 pub fn import_memory(mut self) -> Self {
123 self.rust_flags.push("-C link-arg=--import-memory".into());
124 self
125 }
126
127 pub fn append_to_rust_flags(mut self, flag: impl Into<String>) -> Self {
131 self.rust_flags.push(flag.into());
132 self
133 }
134
135 pub fn build(self) {
137 let out_dir = PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` is set by cargo!"));
138 let file_path = out_dir.join(self.file_name.unwrap_or_else(|| "wasm_binary.rs".into()));
139
140 if check_skip_build() {
141 generate_rerun_if_changed_instructions();
144
145 provide_dummy_wasm_binary_if_not_exist(&file_path);
146
147 return;
148 }
149
150 build_project(
151 file_path,
152 self.project_cargo_toml,
153 self.rust_flags.into_iter().map(|f| format!("{} ", f)).collect(),
154 );
155
156 generate_rerun_if_changed_instructions();
159 }
160}
161
162fn generate_crate_skip_build_env_name() -> String {
164 format!(
165 "SKIP_{}_WASM_BUILD",
166 env::var("CARGO_PKG_NAME").expect("Package name is set").to_uppercase().replace('-', "_"),
167 )
168}
169
170fn check_skip_build() -> bool {
172 env::var(crate::SKIP_BUILD_ENV).is_ok() || env::var(generate_crate_skip_build_env_name()).is_ok()
173}
174
175fn provide_dummy_wasm_binary_if_not_exist(file_path: &Path) {
177 if !file_path.exists() {
178 crate::write_file_if_changed(
179 file_path,
180 "pub const WASM_BINARY: Option<&[u8]> = None;\
181 pub const WASM_BINARY_BLOATY: Option<&[u8]> = None;",
182 );
183 }
184}
185
186fn generate_rerun_if_changed_instructions() {
189 println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV);
191 println!("cargo:rerun-if-env-changed={}", crate::FORCE_WASM_BUILD_ENV);
192 println!("cargo:rerun-if-env-changed={}", generate_crate_skip_build_env_name());
193}
194
195fn build_project(
204 file_name: PathBuf,
205 project_cargo_toml: PathBuf,
206 default_rustflags: String,
207) {
208 let cargo_cmd = match crate::prerequisites::check() {
209 Ok(cmd) => cmd,
210 Err(err_msg) => {
211 eprintln!("{}", err_msg);
212 process::exit(1);
213 },
214 };
215
216 let (wasm_binary, bloaty) = crate::wasm_project::create_and_compile(
217 &project_cargo_toml,
218 &default_rustflags,
219 cargo_cmd,
220 );
221
222 let (wasm_binary, wasm_binary_bloaty) = if let Some(wasm_binary) = wasm_binary {
223 (
224 wasm_binary.wasm_binary_path_escaped(),
225 bloaty.wasm_binary_bloaty_path_escaped(),
226 )
227 } else {
228 (
229 bloaty.wasm_binary_bloaty_path_escaped(),
230 bloaty.wasm_binary_bloaty_path_escaped(),
231 )
232 };
233
234 crate::write_file_if_changed(
235 file_name,
236 format!(
237 r#"
238 pub const WASM_BINARY: Option<&[u8]> = Some(include_bytes!("{wasm_binary}"));
239 pub const WASM_BINARY_BLOATY: Option<&[u8]> = Some(include_bytes!("{wasm_binary_bloaty}"));
240 "#,
241 wasm_binary = wasm_binary,
242 wasm_binary_bloaty = wasm_binary_bloaty,
243 ),
244 );
245}