mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 17:01:09 +00:00
Reorganising the repository - external renames and moves (#4074)
* Adding first rough ouline of the repository structure * Remove old CI stuff * add title * formatting fixes * move node-exits job's script to scripts dir * Move docs into subdir * move to bin * move maintainence scripts, configs and helpers into its own dir * add .local to ignore * move core->client * start up 'test' area * move test client * move test runtime * make test move compile * Add dependencies rule enforcement. * Fix indexing. * Update docs to reflect latest changes * Moving /srml->/paint * update docs * move client/sr-* -> primitives/ * clean old readme * remove old broken code in rhd * update lock * Step 1. * starting to untangle client * Fix after merge. * start splitting out client interfaces * move children and blockchain interfaces * Move trie and state-machine to primitives. * Fix WASM builds. * fixing broken imports * more interface moves * move backend and light to interfaces * move CallExecutor * move cli off client * moving around more interfaces * re-add consensus crates into the mix * fix subkey path * relieve client from executor * starting to pull out client from grandpa * move is_decendent_of out of client * grandpa still depends on client directly * lemme tests pass * rename srml->paint * Make it compile. * rename interfaces->client-api * Move keyring to primitives. * fixup libp2p dep * fix broken use * allow dependency enforcement to fail * move fork-tree * Moving wasm-builder * make env * move build-script-utils * fixup broken crate depdencies and names * fix imports for authority discovery * fix typo * update cargo.lock * fixing imports * Fix paths and add missing crates * re-add missing crates
This commit is contained in:
committed by
Bastian Köcher
parent
becc3b0a4f
commit
60e5011c72
@@ -0,0 +1,245 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! # WASM builder is a utility for building a project as a WASM binary
|
||||
//!
|
||||
//! The WASM builder is a tool that integrates the process of building the WASM binary of your project into the main
|
||||
//! `cargo` build process.
|
||||
//!
|
||||
//! ## Project setup
|
||||
//!
|
||||
//! A project that should be compiled as a WASM binary needs to:
|
||||
//!
|
||||
//! 1. Add a `build.rs` file.
|
||||
//! 2. Add `substrate-wasm-builder` as dependency into `build-dependencies`.
|
||||
//!
|
||||
//! The `build.rs` file needs to contain the following code:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! use wasm_builder_runner::{build_current_project, WasmBuilderSource};
|
||||
//!
|
||||
//! fn main() {
|
||||
//! build_current_project(
|
||||
//! // The name of the file being generated in out-dir.
|
||||
//! "wasm_binary.rs",
|
||||
//! // How to include wasm-builder, in this case from crates.io.
|
||||
//! WasmBuilderSource::Crates("1.0.0"),
|
||||
//! );
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! As the final step, you need to add the following to your project:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||
//! ```
|
||||
//!
|
||||
//! This will include the generated WASM binary as two constants `WASM_BINARY` and `WASM_BINARY_BLOATY`.
|
||||
//! The former is a compact WASM binary and the latter is not compacted.
|
||||
//!
|
||||
//! ## Environment variables
|
||||
//!
|
||||
//! By using environment variables, you can configure which WASM binaries are built and how:
|
||||
//!
|
||||
//! - `SKIP_WASM_BUILD` - Skips building any wasm binary. This is useful when only native should be recompiled.
|
||||
//! - `BUILD_DUMMY_WASM_BINARY` - Builds dummy wasm binaries. These dummy binaries are empty and useful
|
||||
//! for `cargo check` runs.
|
||||
//! - `WASM_BUILD_TYPE` - Sets the build type for building wasm binaries. Supported values are `release` or `debug`.
|
||||
//! By default the build type is equal to the build type used by the main build.
|
||||
//! - `TRIGGER_WASM_BUILD` - Can be set to trigger a wasm build. On subsequent calls the value of the variable
|
||||
//! needs to change. As WASM builder instructs `cargo` to watch for file changes
|
||||
//! this environment variable should only be required in certain circumstances.
|
||||
//! - `WASM_BUILD_RUSTFLAGS` - Extend `RUSTFLAGS` given to `cargo build` while building the wasm binary.
|
||||
//! - `WASM_BUILD_NO_COLOR` - Disable color output of the wasm build.
|
||||
//! - `WASM_TARGET_DIRECTORY` - Will copy any build wasm binary to the given directory. The path needs
|
||||
//! to be absolute.
|
||||
//!
|
||||
//! Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`.
|
||||
//! Where `PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `node-runtime` will
|
||||
//! be `NODE_RUNTIME`.
|
||||
//!
|
||||
//! ## Prerequisites:
|
||||
//!
|
||||
//! WASM builder requires the following prerequisities for building the WASM binary:
|
||||
//!
|
||||
//! - rust nightly + `wasm32-unknown-unknown` toolchain
|
||||
//!
|
||||
|
||||
use std::{env, fs, path::PathBuf, process::{Command, Stdio, self}};
|
||||
|
||||
mod prerequisites;
|
||||
mod wasm_project;
|
||||
|
||||
/// Environment variable that tells us to skip building the wasm binary.
|
||||
const SKIP_BUILD_ENV: &str = "SKIP_WASM_BUILD";
|
||||
|
||||
/// Environment variable to force a certain build type when building the wasm binary.
|
||||
/// Expects "debug" or "release" as value.
|
||||
///
|
||||
/// By default the WASM binary uses the same build type as the main cargo build.
|
||||
const WASM_BUILD_TYPE_ENV: &str = "WASM_BUILD_TYPE";
|
||||
|
||||
/// Environment variable to extend the `RUSTFLAGS` variable given to the wasm build.
|
||||
const WASM_BUILD_RUSTFLAGS_ENV: &str = "WASM_BUILD_RUSTFLAGS";
|
||||
|
||||
/// Environment variable to set the target directory to copy the final wasm binary.
|
||||
///
|
||||
/// The directory needs to be an absolute path.
|
||||
const WASM_TARGET_DIRECTORY: &str = "WASM_TARGET_DIRECTORY";
|
||||
|
||||
/// Environment variable to disable color output of the wasm build.
|
||||
const WASM_BUILD_NO_COLOR: &str = "WASM_BUILD_NO_COLOR";
|
||||
|
||||
/// Build the currently built project as wasm binary.
|
||||
///
|
||||
/// The current project is determined by using the `CARGO_MANIFEST_DIR` environment variable.
|
||||
///
|
||||
/// `file_name` - The name + path of the file being generated. The file contains the
|
||||
/// constant `WASM_BINARY`, which contains the built WASM binary.
|
||||
/// `cargo_manifest` - The path to the `Cargo.toml` of the project that should be built.
|
||||
pub fn build_project(file_name: &str, cargo_manifest: &str) {
|
||||
build_project_with_default_rustflags(file_name, cargo_manifest, "");
|
||||
}
|
||||
|
||||
/// Build the currently built project as wasm binary.
|
||||
///
|
||||
/// The current project is determined by using the `CARGO_MANIFEST_DIR` environment variable.
|
||||
///
|
||||
/// `file_name` - The name + path of the file being generated. The file contains the
|
||||
/// constant `WASM_BINARY`, which contains the built WASM binary.
|
||||
/// `cargo_manifest` - The path to the `Cargo.toml` of the project that should be built.
|
||||
/// `default_rustflags` - Default `RUSTFLAGS` that will always be set for the build.
|
||||
pub fn build_project_with_default_rustflags(
|
||||
file_name: &str,
|
||||
cargo_manifest: &str,
|
||||
default_rustflags: &str,
|
||||
) {
|
||||
if check_skip_build() {
|
||||
return;
|
||||
}
|
||||
|
||||
let cargo_manifest = PathBuf::from(cargo_manifest);
|
||||
|
||||
if !cargo_manifest.exists() {
|
||||
panic!("'{}' does not exist!", cargo_manifest.display());
|
||||
}
|
||||
|
||||
if !cargo_manifest.ends_with("Cargo.toml") {
|
||||
panic!("'{}' no valid path to a `Cargo.toml`!", cargo_manifest.display());
|
||||
}
|
||||
|
||||
if let Some(err_msg) = prerequisites::check() {
|
||||
eprintln!("{}", err_msg);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let (wasm_binary, bloaty) = wasm_project::create_and_compile(
|
||||
&cargo_manifest,
|
||||
default_rustflags,
|
||||
);
|
||||
|
||||
write_file_if_changed(
|
||||
file_name.into(),
|
||||
format!(
|
||||
r#"
|
||||
pub const WASM_BINARY: &[u8] = include_bytes!("{wasm_binary}");
|
||||
pub const WASM_BINARY_BLOATY: &[u8] = include_bytes!("{wasm_binary_bloaty}");
|
||||
"#,
|
||||
wasm_binary = wasm_binary.wasm_binary_path(),
|
||||
wasm_binary_bloaty = bloaty.wasm_binary_bloaty_path(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Checks if the build of the WASM binary should be skipped.
|
||||
fn check_skip_build() -> bool {
|
||||
env::var(SKIP_BUILD_ENV).is_ok()
|
||||
}
|
||||
|
||||
/// Write to the given `file` if the `content` is different.
|
||||
fn write_file_if_changed(file: PathBuf, content: String) {
|
||||
if fs::read_to_string(&file).ok().as_ref() != Some(&content) {
|
||||
fs::write(&file, content).expect(&format!("Writing `{}` can not fail!", file.display()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a cargo command that compiles with nightly
|
||||
fn get_nightly_cargo() -> CargoCommand {
|
||||
let default_cargo = CargoCommand::new("cargo");
|
||||
let mut rustup_run_nightly = CargoCommand::new("rustup");
|
||||
rustup_run_nightly.args(&["run", "nightly", "cargo"]);
|
||||
|
||||
if default_cargo.is_nightly() {
|
||||
default_cargo
|
||||
} else if rustup_run_nightly.works() {
|
||||
rustup_run_nightly
|
||||
} else {
|
||||
default_cargo
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for cargo commands
|
||||
#[derive(Debug)]
|
||||
struct CargoCommand {
|
||||
program: String,
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
impl CargoCommand {
|
||||
fn new(program: &str) -> Self {
|
||||
CargoCommand { program: program.into(), args: Vec::new() }
|
||||
}
|
||||
|
||||
fn arg(&mut self, arg: &str) -> &mut Self {
|
||||
self.args.push(arg.into());
|
||||
self
|
||||
}
|
||||
|
||||
fn args(&mut self, args: &[&str]) -> &mut Self {
|
||||
args.into_iter().for_each(|a| { self.arg(a); });
|
||||
self
|
||||
}
|
||||
|
||||
fn command(&self) -> Command {
|
||||
let mut cmd = Command::new(&self.program);
|
||||
cmd.args(&self.args);
|
||||
cmd
|
||||
}
|
||||
|
||||
fn works(&self) -> bool {
|
||||
self.command()
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.status()
|
||||
.map(|s| s.success()).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Check if the supplied cargo command is a nightly version
|
||||
fn is_nightly(&self) -> bool {
|
||||
// `RUSTC_BOOTSTRAP` tells a stable compiler to behave like a nightly. So, when this env
|
||||
// variable is set, we can assume that whatever rust compiler we have, it is a nightly compiler.
|
||||
// For "more" information, see:
|
||||
// https://github.com/rust-lang/rust/blob/fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f/src/libsyntax/feature_gate/check.rs#L891
|
||||
env::var("RUSTC_BOOTSTRAP").is_ok() ||
|
||||
self.command()
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map_err(|_| ())
|
||||
.and_then(|o| String::from_utf8(o.stdout).map_err(|_| ()))
|
||||
.unwrap_or_default()
|
||||
.contains("-nightly")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::fs;
|
||||
|
||||
use tempfile::tempdir;
|
||||
|
||||
/// Checks that all prerequisites are installed.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns `None` if everything was found and `Some(ERR_MSG)` if something could not be found.
|
||||
pub fn check() -> Option<&'static str> {
|
||||
if !check_nightly_installed(){
|
||||
return Some("Rust nightly not installed, please install it!")
|
||||
}
|
||||
|
||||
check_wasm_toolchain_installed()
|
||||
}
|
||||
|
||||
fn check_nightly_installed() -> bool {
|
||||
crate::get_nightly_cargo().is_nightly()
|
||||
}
|
||||
|
||||
fn check_wasm_toolchain_installed() -> Option<&'static str> {
|
||||
let temp = tempdir().expect("Creating temp dir does not fail; qed");
|
||||
fs::create_dir_all(temp.path().join("src")).expect("Creating src dir does not fail; qed");
|
||||
|
||||
let test_file = temp.path().join("src/lib.rs");
|
||||
let manifest_path = temp.path().join("Cargo.toml");
|
||||
|
||||
fs::write(&manifest_path,
|
||||
r#"
|
||||
[package]
|
||||
name = "wasm-test"
|
||||
version = "1.0.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "wasm_test"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[workspace]
|
||||
"#,
|
||||
).expect("Writing wasm-test manifest does not fail; qed");
|
||||
fs::write(&test_file, "pub fn test() {}")
|
||||
.expect("Writing to the test file does not fail; qed");
|
||||
|
||||
let err_msg = "Rust WASM toolchain not installed, please install it!";
|
||||
let manifest_path = manifest_path.display().to_string();
|
||||
crate::get_nightly_cargo()
|
||||
.command()
|
||||
.args(&["build", "--target=wasm32-unknown-unknown", "--manifest-path", &manifest_path])
|
||||
.output()
|
||||
.map_err(|_| err_msg)
|
||||
.and_then(|s|
|
||||
if s.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
match String::from_utf8(s.stderr) {
|
||||
Ok(ref err) if err.contains("linker `rust-lld` not found") => {
|
||||
Err("`rust-lld` not found, please install it!")
|
||||
},
|
||||
_ => Err(err_msg)
|
||||
}
|
||||
}
|
||||
)
|
||||
.err()
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::write_file_if_changed;
|
||||
|
||||
use std::{fs, path::{Path, PathBuf}, borrow::ToOwned, process, env};
|
||||
|
||||
use toml::value::Table;
|
||||
|
||||
use build_helper::rerun_if_changed;
|
||||
|
||||
use cargo_metadata::MetadataCommand;
|
||||
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use fs2::FileExt;
|
||||
|
||||
/// Holds the path to the bloaty WASM binary.
|
||||
pub struct WasmBinaryBloaty(PathBuf);
|
||||
|
||||
impl WasmBinaryBloaty {
|
||||
/// Returns the path to the bloaty wasm binary.
|
||||
pub fn wasm_binary_bloaty_path(&self) -> String {
|
||||
self.0.display().to_string().replace('\\', "/")
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the path to the WASM binary.
|
||||
pub struct WasmBinary(PathBuf);
|
||||
|
||||
impl WasmBinary {
|
||||
/// Returns the path to the wasm binary.
|
||||
pub fn wasm_binary_path(&self) -> String {
|
||||
self.0.display().to_string().replace('\\', "/")
|
||||
}
|
||||
}
|
||||
|
||||
/// A lock for the WASM workspace.
|
||||
struct WorkspaceLock(fs::File);
|
||||
|
||||
impl WorkspaceLock {
|
||||
/// Create a new lock
|
||||
fn new(wasm_workspace_root: &Path) -> Self {
|
||||
let lock = fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(wasm_workspace_root.join("wasm_workspace.lock"))
|
||||
.expect("Opening the lock file does not fail");
|
||||
|
||||
lock.lock_exclusive().expect("Locking `wasm_workspace.lock` failed");
|
||||
|
||||
WorkspaceLock(lock)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WorkspaceLock {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.0.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the WASM project, compiles the WASM binary and compacts the WASM binary.
|
||||
///
|
||||
/// # Returns
|
||||
/// The path to the compact WASM binary and the bloaty WASM binary.
|
||||
pub fn create_and_compile(
|
||||
cargo_manifest: &Path,
|
||||
default_rustflags: &str,
|
||||
) -> (WasmBinary, WasmBinaryBloaty) {
|
||||
let wasm_workspace_root = get_wasm_workspace_root();
|
||||
let wasm_workspace = wasm_workspace_root.join("wbuild");
|
||||
|
||||
// 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);
|
||||
|
||||
build_project(&project, default_rustflags);
|
||||
let (wasm_binary, bloaty) = compact_wasm_file(
|
||||
&project,
|
||||
cargo_manifest,
|
||||
&wasm_workspace,
|
||||
);
|
||||
|
||||
copy_wasm_to_target_directory(cargo_manifest, &wasm_binary);
|
||||
|
||||
generate_rerun_if_changed_instructions(cargo_manifest, &project, &wasm_workspace);
|
||||
|
||||
(wasm_binary, bloaty)
|
||||
}
|
||||
|
||||
/// Find the `Cargo.lock` relative to the `OUT_DIR` environment variable.
|
||||
///
|
||||
/// If the `Cargo.lock` cannot be found, we emit a warning and return `None`.
|
||||
fn find_cargo_lock(cargo_manifest: &Path) -> Option<PathBuf> {
|
||||
fn find_impl(mut path: PathBuf) -> Option<PathBuf> {
|
||||
loop {
|
||||
if path.join("Cargo.lock").exists() {
|
||||
return Some(path.join("Cargo.lock"))
|
||||
}
|
||||
|
||||
if !path.pop() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(path) = find_impl(build_helper::out_dir()) {
|
||||
return Some(path);
|
||||
}
|
||||
|
||||
if let Some(path) = find_impl(cargo_manifest.to_path_buf()) {
|
||||
return Some(path);
|
||||
}
|
||||
|
||||
build_helper::warning!(
|
||||
"Could not find `Cargo.lock` for `{}`, while searching from `{}`.",
|
||||
cargo_manifest.display(),
|
||||
build_helper::out_dir().display()
|
||||
);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Extract the crate name from the given `Cargo.toml`.
|
||||
fn get_crate_name(cargo_manifest: &Path) -> String {
|
||||
let cargo_toml: Table = toml::from_str(
|
||||
&fs::read_to_string(cargo_manifest).expect("File exists as checked before; qed")
|
||||
).expect("Cargo manifest is a valid toml file; qed");
|
||||
|
||||
let package = cargo_toml
|
||||
.get("package")
|
||||
.and_then(|t| t.as_table())
|
||||
.expect("`package` key exists in valid `Cargo.toml`; qed");
|
||||
|
||||
package.get("name").and_then(|p| p.as_str()).map(ToOwned::to_owned).expect("Package name exists; qed")
|
||||
}
|
||||
|
||||
/// Returns the name for the wasm binary.
|
||||
fn get_wasm_binary_name(cargo_manifest: &Path) -> String {
|
||||
get_crate_name(cargo_manifest).replace('-', "_")
|
||||
}
|
||||
|
||||
/// Returns the root path of the wasm workspace.
|
||||
fn get_wasm_workspace_root() -> PathBuf {
|
||||
let mut out_dir = build_helper::out_dir();
|
||||
|
||||
loop {
|
||||
match out_dir.parent() {
|
||||
Some(parent) if out_dir.ends_with("build") => return parent.to_path_buf(),
|
||||
_ => if !out_dir.pop() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panic!("Could not find target dir in: {}", build_helper::out_dir().display())
|
||||
}
|
||||
|
||||
fn create_wasm_workspace_project(wasm_workspace: &Path, cargo_manifest: &Path) {
|
||||
let members = WalkDir::new(wasm_workspace)
|
||||
.min_depth(1)
|
||||
.max_depth(1)
|
||||
.into_iter()
|
||||
.filter_map(|p| p.ok())
|
||||
.map(|d| d.into_path())
|
||||
.filter(|p| p.is_dir() && !p.ends_with("target"))
|
||||
.filter_map(|p| p.file_name().map(|f| f.to_owned()).and_then(|s| s.into_string().ok()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
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"),
|
||||
).expect("Workspace root `Cargo.toml` exists; qed")
|
||||
).expect("Workspace root `Cargo.toml` is a valid toml file; qed");
|
||||
|
||||
let mut wasm_workspace_toml = Table::new();
|
||||
|
||||
// Add `profile` with release and dev
|
||||
let mut release_profile = Table::new();
|
||||
release_profile.insert("panic".into(), "abort".into());
|
||||
release_profile.insert("lto".into(), true.into());
|
||||
|
||||
let mut dev_profile = Table::new();
|
||||
dev_profile.insert("panic".into(), "abort".into());
|
||||
|
||||
let mut profile = Table::new();
|
||||
profile.insert("release".into(), release_profile.into());
|
||||
profile.insert("dev".into(), dev_profile.into());
|
||||
|
||||
wasm_workspace_toml.insert("profile".into(), profile.into());
|
||||
|
||||
// Add `workspace` with members
|
||||
let mut workspace = Table::new();
|
||||
workspace.insert("members".into(), members.into());
|
||||
|
||||
wasm_workspace_toml.insert("workspace".into(), workspace.into());
|
||||
|
||||
// Add patch section from the project root `Cargo.toml`
|
||||
if let Some(mut patch) = workspace_toml.remove("patch").and_then(|p| p.try_into::<Table>().ok()) {
|
||||
// Iterate over all patches and make the patch path absolute from the workspace root path.
|
||||
patch.iter_mut()
|
||||
.filter_map(|p|
|
||||
p.1.as_table_mut().map(|t| t.iter_mut().filter_map(|t| t.1.as_table_mut()))
|
||||
)
|
||||
.flatten()
|
||||
.for_each(|p|
|
||||
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();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
wasm_workspace_toml.insert("patch".into(), patch.into());
|
||||
}
|
||||
|
||||
fs::write(
|
||||
wasm_workspace.join("Cargo.toml"),
|
||||
toml::to_string_pretty(&wasm_workspace_toml).expect("Wasm workspace toml is valid; qed"),
|
||||
).expect("WASM workspace `Cargo.toml` writing can not fail; qed");
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
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);
|
||||
let project_folder = wasm_workspace.join(&crate_name);
|
||||
|
||||
fs::create_dir_all(project_folder.join("src")).expect("Wasm project dir create can not fail; qed");
|
||||
|
||||
write_file_if_changed(
|
||||
project_folder.join("Cargo.toml"),
|
||||
format!(
|
||||
r#"
|
||||
[package]
|
||||
name = "{crate_name}-wasm"
|
||||
version = "1.0.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "{wasm_binary}"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm_project = {{ package = "{crate_name}", path = "{crate_path}", default-features = false }}
|
||||
"#,
|
||||
crate_name = crate_name,
|
||||
crate_path = crate_path.display(),
|
||||
wasm_binary = wasm_binary,
|
||||
)
|
||||
);
|
||||
|
||||
write_file_if_changed(
|
||||
project_folder.join("src/lib.rs"),
|
||||
"#![no_std] pub use wasm_project::*;".into(),
|
||||
);
|
||||
|
||||
if let Some(crate_lock_file) = find_cargo_lock(cargo_manifest) {
|
||||
// Use the `Cargo.lock` of the main project.
|
||||
fs::copy(crate_lock_file, wasm_workspace.join("Cargo.lock"))
|
||||
.expect("Copying the `Cargo.lock` can not fail; qed");
|
||||
}
|
||||
|
||||
project_folder
|
||||
}
|
||||
|
||||
/// Returns if the project should be built as a release.
|
||||
fn is_release_build() -> bool {
|
||||
if let Ok(var) = env::var(crate::WASM_BUILD_TYPE_ENV) {
|
||||
match var.as_str() {
|
||||
"release" => true,
|
||||
"debug" => false,
|
||||
var => panic!(
|
||||
"Unexpected value for `{}` env variable: {}\nOne of the following are expected: `debug` or `release`.",
|
||||
crate::WASM_BUILD_TYPE_ENV,
|
||||
var,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
!build_helper::debug()
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the project to create the WASM binary.
|
||||
fn build_project(project: &Path, default_rustflags: &str) {
|
||||
let manifest_path = project.join("Cargo.toml");
|
||||
let mut build_cmd = crate::get_nightly_cargo().command();
|
||||
|
||||
let rustflags = format!(
|
||||
"-C link-arg=--export-table {} {}",
|
||||
default_rustflags,
|
||||
env::var(crate::WASM_BUILD_RUSTFLAGS_ENV).unwrap_or_default(),
|
||||
);
|
||||
|
||||
build_cmd.args(&["rustc", "--target=wasm32-unknown-unknown"])
|
||||
.arg(format!("--manifest-path={}", manifest_path.display()))
|
||||
.env("RUSTFLAGS", rustflags)
|
||||
// We don't want to call ourselves recursively
|
||||
.env(crate::SKIP_BUILD_ENV, "");
|
||||
|
||||
if env::var(crate::WASM_BUILD_NO_COLOR).is_err() {
|
||||
build_cmd.arg("--color=always");
|
||||
}
|
||||
|
||||
if is_release_build() {
|
||||
build_cmd.arg("--release");
|
||||
};
|
||||
|
||||
println!("Executing build command: {:?}", build_cmd);
|
||||
|
||||
match build_cmd.status().map(|s| s.success()) {
|
||||
Ok(true) => {},
|
||||
// Use `process.exit(1)` to have a clean error output.
|
||||
_ => process::exit(1),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compact the WASM binary using `wasm-gc`. Returns the path to the bloaty WASM binary.
|
||||
fn compact_wasm_file(
|
||||
project: &Path,
|
||||
cargo_manifest: &Path,
|
||||
wasm_workspace: &Path,
|
||||
) -> (WasmBinary, WasmBinaryBloaty) {
|
||||
let target = if is_release_build() { "release" } else { "debug" };
|
||||
let wasm_binary = get_wasm_binary_name(cargo_manifest);
|
||||
let wasm_file = wasm_workspace.join("target/wasm32-unknown-unknown")
|
||||
.join(target)
|
||||
.join(format!("{}.wasm", wasm_binary));
|
||||
let wasm_compact_file = project.join(format!("{}.compact.wasm", wasm_binary));
|
||||
|
||||
wasm_gc::garbage_collect_file(&wasm_file, &wasm_compact_file)
|
||||
.expect("Failed to compact generated WASM binary.");
|
||||
|
||||
(WasmBinary(wasm_compact_file), WasmBinaryBloaty(wasm_file))
|
||||
}
|
||||
|
||||
/// Generate the `rerun-if-changed` instructions for cargo to make sure that the WASM binary is
|
||||
/// rebuilt when needed.
|
||||
fn generate_rerun_if_changed_instructions(
|
||||
cargo_manifest: &Path,
|
||||
project_folder: &Path,
|
||||
wasm_workspace: &Path,
|
||||
) {
|
||||
// Rerun `build.rs` if the `Cargo.lock` changes
|
||||
if let Some(cargo_lock) = find_cargo_lock(cargo_manifest) {
|
||||
rerun_if_changed(cargo_lock);
|
||||
}
|
||||
|
||||
let metadata = MetadataCommand::new()
|
||||
.manifest_path(project_folder.join("Cargo.toml"))
|
||||
.exec()
|
||||
.expect("`cargo metadata` can not fail!");
|
||||
|
||||
// Make sure that if any file/folder of a depedency change, we need to rerun the `build.rs`
|
||||
metadata.packages.into_iter()
|
||||
.filter(|package| !package.manifest_path.starts_with(wasm_workspace))
|
||||
.for_each(|package| {
|
||||
let mut manifest_path = package.manifest_path;
|
||||
if manifest_path.ends_with("Cargo.toml") {
|
||||
manifest_path.pop();
|
||||
}
|
||||
|
||||
rerun_if_changed(&manifest_path);
|
||||
|
||||
WalkDir::new(manifest_path)
|
||||
.into_iter()
|
||||
.filter_map(|p| p.ok())
|
||||
.for_each(|p| rerun_if_changed(p.path()));
|
||||
});
|
||||
|
||||
// Register our env variables
|
||||
println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV);
|
||||
println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TYPE_ENV);
|
||||
println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_RUSTFLAGS_ENV);
|
||||
println!("cargo:rerun-if-env-changed={}", crate::WASM_TARGET_DIRECTORY);
|
||||
}
|
||||
|
||||
/// Copy the WASM binary to the target directory set in `WASM_TARGET_DIRECTORY` environment variable.
|
||||
/// If the variable is not set, this is a no-op.
|
||||
fn copy_wasm_to_target_directory(cargo_manifest: &Path, wasm_binary: &WasmBinary) {
|
||||
let target_dir = match env::var(crate::WASM_TARGET_DIRECTORY) {
|
||||
Ok(path) => PathBuf::from(path),
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
if !target_dir.is_absolute() {
|
||||
panic!(
|
||||
"Environment variable `{}` with `{}` is not an absolute path!",
|
||||
crate::WASM_TARGET_DIRECTORY,
|
||||
target_dir.display(),
|
||||
);
|
||||
}
|
||||
|
||||
fs::create_dir_all(&target_dir).expect("Creates `WASM_TARGET_DIRECTORY`.");
|
||||
|
||||
fs::copy(
|
||||
wasm_binary.wasm_binary_path(),
|
||||
target_dir.join(format!("{}.wasm", get_wasm_binary_name(cargo_manifest))),
|
||||
).expect("Copies WASM binary to `WASM_TARGET_DIRECTORY`.");
|
||||
}
|
||||
Reference in New Issue
Block a user