From 3bd088d41c73ec21cf6839b525dc7ffa483e7a3b Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Thu, 5 Mar 2020 08:52:23 +0100 Subject: [PATCH] Support enabling features with `wasm-builder` (#5131) This adds support for enabling features in the wasm build. The `default` and `std` feature are ignored in the build. --- substrate/Cargo.lock | 1 + substrate/utils/wasm-builder/Cargo.toml | 1 + .../utils/wasm-builder/src/wasm_project.rs | 66 +++++++++++++++---- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 6b3fca15e4..79872ffc6e 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -7819,6 +7819,7 @@ dependencies = [ "build-helper", "cargo_metadata", "fs2", + "itertools", "tempfile", "toml", "walkdir", diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index 245ec63114..1aac891393 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -18,3 +18,4 @@ walkdir = "2.2.9" fs2 = "0.4.3" wasm-gc-api = "0.1.11" atty = "0.2.13" +itertools = "0.8.2" diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index c4f00b9cf4..1e6d7fa463 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -28,6 +28,8 @@ use walkdir::WalkDir; use fs2::FileExt; +use itertools::Itertools; + /// Holds the path to the bloaty WASM binary. pub struct WasmBinaryBloaty(PathBuf); @@ -87,8 +89,13 @@ pub fn create_and_compile( // Lock the workspace exclusively for us let _lock = WorkspaceLock::new(&wasm_workspace_root); - let project = create_project(cargo_manifest, &wasm_workspace); - create_wasm_workspace_project(&wasm_workspace, cargo_manifest); + let crate_metadata = MetadataCommand::new() + .manifest_path(cargo_manifest) + .exec() + .expect("`cargo metadata` can not fail on project `Cargo.toml`; qed"); + + let project = create_project(cargo_manifest, &wasm_workspace, &crate_metadata); + create_wasm_workspace_project(&wasm_workspace, &crate_metadata.workspace_root); build_project(&project, default_rustflags); let (wasm_binary, bloaty) = compact_wasm_file( @@ -232,15 +239,9 @@ fn find_and_clear_workspace_members(wasm_workspace: &Path) -> Vec { members } -fn create_wasm_workspace_project(wasm_workspace: &Path, cargo_manifest: &Path) { +fn create_wasm_workspace_project(wasm_workspace: &Path, workspace_root_path: &Path) { let members = find_and_clear_workspace_members(wasm_workspace); - let crate_metadata = MetadataCommand::new() - .manifest_path(cargo_manifest) - .exec() - .expect("`cargo metadata` can not fail on project `Cargo.toml`; qed"); - let workspace_root_path = crate_metadata.workspace_root; - let mut workspace_toml: Table = toml::from_str( &fs::read_to_string( workspace_root_path.join("Cargo.toml"), @@ -281,8 +282,10 @@ fn create_wasm_workspace_project(wasm_workspace: &Path, cargo_manifest: &Path) { p.iter_mut() .filter(|(k, _)| k == &"path") .for_each(|(_, v)| { - if let Some(path) = v.as_str() { - *v = workspace_root_path.join(path).display().to_string().into(); + if let Some(path) = v.as_str().map(PathBuf::from) { + if path.is_relative() { + *v = workspace_root_path.join(path).display().to_string().into(); + } } }) ); @@ -296,11 +299,45 @@ fn create_wasm_workspace_project(wasm_workspace: &Path, cargo_manifest: &Path) { ).expect("WASM workspace `Cargo.toml` writing can not fail; qed"); } +/// Get a list of enabled features for the project. +fn project_enabled_features( + cargo_manifest: &Path, + crate_metadata: &cargo_metadata::Metadata, +) -> Vec { + let package = crate_metadata.packages + .iter() + .find(|p| p.manifest_path == cargo_manifest) + .expect("Wasm project exists in its own metadata; qed"); + + let mut enabled_features = package.features.keys() + .filter(|f| { + let mut feature_env = f.replace("-", "_"); + feature_env.make_ascii_uppercase(); + + // We don't want to enable the `std`/`default` feature for the wasm build and + // we need to check if the feature is enabled by checking the env variable. + *f != "std" + && *f != "default" + && env::var(format!("CARGO_FEATURE_{}", feature_env)) + .map(|v| v == "1") + .unwrap_or_default() + }) + .cloned() + .collect::>(); + + enabled_features.sort(); + enabled_features +} + /// Create the project used to build the wasm binary. /// /// # Returns /// The path to the created project. -fn create_project(cargo_manifest: &Path, wasm_workspace: &Path) -> PathBuf { +fn create_project( + cargo_manifest: &Path, + wasm_workspace: &Path, + crate_metadata: &cargo_metadata::Metadata, +) -> PathBuf { let crate_name = get_crate_name(cargo_manifest); let crate_path = cargo_manifest.parent().expect("Parent path exists; qed"); let wasm_binary = get_wasm_binary_name(cargo_manifest); @@ -308,6 +345,8 @@ fn create_project(cargo_manifest: &Path, wasm_workspace: &Path) -> PathBuf { fs::create_dir_all(project_folder.join("src")).expect("Wasm project dir create can not fail; qed"); + let enabled_features = project_enabled_features(&cargo_manifest, &crate_metadata); + write_file_if_changed( project_folder.join("Cargo.toml"), format!( @@ -322,11 +361,12 @@ fn create_project(cargo_manifest: &Path, wasm_workspace: &Path) -> PathBuf { crate-type = ["cdylib"] [dependencies] - wasm_project = {{ package = "{crate_name}", path = "{crate_path}", default-features = false }} + wasm_project = {{ package = "{crate_name}", path = "{crate_path}", default-features = false, features = [ {features} ] }} "#, crate_name = crate_name, crate_path = crate_path.display(), wasm_binary = wasm_binary, + features = enabled_features.into_iter().map(|f| format!("\"{}\"", f)).join(","), ) );