From cbbe6a5f18c60ddf4fcf67db1813440223b82227 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 4 Sep 2022 17:05:50 -0600 Subject: [PATCH 1/6] Change wasm-opt installation suggestion to favor 'cargo install wasm-opt' --- crates/cargo-contract/src/wasm_opt.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/cargo-contract/src/wasm_opt.rs b/crates/cargo-contract/src/wasm_opt.rs index 6ea5a6c97..170782b33 100644 --- a/crates/cargo-contract/src/wasm_opt.rs +++ b/crates/cargo-contract/src/wasm_opt.rs @@ -36,13 +36,16 @@ use std::{ const WASM_OPT_INSTALLATION_SUGGESTION: &str = "wasm-opt not found! Make sure the binary is in your PATH environment.\n\n\ We use this tool to optimize the size of your contract's Wasm binary.\n\n\ - wasm-opt is part of the binaryen package. You can find detailed\n\ - installation instructions on https://github.com/WebAssembly/binaryen#tools.\n\n\ - There are ready-to-install packages for many platforms:\n\ + It can be installed with the command\n\n\ + cargo install wasm-opt --locked\n\n\ + Alternately, there are ready-to-install packages for many platforms:\n\ * Debian/Ubuntu: apt-get install binaryen\n\ * Homebrew: brew install binaryen\n\ * Arch Linux: pacman -S binaryen\n\ - * Windows: binary releases at https://github.com/WebAssembly/binaryen/releases"; + * Windows: binary releases at https://github.com/WebAssembly/binaryen/releases\n\n\" + wasm-opt is part of the binaryen toolset.\n\ + You can find detailed\n\ + installation instructions at https://github.com/WebAssembly/binaryen#tools."; /// A helpful struct for interacting with Binaryen's `wasm-opt` tool. pub struct WasmOptHandler { From dd4880842ea01c1ea58fda6636d741fa1f0e69b4 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 4 Sep 2022 17:45:00 -0600 Subject: [PATCH 2/6] Use integrated wasm-opt API --- Cargo.lock | 154 +++++++++++++++++++++++++- crates/cargo-contract/Cargo.toml | 4 +- crates/cargo-contract/src/wasm_opt.rs | 124 +++++++++++++++------ 3 files changed, 241 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 701e16443..2f0c236ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -501,6 +501,7 @@ dependencies = [ "url", "wabt", "walkdir", + "wasm-opt", "which", "zip", ] @@ -532,6 +533,9 @@ name = "cc" version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -597,6 +601,16 @@ dependencies = [ "cc", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "colored" version = "2.0.0" @@ -783,6 +797,50 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cxx" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7df2292959b7e22a5cb39d37b7e72b2c748b12f956cc409b529fddcdc8857b" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0806e5c64f74bd64b94d857b1c28cc3d493579a65f5f31e7d3451706d4025405" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2069b1573efd6e5901004e8fdca2e28bc6f47f86dc24da81182851e71cf3208" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d980827d1ec28ea6e0db545fceaa611eb8e43f70eff8c1c33cc2c96ffa0f0476" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "darling" version = "0.14.1" @@ -1645,6 +1703,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + [[package]] name = "joinery" version = "2.1.0" @@ -1817,6 +1884,15 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "lock_api" version = "0.4.7" @@ -2729,6 +2805,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "sct" version = "0.7.0" @@ -3310,6 +3392,25 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "substrate-bip39" version = "0.4.4" @@ -3467,18 +3568,18 @@ checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b" [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" dependencies = [ "proc-macro2", "quote", @@ -3774,6 +3875,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode-xid" version = "0.2.3" @@ -3953,6 +4060,45 @@ version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +[[package]] +name = "wasm-opt" +version = "0.110.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02484958a1edbd8e71485c5c10e89cbcf58b3a234aafc2fe78dee79cbfbbaae5" +dependencies = [ + "anyhow", + "libc", + "strum", + "strum_macros", + "tempfile", + "thiserror", + "wasm-opt-cxx-sys", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-cxx-sys" +version = "0.110.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c150ac22758b63137b0ccbcddcc45cfaa2bb1b4d7ebc7d50f6bb76d4d52a5bf1" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-sys" +version = "0.110.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc8110e347152693834f357f67b1505ab85ec9546b9546d41a6299bab06d4f9a" +dependencies = [ + "anyhow", + "cc", + "regex", +] + [[package]] name = "wasmi" version = "0.9.1" diff --git a/crates/cargo-contract/Cargo.toml b/crates/cargo-contract/Cargo.toml index ae6ebf313..adfeaae35 100644 --- a/crates/cargo-contract/Cargo.toml +++ b/crates/cargo-contract/Cargo.toml @@ -41,6 +41,7 @@ tempfile = "3.3.0" url = { version = "2.3.1", features = ["serde"] } impl-serde = "0.4.0" regex = "1.6.0" +wasm-opt = { version = "0.110.0", optional = true } # dependencies for extrinsics (deploying and calling a contract) async-std = { version = "1.12.0", features = ["attributes", "tokio1"] } @@ -70,8 +71,9 @@ predicates = "2.1.1" [features] # This `std` feature is required for testing using an inline contract's metadata, because `ink!` annotates the metadata # generation code with `#[cfg(feature = "std")]`. -default = ["std"] +default = ["std", "integrated-wasm-opt"] std = [] +integrated-wasm-opt = ["wasm-opt"] # Enable this to execute long running tests, which usually are only run on the CI server # diff --git a/crates/cargo-contract/src/wasm_opt.rs b/crates/cargo-contract/src/wasm_opt.rs index 170782b33..4f8be5c8f 100644 --- a/crates/cargo-contract/src/wasm_opt.rs +++ b/crates/cargo-contract/src/wasm_opt.rs @@ -29,10 +29,15 @@ use std::{ Path, PathBuf, }, - process::Command, str, }; +#[cfg(feature = "wasm-opt")] +use wasm_opt::integration::Command; + +#[cfg(not(feature = "wasm-opt"))] +use std::process::Command; + const WASM_OPT_INSTALLATION_SUGGESTION: &str = "wasm-opt not found! Make sure the binary is in your PATH environment.\n\n\ We use this tool to optimize the size of your contract's Wasm binary.\n\n\ @@ -48,6 +53,12 @@ const WASM_OPT_INSTALLATION_SUGGESTION: &str = installation instructions at https://github.com/WebAssembly/binaryen#tools."; /// A helpful struct for interacting with Binaryen's `wasm-opt` tool. +/// +/// This supports both the `wasm-opt` CLI and the `wasm-opt` crate, +/// with the crate being used if both the `integrated-wasm-opt` cargo feature +/// is active, and the `DISABLE_INTEGRATED_WASM_OPT` environment variable is not set. +/// It is intended that once confidence in the crate is established support +/// for the CLI will be removed. pub struct WasmOptHandler { /// The path to the `wasm-opt` binary. wasm_opt_path: PathBuf, @@ -68,24 +79,35 @@ impl WasmOptHandler { optimization_level: OptimizationPasses, keep_debug_symbols: bool, ) -> Result { - let which = which::which("wasm-opt"); - if which.is_err() { - anyhow::bail!(WASM_OPT_INSTALLATION_SUGGESTION.to_string().bright_yellow()); + if Self::use_integrated_wasm_opt() { + Ok(Self { + wasm_opt_path: PathBuf::from("wasm-opt"), + optimization_level, + keep_debug_symbols, + _version: 0, + }) + } else { + let which = which::which("wasm-opt"); + if which.is_err() { + anyhow::bail!(WASM_OPT_INSTALLATION_SUGGESTION + .to_string() + .bright_yellow()); + } + + let wasm_opt_path = + which.expect("we just checked if `which` returned an err; qed"); + tracing::debug!("Path to wasm-opt executable: {}", wasm_opt_path.display()); + + let version = + Self::check_wasm_opt_version_compatibility(wasm_opt_path.as_path())?; + + Ok(Self { + wasm_opt_path, + optimization_level, + keep_debug_symbols, + _version: version, + }) } - - let wasm_opt_path = - which.expect("we just checked if `which` returned an err; qed"); - tracing::debug!("Path to wasm-opt executable: {}", wasm_opt_path.display()); - - let version = - Self::check_wasm_opt_version_compatibility(wasm_opt_path.as_path())?; - - Ok(Self { - wasm_opt_path, - optimization_level, - keep_debug_symbols, - _version: version, - }) } /// Attempts to perform optional Wasm optimization using Binaryen's `wasm-opt` tool. @@ -123,24 +145,7 @@ impl WasmOptHandler { tracing::debug!("Invoking wasm-opt with {:?}", command); - let output = command.output().map_err(|err| { - anyhow::anyhow!( - "Executing {} failed with {:?}", - self.wasm_opt_path.display(), - err - ) - })?; - - if !output.status.success() { - let err = str::from_utf8(&output.stderr) - .expect("Cannot convert stderr output of wasm-opt to string") - .trim(); - anyhow::bail!( - "The wasm-opt optimization failed.\n\n\ - The error which wasm-opt returned was: \n{}", - err - ); - } + self.run_wasm_opt(command)?; if !dest_optimized.exists() { return Err(anyhow::anyhow!( @@ -161,6 +166,53 @@ impl WasmOptHandler { }) } + fn use_integrated_wasm_opt() -> bool { + if std::env::var("DISABLE_INTEGRATED_WASM_OPT").is_ok() { + false + } else { + cfg!(feature = "integrated-wasm-opt") + } + } + + fn run_wasm_opt(&self, command: Command) -> Result<()> { + if Self::use_integrated_wasm_opt() { + self.run_wasm_opt_integrated(command) + } else { + self.run_wasm_opt_cli(command) + } + } + + fn run_wasm_opt_integrated(&self, command: Command) -> Result<()> { + if cfg!(feature = "wasm-opt") { + Ok(wasm_opt::integration::run_from_command_args(command)?) + } else { + unreachable!("Not built with integrated wasm-opt") + } + } + + fn run_wasm_opt_cli(&self, mut command: Command) -> Result<()> { + let output = command.output().map_err(|err| { + anyhow::anyhow!( + "Executing {} failed with {:?}", + self.wasm_opt_path.display(), + err + ) + })?; + + if !output.status.success() { + let err = str::from_utf8(&output.stderr) + .expect("Cannot convert stderr output of wasm-opt to string") + .trim(); + anyhow::bail!( + "The wasm-opt optimization failed.\n\n\ + The error which wasm-opt returned was: \n{}", + err + ); + } + + Ok(()) + } + /// Checks if the `wasm-opt` binary under `wasm_opt_path` returns a version /// compatible with `cargo-contract`. /// From 4ccdd26661eb8de6b23866031d0175a6b622f27c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 4 Oct 2022 03:22:53 -0400 Subject: [PATCH 3/6] Remove option to use wasm-opt CLI --- crates/cargo-contract/Cargo.toml | 6 +- crates/cargo-contract/src/main.rs | 23 ++ crates/cargo-contract/src/wasm_opt.rs | 329 +------------------------- 3 files changed, 35 insertions(+), 323 deletions(-) diff --git a/crates/cargo-contract/Cargo.toml b/crates/cargo-contract/Cargo.toml index adfeaae35..c98affe3d 100644 --- a/crates/cargo-contract/Cargo.toml +++ b/crates/cargo-contract/Cargo.toml @@ -40,8 +40,7 @@ serde_json = "1.0.85" tempfile = "3.3.0" url = { version = "2.3.1", features = ["serde"] } impl-serde = "0.4.0" -regex = "1.6.0" -wasm-opt = { version = "0.110.0", optional = true } +wasm-opt = "0.110.0" # dependencies for extrinsics (deploying and calling a contract) async-std = { version = "1.12.0", features = ["attributes", "tokio1"] } @@ -71,9 +70,8 @@ predicates = "2.1.1" [features] # This `std` feature is required for testing using an inline contract's metadata, because `ink!` annotates the metadata # generation code with `#[cfg(feature = "std")]`. -default = ["std", "integrated-wasm-opt"] +default = ["std"] std = [] -integrated-wasm-opt = ["wasm-opt"] # Enable this to execute long running tests, which usually are only run on the CI server # diff --git a/crates/cargo-contract/src/main.rs b/crates/cargo-contract/src/main.rs index 1cc06b674..901f4506b 100644 --- a/crates/cargo-contract/src/main.rs +++ b/crates/cargo-contract/src/main.rs @@ -50,6 +50,7 @@ use std::{ str::FromStr, }; +use ::wasm_opt::OptimizationOptions; use anyhow::{ anyhow, Error, @@ -71,6 +72,12 @@ use assert_cmd as _; #[cfg(test)] use predicates as _; +#[cfg(test)] +use regex as _; + +// Only used on windows. +use which as _; + #[derive(Debug, Parser)] #[clap(bin_name = "cargo")] #[clap(version = env!("CARGO_CONTRACT_CLI_IMPL_VERSION"))] @@ -158,6 +165,22 @@ impl From for OptimizationPasses { } } +impl From for OptimizationOptions { + fn from(passes: OptimizationPasses) -> OptimizationOptions { + match passes { + OptimizationPasses::Zero => OptimizationOptions::new_opt_level_0(), + OptimizationPasses::One => OptimizationOptions::new_opt_level_1(), + OptimizationPasses::Two => OptimizationOptions::new_opt_level_2(), + OptimizationPasses::Three => OptimizationOptions::new_opt_level_3(), + OptimizationPasses::Four => OptimizationOptions::new_opt_level_4(), + OptimizationPasses::S => OptimizationOptions::new_optimize_for_size(), + OptimizationPasses::Z => { + OptimizationOptions::new_optimize_for_size_aggressively() + } + } + } +} + #[derive(Default, Clone, Debug, Args)] pub struct VerbosityFlags { /// No output printed to stdout diff --git a/crates/cargo-contract/src/wasm_opt.rs b/crates/cargo-contract/src/wasm_opt.rs index 4f8be5c8f..0037f22d5 100644 --- a/crates/cargo-contract/src/wasm_opt.rs +++ b/crates/cargo-contract/src/wasm_opt.rs @@ -20,54 +20,19 @@ use crate::{ }; use anyhow::Result; -use colored::Colorize; -use regex::Regex; +use wasm_opt::OptimizationOptions; use std::{ fs::metadata, - path::{ - Path, - PathBuf, - }, - str, + path::PathBuf, }; -#[cfg(feature = "wasm-opt")] -use wasm_opt::integration::Command; - -#[cfg(not(feature = "wasm-opt"))] -use std::process::Command; - -const WASM_OPT_INSTALLATION_SUGGESTION: &str = - "wasm-opt not found! Make sure the binary is in your PATH environment.\n\n\ - We use this tool to optimize the size of your contract's Wasm binary.\n\n\ - It can be installed with the command\n\n\ - cargo install wasm-opt --locked\n\n\ - Alternately, there are ready-to-install packages for many platforms:\n\ - * Debian/Ubuntu: apt-get install binaryen\n\ - * Homebrew: brew install binaryen\n\ - * Arch Linux: pacman -S binaryen\n\ - * Windows: binary releases at https://github.com/WebAssembly/binaryen/releases\n\n\" - wasm-opt is part of the binaryen toolset.\n\ - You can find detailed\n\ - installation instructions at https://github.com/WebAssembly/binaryen#tools."; - /// A helpful struct for interacting with Binaryen's `wasm-opt` tool. -/// -/// This supports both the `wasm-opt` CLI and the `wasm-opt` crate, -/// with the crate being used if both the `integrated-wasm-opt` cargo feature -/// is active, and the `DISABLE_INTEGRATED_WASM_OPT` environment variable is not set. -/// It is intended that once confidence in the crate is established support -/// for the CLI will be removed. pub struct WasmOptHandler { - /// The path to the `wasm-opt` binary. - wasm_opt_path: PathBuf, /// The optimization level that should be used when optimizing the Wasm binary. optimization_level: OptimizationPasses, /// Whether or not to keep debugging information in the final Wasm binary. keep_debug_symbols: bool, - /// The version number of the `wasm-opt` binary being executed. - _version: u32, } impl WasmOptHandler { @@ -79,35 +44,10 @@ impl WasmOptHandler { optimization_level: OptimizationPasses, keep_debug_symbols: bool, ) -> Result { - if Self::use_integrated_wasm_opt() { - Ok(Self { - wasm_opt_path: PathBuf::from("wasm-opt"), - optimization_level, - keep_debug_symbols, - _version: 0, - }) - } else { - let which = which::which("wasm-opt"); - if which.is_err() { - anyhow::bail!(WASM_OPT_INSTALLATION_SUGGESTION - .to_string() - .bright_yellow()); - } - - let wasm_opt_path = - which.expect("we just checked if `which` returned an err; qed"); - tracing::debug!("Path to wasm-opt executable: {}", wasm_opt_path.display()); - - let version = - Self::check_wasm_opt_version_compatibility(wasm_opt_path.as_path())?; - - Ok(Self { - wasm_opt_path, - optimization_level, - keep_debug_symbols, - _version: version, - }) - } + Ok(Self { + optimization_level, + keep_debug_symbols, + }) } /// Attempts to perform optional Wasm optimization using Binaryen's `wasm-opt` tool. @@ -128,24 +68,13 @@ impl WasmOptHandler { self.optimization_level ); - let mut command = Command::new(self.wasm_opt_path.as_path()); - command - .arg(dest_wasm.as_os_str()) - .arg(format!("-O{}", self.optimization_level)) - .arg("-o") - .arg(dest_optimized.as_os_str()) + OptimizationOptions::from(self.optimization_level) // the memory in our module is imported, `wasm-opt` needs to be told that // the memory is initialized to zeroes, otherwise it won't run the // memory-packing pre-pass. - .arg("--zero-filled-memory"); - - if self.keep_debug_symbols { - command.arg("-g"); - } - - tracing::debug!("Invoking wasm-opt with {:?}", command); - - self.run_wasm_opt(command)?; + .zero_filled_memory(true) + .debug_info(self.keep_debug_symbols) + .run(&dest_wasm, &dest_optimized)?; if !dest_optimized.exists() { return Err(anyhow::anyhow!( @@ -165,242 +94,4 @@ impl WasmOptHandler { optimized_size, }) } - - fn use_integrated_wasm_opt() -> bool { - if std::env::var("DISABLE_INTEGRATED_WASM_OPT").is_ok() { - false - } else { - cfg!(feature = "integrated-wasm-opt") - } - } - - fn run_wasm_opt(&self, command: Command) -> Result<()> { - if Self::use_integrated_wasm_opt() { - self.run_wasm_opt_integrated(command) - } else { - self.run_wasm_opt_cli(command) - } - } - - fn run_wasm_opt_integrated(&self, command: Command) -> Result<()> { - if cfg!(feature = "wasm-opt") { - Ok(wasm_opt::integration::run_from_command_args(command)?) - } else { - unreachable!("Not built with integrated wasm-opt") - } - } - - fn run_wasm_opt_cli(&self, mut command: Command) -> Result<()> { - let output = command.output().map_err(|err| { - anyhow::anyhow!( - "Executing {} failed with {:?}", - self.wasm_opt_path.display(), - err - ) - })?; - - if !output.status.success() { - let err = str::from_utf8(&output.stderr) - .expect("Cannot convert stderr output of wasm-opt to string") - .trim(); - anyhow::bail!( - "The wasm-opt optimization failed.\n\n\ - The error which wasm-opt returned was: \n{}", - err - ); - } - - Ok(()) - } - - /// Checks if the `wasm-opt` binary under `wasm_opt_path` returns a version - /// compatible with `cargo-contract`. - /// - /// Currently this must be a version >= 99. - fn check_wasm_opt_version_compatibility(wasm_opt_path: &Path) -> Result { - let mut cmd_res = Command::new(wasm_opt_path).arg("--version").output(); - - // The following condition is a workaround for a spurious CI failure: - // ``` - // Executing `"/tmp/cargo-contract.test.GGnC0p/wasm-opt-mocked" --version` failed with - // Os { code: 26, kind: ExecutableFileBusy, message: "Text file busy" } - // ``` - if cmd_res.is_err() && format!("{:?}", cmd_res).contains("ExecutableFileBusy") { - std::thread::sleep(std::time::Duration::from_secs(1)); - cmd_res = Command::new(wasm_opt_path).arg("--version").output(); - } - - let res = cmd_res.map_err(|err| { - anyhow::anyhow!( - "Executing `{:?} --version` failed with {:?}", - wasm_opt_path.display(), - err - ) - })?; - if !res.status.success() { - let err = str::from_utf8(&res.stderr) - .expect("Cannot convert stderr output of wasm-opt to string") - .trim(); - anyhow::bail!( - "Getting version information from wasm-opt failed.\n\ - The error which wasm-opt returned was: \n{}", - err - ); - } - - // ```sh - // $ wasm-opt --version - // wasm-opt version 99 (version_99-79-gc12cc3f50) - // ``` - let github_note = "\n\n\ - If you tried installing from your system package manager the best\n\ - way forward is to download a recent binary release directly:\n\n\ - https://github.com/WebAssembly/binaryen/releases\n\n\ - Make sure that the `wasm-opt` file from that release is in your `PATH`."; - let version_stdout = str::from_utf8(&res.stdout) - .expect("Cannot convert stdout output of wasm-opt to string") - .trim(); - let re = Regex::new(r"wasm-opt version (\d+)").expect("invalid regex"); - let captures = re.captures(version_stdout).ok_or_else(|| { - anyhow::anyhow!( - "Unable to extract version information from '{}'.\n\ - Your wasm-opt version is most probably too old. Make sure you use a version >= 99.{}", - version_stdout, - github_note, - ) - })?; - let version_number: u32 = captures - .get(1) // first capture group is at index 1 - .ok_or_else(|| { - anyhow::anyhow!( - "Unable to extract version number from '{:?}'", - version_stdout - ) - })? - .as_str() - .parse() - .map_err(|err| { - anyhow::anyhow!( - "Parsing version number failed with '{:?}' for '{:?}'", - err, - version_stdout - ) - })?; - - tracing::debug!( - "The wasm-opt version output is '{}', which was parsed to '{}'", - version_stdout, - version_number - ); - if version_number < 99 { - anyhow::bail!( - "Your wasm-opt version is {}, but we require a version >= 99.{}", - version_number, - github_note, - ); - } - - Ok(version_number) - } -} - -#[cfg(feature = "test-ci-only")] -#[cfg(all(test, unix))] -mod tests_ci_only { - use super::*; - - use crate::util::tests::{ - create_executable, - with_tmp_dir, - MockGuard, - }; - - /// Creates an executable `wasm-opt-mocked` file which outputs - /// "wasm-opt version `version`". - /// - /// Returns the path to this file. - /// - /// Currently works only on `unix`. - fn mock_wasm_opt_version(tmp_dir: &Path, version: &str) -> MockGuard { - let path = tmp_dir.join("wasm-opt-mocked"); - let content = format!("#!/bin/sh\necho \"wasm-opt version {}\"", version); - create_executable(&path, &content) - } - - #[test] - fn incompatible_wasm_opt_version_must_be_detected_if_built_from_repo() { - with_tmp_dir(|path| { - // given - let path = mock_wasm_opt_version(path, "98 (version_13-79-gc12cc3f50)"); - - // when - let res = WasmOptHandler::check_wasm_opt_version_compatibility(&path); - - // then - assert!(res.is_err()); - assert!( - format!("{:?}", res).starts_with( - "Err(Your wasm-opt version is 98, but we require a version >= 99." - ), - "Expected a different output, found {:?}", - res - ); - - Ok(()) - }) - } - - #[test] - fn compatible_wasm_opt_version_must_be_detected_if_built_from_repo() { - with_tmp_dir(|path| { - // given - let path = mock_wasm_opt_version(path, "99 (version_99-79-gc12cc3f50"); - - // when - let res = WasmOptHandler::check_wasm_opt_version_compatibility(&path); - - // then - assert!(res.is_ok()); - - Ok(()) - }) - } - - #[test] - fn incompatible_wasm_opt_version_must_be_detected_if_installed_as_package() { - with_tmp_dir(|path| { - // given - let path = mock_wasm_opt_version(path, "98"); - - // when - let res = WasmOptHandler::check_wasm_opt_version_compatibility(&path); - - // then - assert!(res.is_err()); - - // this println is here to debug a spuriously failing CI at the following assert. - eprintln!("error: {:?}", res); - assert!(format!("{:?}", res).starts_with( - "Err(Your wasm-opt version is 98, but we require a version >= 99." - )); - - Ok(()) - }) - } - - #[test] - fn compatible_wasm_opt_version_must_be_detected_if_installed_as_package() { - with_tmp_dir(|path| { - // given - let path = mock_wasm_opt_version(path, "99"); - - // when - let res = WasmOptHandler::check_wasm_opt_version_compatibility(&path); - - // then - assert!(res.is_ok()); - - Ok(()) - }) - } } From f84ad73efe63c56d43f2a0fa32cfd3f103c6f998 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 4 Oct 2022 23:29:50 -0400 Subject: [PATCH 4/6] Remove binaryen from prereqs --- README.md | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 875c896dd..41b601dc6 100644 --- a/README.md +++ b/README.md @@ -36,23 +36,13 @@ More relevant links: * Step 1: `rustup component add rust-src`. -* Step 2: Install `binaryen` in a version >= 99: - - * [Debian/Ubuntu](https://tracker.debian.org/pkg/binaryen): `apt-get install binaryen` - * [Homebrew](https://formulae.brew.sh/formula/binaryen): `brew install binaryen` - * [Arch Linux](https://archlinux.org/packages/community/x86_64/binaryen/): `pacman -S binaryen` - * Windows: [binary releases are available](https://github.com/WebAssembly/binaryen/releases) - - There's only an old version in your distributions package manager? Just use a - [binary release](https://github.com/WebAssembly/binaryen/releases). - -* Step 3: Install `dylint` +* Step 2: Install `dylint` * (MacOS) `brew install openssl` * `cargo install cargo-dylint dylint-link`. -* Step 4: `cargo install --force --locked cargo-contract`. +* Step 3: `cargo install --force --locked cargo-contract`. -You can always update the `cargo-contract` binary to the latest version by running the Step 4. +You can always update the `cargo-contract` binary to the latest version by running the Step 3. ### Installation using Docker Image From 1d3939a0a517632f153ee070d08d50eb7d640cdc Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 4 Oct 2022 23:31:21 -0400 Subject: [PATCH 5/6] Update changelog for wasm-opt crate --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b5ad2c21..8c1918161 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed +- Removed requirement to install binaryen. The `wasm-opt` tool is now compiled into `cargo-contract`. + ## [2.0.0-alpha.4] - 2022-10-03 ### Fixed From 3a6911436ea042a1f5c1b045a6049c95b0149e7f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 4 Oct 2022 23:48:12 -0400 Subject: [PATCH 6/6] Mention c++17 in readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 41b601dc6..789db18e7 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,9 @@ More relevant links: ## Installation +In addition to Rust, installation requires a C++ compiler that supports C++17. +Modern releases of gcc and clang, as well as Visual Studio 2019+ should work. + * Step 1: `rustup component add rust-src`. * Step 2: Install `dylint`