diff --git a/Cargo.lock b/Cargo.lock index 0c20d3890a37ffd8ce2e3cb5d42a02864816245e..49d4321a723ec5e7b425e92d879c1ce4ff2607d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,6 +269,7 @@ dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "async-std 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -284,6 +285,7 @@ dependencies = [ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -346,6 +348,16 @@ dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "colored" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "const-random" version = "0.1.8" @@ -2952,6 +2964,15 @@ dependencies = [ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "which" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -3074,6 +3095,7 @@ dependencies = [ "checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" +"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d" "checksum const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" "checksum const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" @@ -3350,6 +3372,7 @@ dependencies = [ "checksum webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e664e770ac0110e2384769bcc59ed19e329d81f555916a6e072714957b81b4" "checksum webpki-roots 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a262ae37dd9d60f60dd473d1158f9fbebf110ba7b6a5051c8160460f6043718b" "checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" +"checksum which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index 3cee7d4349b3b0abdb420b560bb4992dd6ea6e75..b858e4be8582e859fba35d37e6c97cf7b1ed29cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,8 @@ pwasm-utils = "0.12" parity-wasm = "0.41" cargo_metadata = "0.9" codec = { package = "parity-scale-codec", version = "1.1" } +which = "3.1.0" +colored = "1.9" # dependencies for optional extrinsics feature async-std = { version = "1.2.0", optional = true } diff --git a/src/cmd/build.rs b/src/cmd/build.rs index b7deddfb73bf4d1108f60579e8cb7557e6a59bcd..c054f591ccb9040882a2d3e56aa0c25bc61e404a 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -14,10 +14,16 @@ // You should have received a copy of the GNU General Public License // along with ink!. If not, see . -use std::path::PathBuf; +use std::{ + fs::metadata, + io::{self, Write}, + path::PathBuf, + process::Command, +}; use anyhow::{Context, Result}; use cargo_metadata::MetadataCommand; +use colored::Colorize; use parity_wasm::elements::{External, MemoryType, Module, Section}; /// This is the maximum number of pages available for a contract to allocate. @@ -25,6 +31,7 @@ const MAX_MEMORY_PAGES: u32 = 16; /// Relevant metadata obtained from Cargo.toml. pub struct CrateMetadata { + package_name: String, original_wasm: PathBuf, pub dest_wasm: PathBuf, } @@ -62,10 +69,11 @@ pub fn collect_crate_metadata(working_dir: Option<&PathBuf>) -> Result Result<()> { Ok(()) } +/// Attempts to perform optional wasm optimization using `wasm-opt`. +/// +/// The intention is to reduce the size of bloated wasm binaries as a result of missing +/// optimizations (or bugs?) between Rust and Wasm. +/// +/// This step depends on the `wasm-opt` tool being installed. If it is not the build will still +/// succeed, and the user will be encouraged to install it for further optimizations. +fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> { + // check `wasm-opt` installed + if which::which("wasm-opt").is_err() { + println!( + "{}", + "wasm-opt is not installed. Install this tool on your system in order to \n\ + reduce the size of your contract's Wasm binary. \n\ + See https://github.com/WebAssembly/binaryen#tools" + .bright_yellow() + ); + return Ok(()); + } + + let mut optimized = crate_metadata.dest_wasm.clone(); + optimized.set_file_name(format!("{}-opt.wasm", crate_metadata.package_name)); + + let output = Command::new("wasm-opt") + .arg(crate_metadata.dest_wasm.as_os_str()) + .arg("-O3") // execute -O3 optimization passes (spends potentially a lot of time optimizing) + .arg("-o") + .arg(optimized.as_os_str()) + .output()?; + + if !output.status.success() { + // Dump the output streams produced by wasm-opt into the stdout/stderr. + io::stdout().write_all(&output.stdout)?; + io::stderr().write_all(&output.stderr)?; + anyhow::bail!("wasm-opt optimization failed"); + } + + let original_size = metadata(&crate_metadata.dest_wasm)?.len() / 1000; + let optimized_size = metadata(&optimized)?.len() / 1000; + println!( + " Original wasm size: {}K, Optimized: {}K", + original_size, optimized_size + ); + + // overwrite existing destination wasm file with the optimised version + std::fs::rename(&optimized, &crate_metadata.dest_wasm)?; + Ok(()) +} + /// Executes build of the smart-contract which produces a wasm binary that is ready for deploying. /// /// It does so by invoking build by cargo and then post processing the final binary. pub(crate) fn execute_build(working_dir: Option<&PathBuf>) -> Result { - println!(" [1/3] Collecting crate metadata"); + println!( + " {} {}", + "[1/4]".bold(), + "Collecting crate metadata".bright_green().bold() + ); let crate_metadata = collect_crate_metadata(working_dir)?; - println!(" [2/3] Building cargo project"); + println!( + " {} {}", + "[2/4]".bold(), + "Building cargo project".bright_green().bold() + ); build_cargo_project(working_dir)?; - println!(" [3/3] Post processing wasm file"); + println!( + " {} {}", + "[3/4]".bold(), + "Post processing wasm file".bright_green().bold() + ); post_process_wasm(&crate_metadata)?; + println!( + " {} {}", + "[4/4]".bold(), + "Optimizing wasm file".bright_green().bold() + ); + optimize_wasm(&crate_metadata)?; Ok(format!( - "Your contract is ready.\nYou can find it here:\n{}", - crate_metadata.dest_wasm.display() + "\nYour contract is ready. You can find it here:\n{}", + crate_metadata.dest_wasm.display().to_string().bold() )) }