Files
2026-07-13 12:25:07 +08:00

140 lines
5.5 KiB
Rust

// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
use std::path::Path;
use std::process::{Command, exit};
use clap::*;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct BundleArgs {
/// Artifact name
artifact: String,
/// Compile in release mode?
#[arg(short, long)]
release: bool,
/// Extra features to build with
#[arg(long)]
features: Option<String>,
}
use wasm_bindgen_cli_support::{Bindgen, EncodeInto};
use wasm_opt::{Feature, OptimizationOptions};
/// Run the packages `build` task with the appropriate flags. These can't be
/// defined in the `/.cargo/config.toml` because they would define this build
/// script's parameters also, and there is no way to reset e.g. the `target`
/// field to the host platform.
fn build(pkg: Option<&str>, is_release: bool, features: Vec<String>) {
let features = format!("tracing/release_max_level_warn,{}", features.join(","));
// Build RUSTFLAGS including target-specific flags from config.toml and new
// panic flags These are the flags from .cargo/config.toml for
// wasm32-unknown-unknown target
let target_flags = [
"--cfg=getrandom_backend=\"wasm_js\"",
"--cfg=web_sys_unstable_apis",
"-Ctarget-feature=+bulk-memory,+simd128,+relaxed-simd,+reference-types",
];
let rustflags = target_flags.join(" ");
let mut cmd = Command::new("cargo");
cmd.env("RUSTFLAGS", rustflags)
.args(["build"])
.args(["--lib"])
.args(["--features", &features])
.args(["--target", "wasm32-unknown-unknown"])
.args(["-Z", "build-std=std,panic_abort"]);
if is_release {
cmd.args(["--release"]);
}
if let Some(pkg) = pkg {
cmd.args(["-p", pkg]);
}
cmd.execute()
}
/// Generate the `wasm-bindgen` JavaScript and WASM bindings.
fn bindgen(outdir: &Path, artifact: &str, is_release: bool) {
let input = Path::new("../target/wasm32-unknown-unknown")
.join(if is_release { "release" } else { "debug" })
.join(format!("{artifact}.wasm"));
Bindgen::new()
.web(true)
.unwrap()
.keep_debug(!is_release)
.input_path(input)
.encode_into(EncodeInto::Always)
.typescript(true)
// .reference_types(true)
.out_name(&format!("{}.wasm", artifact.replace('_', "-")))
.generate(outdir)
.unwrap();
}
/// Run `wasm-opt` and output the new binary on top of the old one.
fn opt(outpath: &Path, is_release: bool) {
if is_release {
OptimizationOptions::new_optimize_for_size_aggressively()
.enable_feature(Feature::BulkMemory)
.enable_feature(Feature::ReferenceTypes)
.enable_feature(Feature::Simd)
.enable_feature(Feature::RelaxedSimd)
.enable_feature(Feature::TruncSat)
.run(outpath, outpath)
.unwrap();
}
}
fn main() {
let args = BundleArgs::parse();
let outdir = Path::new("dist/wasm");
let is_release = args.release;
let package = args.artifact.clone().replace('_', "-");
let outpath = &Path::new(outdir).join(format!(
"{}.wasm",
args.artifact.replace("-js", "").replace('_', "-")
));
let features = args
.features
.unwrap_or_default()
.split(',')
.map(|x| x.to_string())
.collect();
build(Some(package.as_str()), is_release, features);
bindgen(outdir, args.artifact.as_str(), is_release);
opt(outpath, is_release);
}
trait SimpleCommand {
fn execute(&mut self);
}
impl SimpleCommand for Command {
fn execute(&mut self) {
match self.status().ok().and_then(|x| x.code()) {
Some(0) => (),
Some(x) => exit(x),
None => exit(1),
}
}
}