diff --git a/.gitignore b/.gitignore index 7462033db..bfa49a9b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/target +target/ javy.wat javy.wasm index.js diff --git a/Makefile b/Makefile index e1dc4d9a8..87e833f08 100644 --- a/Makefile +++ b/Makefile @@ -2,19 +2,21 @@ .DEFAULT_GOAL := cli cli: core - cd crates/cli && cargo build --release + cd crates/cli && cargo build && cd - check-benchmarks: - cd crates/benchmarks \ - && cargo check --benches --release + cd crates/benchmarks \ + && cargo check --benches --release \ + && cd - core: cd crates/core \ - && cargo build --release --target=wasm32-wasi + && cargo build --release --target=wasm32-wasi \ + && cd - test-core: - cd crates/core \ - && cargo wasi test --features standalone-wasi -- --nocapture + cd crates/core \ + && cargo wasi test --features standalone-wasi -- --nocapture tests: check-benchmarks test-core @@ -24,13 +26,13 @@ fmt-quickjs-sys: cd crates/quickjs-sys/ \ && cargo fmt -- --check \ && cargo clippy -- -D warnings \ - && cd - \ + && cd - fmt-core: cd crates/core/ \ && cargo fmt -- --check \ && cargo clippy -- -D warnings \ - && cd - \ + && cd - fmt-cli: cd crates/cli/ \ diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index e7bb07c88..d499d3574 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -14,3 +14,7 @@ which = "4.2" structopt = "0.3" anyhow = "1.0" tempfile = "3.2.0" + +[build-dependencies] +which = "4.2" + diff --git a/crates/cli/build.rs b/crates/cli/build.rs index 85fd6a303..fa4a417d9 100644 --- a/crates/cli/build.rs +++ b/crates/cli/build.rs @@ -1,5 +1,9 @@ use std::env; -use std::path::PathBuf; +use std::fs; +use std::io; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::process::Command; fn main() { copy_prebuilt_binaries(); @@ -14,56 +18,20 @@ fn main() { // When using clippy, we need to write a stubbed engine.wasm file to ensure compilation succeeds. This // skips building the actual engine.wasm binary that would be injected into the CLI binary. fn stub_engine_for_clippy() { - let out_dir: PathBuf = env::var("OUT_DIR") - .expect("failed to retrieve out dir") - .into(); + let engine_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("engine.wasm"); - let engine_path = out_dir.join("engine.wasm"); if !engine_path.exists() { - std::fs::write(engine_path, "").expect("failed to write empty engine.wasm stub"); + std::fs::write(engine_path, &[]).expect("failed to write empty engine.wasm stub"); println!("cargo:warning=using stubbed engine.wasm for static analysis purposes..."); } } -fn copy_engine_binary() { - let profile = env::var("PROFILE").expect("Couldn't retrieve profile"); - if profile != "release" { - eprintln!("only --release is supported due to https://github.com/bytecodealliance/wizer/issues/27"); - std::process::exit(1); - } - - let out_dir: PathBuf = env::var("OUT_DIR") - .expect("failed to retrieve out dir") - .into(); - - let engine_path: PathBuf = std::env::var("CARGO_MANIFEST_DIR") - .map(PathBuf::from) - .ok() - .map(|mut b| { - b.pop(); - b.pop(); - b.join("target") - .join("wasm32-wasi") - .join(profile) - .join("javy_core.wasm") - }) - .expect("failed to create path"); - - println!("cargo:rerun-if-changed={:?}", engine_path); - - // Only copy the file when it exists. Cargo will take care of re-running this script when the file changes. - if engine_path.exists() { - std::fs::copy(&engine_path, out_dir.join("engine.wasm")) - .unwrap_or_else(|_| panic!("failed to copy engine from {:?}", engine_path)); - } -} - // Copy OS specific pre-built binaries to a known location. The binaries will be embedded in the final binary and // extracted to a temporary location if it's not already installed. fn copy_prebuilt_binaries() { - let target_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); - let target_os = PathBuf::from(std::env::var("CARGO_CFG_TARGET_OS").unwrap()); - let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); + let target_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let target_os = PathBuf::from(env::var("CARGO_CFG_TARGET_OS").unwrap()); + let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); let vendor_dir = root.join("vendor").join(target_os); let target_vendor_dir = target_dir.join("vendor"); @@ -79,3 +47,63 @@ fn copy_prebuilt_binaries() { } }); } + +// Copy the engine binary build from the `core` crate, and run wasm-strip + wasm-opt against it as suggested by https://github.com/bytecodealliance/wizer/issues/27. +fn copy_engine_binary() { + let mut engine_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + engine_path.pop(); + engine_path.pop(); + let engine_path = engine_path.join("target/wasm32-wasi/release/javy_core.wasm"); + + println!("cargo:rerun-if-changed={:?}", engine_path); + + if engine_path.exists() { + let copied_engine_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("engine.wasm"); + + fs::copy(&engine_path, &copied_engine_path).unwrap(); + optimize_engine(&copied_engine_path); + } +} + +fn optimize_engine(engine_path: impl AsRef) { + if env::var("JAVY_SKIP_ENGINE_OPTIMIZATIONS").is_ok() { + return; + } + + run_wasm_strip(&engine_path); + run_wasm_opt(&engine_path); +} + +fn run_wasm_strip(engine_path: impl AsRef) { + let wasm_strip = which::which("wasm-strip") + .unwrap_or_else(|_| PathBuf::from(env::var("OUT_DIR").unwrap()).join("vendor/wasm-opt")); + + let output = Command::new(wasm_strip) + .arg(engine_path.as_ref()) + .output() + .unwrap(); + + println!("wasm-strip status: {}", output.status); + io::stdout().write_all(&output.stdout).unwrap(); + io::stderr().write_all(&output.stderr).unwrap(); + assert!(output.status.success()); +} + +fn run_wasm_opt(engine_path: impl AsRef) { + let wasm_opt = which::which("wasm-opt") + .unwrap_or_else(|_| PathBuf::from(env::var("OUT_DIR").unwrap()).join("vendor/wasm-opt")); + + let output = Command::new(wasm_opt) + .arg(engine_path.as_ref()) + .arg("-O3") + .arg("--dce") + .arg("-o") + .arg(engine_path.as_ref()) + .output() + .unwrap(); + + println!("wasm-opt status: {}", output.status); + io::stdout().write_all(&output.stdout).unwrap(); + io::stderr().write_all(&output.stderr).unwrap(); + assert!(output.status.success()); +}