From 5199aa3f64c7e2d61dce2cdc84fe042e047e6893 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Sat, 9 Nov 2024 07:01:54 +0200 Subject: [PATCH] wasm-builder: Use the custom target riscv32emac-unknown-none-polkavm Signed-off-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- .gitignore | 1 + prdoc/pr_6419.prdoc | 12 +++ substrate/utils/wasm-builder/Cargo.toml | 1 + substrate/utils/wasm-builder/build.rs | 10 +++ .../riscv32emac-unknown-none-polkavm.json | 26 ++++++ .../utils/wasm-builder/rust-toolchain.xml | 2 + substrate/utils/wasm-builder/src/builder.rs | 8 +- substrate/utils/wasm-builder/src/lib.rs | 79 ++++++------------- .../utils/wasm-builder/src/prerequisites.rs | 2 +- .../utils/wasm-builder/src/wasm_project.rs | 13 +-- 10 files changed, 91 insertions(+), 63 deletions(-) create mode 100644 prdoc/pr_6419.prdoc create mode 100644 substrate/utils/wasm-builder/build.rs create mode 100644 substrate/utils/wasm-builder/riscv32emac-unknown-none-polkavm.json create mode 100644 substrate/utils/wasm-builder/rust-toolchain.xml diff --git a/.gitignore b/.gitignore index d48287657085..358265588b62 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ **/hfuzz_target/ **/hfuzz_workspace/ **/node_modules +**/rusty-tags.vi **/target/ **/wip/*.stderr **/__pycache__/ diff --git a/prdoc/pr_6419.prdoc b/prdoc/pr_6419.prdoc new file mode 100644 index 000000000000..6cc155d64b91 --- /dev/null +++ b/prdoc/pr_6419.prdoc @@ -0,0 +1,12 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Use the custom target riscv32emac-unknown-none-polkavm +doc: + - audience: Runtime Dev + description: | + Closes: https://github.com/paritytech/polkadot-sdk/issues/6335 + +crates: +- name: substrate-wasm-builder + bump: patch diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index 8f0e8a23e54a..b36b6abd3fb3 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -7,6 +7,7 @@ edition.workspace = true repository.workspace = true license = "Apache-2.0" homepage.workspace = true +rust-version = "1.84" [lints] workspace = true diff --git a/substrate/utils/wasm-builder/build.rs b/substrate/utils/wasm-builder/build.rs new file mode 100644 index 000000000000..cfa7435bc552 --- /dev/null +++ b/substrate/utils/wasm-builder/build.rs @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 + +use std::process::Command; + +fn main() { + Command::new("rustup") + .args(["override", "set", "nightly-2024-11-01"]).output().expect("rustup"); + + println!("cargo::rerun-if-changed=build.rs"); +} diff --git a/substrate/utils/wasm-builder/riscv32emac-unknown-none-polkavm.json b/substrate/utils/wasm-builder/riscv32emac-unknown-none-polkavm.json new file mode 100644 index 000000000000..482b4c4219bb --- /dev/null +++ b/substrate/utils/wasm-builder/riscv32emac-unknown-none-polkavm.json @@ -0,0 +1,26 @@ +{ + "arch": "riscv32", + "cpu": "generic-rv32", + "crt-objects-fallback": "false", + "data-layout": "e-m:e-p:32:32-i64:64-n32-S32", + "eh-frame-header": false, + "emit-debug-gdb-scripts": false, + "features": "+e,+m,+a,+c,+lui-addi-fusion,+xtheadcondmov", + "linker": "rust-lld", + "linker-flavor": "ld.lld", + "llvm-abiname": "ilp32e", + "llvm-target": "riscv32", + "max-atomic-width": 32, + "panic-strategy": "abort", + "relocation-model": "pie", + "target-pointer-width": "32", + "singlethread": true, + "pre-link-args": { + "ld": [ + "--emit-relocs", + "--unique", + "--relocatable" + ] + }, + "env": "polkavm" +} diff --git a/substrate/utils/wasm-builder/rust-toolchain.xml b/substrate/utils/wasm-builder/rust-toolchain.xml new file mode 100644 index 000000000000..2ab732e63b60 --- /dev/null +++ b/substrate/utils/wasm-builder/rust-toolchain.xml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly-2024-11-01" diff --git a/substrate/utils/wasm-builder/src/builder.rs b/substrate/utils/wasm-builder/src/builder.rs index a40aafe1d812..a4fba8c42e7e 100644 --- a/substrate/utils/wasm-builder/src/builder.rs +++ b/substrate/utils/wasm-builder/src/builder.rs @@ -235,7 +235,13 @@ impl WasmBuilder { /// Build the WASM binary. pub fn build(mut self) { - let target = crate::runtime_target(); + let Some(target) = RuntimeTarget::new() else { + build_helper::warning!( + "RUNTIME_TARGET environment variable must be set to either \"wasm\" or \"riscv\"" + ); + std::process::exit(1); + }; + if target == RuntimeTarget::Wasm { if self.export_heap_base { self.rust_flags.push("-Clink-arg=--export=__heap_base".into()); diff --git a/substrate/utils/wasm-builder/src/lib.rs b/substrate/utils/wasm-builder/src/lib.rs index 420ecd63e1dc..5e25ca39c43c 100644 --- a/substrate/utils/wasm-builder/src/lib.rs +++ b/substrate/utils/wasm-builder/src/lib.rs @@ -112,7 +112,6 @@ //! wasm32-unknown-unknown --toolchain nightly-2020-02-20`. use std::{ - collections::BTreeSet, env, fs, io::BufRead, path::{Path, PathBuf}, @@ -254,26 +253,22 @@ struct CargoCommand { program: String, args: Vec, version: Option, - target_list: Option>, } impl CargoCommand { fn new(program: &str) -> Self { let version = Self::extract_version(program, &[]); - let target_list = Self::extract_target_list(program, &[]); - CargoCommand { program: program.into(), args: Vec::new(), version, target_list } + CargoCommand { program: program.into(), args: Vec::new(), version } } fn new_with_args(program: &str, args: &[&str]) -> Self { let version = Self::extract_version(program, args); - let target_list = Self::extract_target_list(program, args); CargoCommand { program: program.into(), args: args.iter().map(ToString::to_string).collect(), version, - target_list, } } @@ -294,23 +289,6 @@ impl CargoCommand { Version::extract(&version) } - fn extract_target_list(program: &str, args: &[&str]) -> Option> { - // This is technically an unstable option, but we don't care because we only need this - // to build RISC-V runtimes, and those currently require a specific nightly toolchain - // anyway, so it's totally fine for this to fail in other cases. - let list = Command::new(program) - .args(args) - .args(&["rustc", "-Z", "unstable-options", "--print", "target-list"]) - // Make sure if we're called from within a `build.rs` the host toolchain won't override - // a rustup toolchain we've picked. - .env_remove("RUSTC") - .output() - .ok() - .and_then(|o| String::from_utf8(o.stdout).ok())?; - - Some(list.trim().split("\n").map(ToString::to_string).collect()) - } - /// Returns the version of this cargo command or `None` if it failed to extract the version. fn version(&self) -> Option { self.version @@ -326,19 +304,10 @@ impl CargoCommand { fn supports_substrate_runtime_env(&self, target: RuntimeTarget) -> bool { match target { RuntimeTarget::Wasm => self.supports_substrate_runtime_env_wasm(), - RuntimeTarget::Riscv => self.supports_substrate_runtime_env_riscv(), + RuntimeTarget::Riscv => true, } } - /// Check if the supplied cargo command supports our RISC-V runtime environment. - fn supports_substrate_runtime_env_riscv(&self) -> bool { - let Some(target_list) = self.target_list.as_ref() else { return false }; - // This is our custom target which currently doesn't exist on any upstream toolchain, - // so if it exists it's guaranteed to be our custom toolchain and have have everything - // we need, so any further version checks are unnecessary at this point. - target_list.contains("riscv32ema-unknown-none-elf") - } - /// Check if the supplied cargo command supports our Substrate wasm environment. /// /// This means that either the cargo version is at minimum 1.68.0 or this is a nightly cargo. @@ -411,7 +380,7 @@ fn get_bool_environment_variable(name: &str) -> Option { /// Returns whether we need to also compile the standard library when compiling the runtime. fn build_std_required() -> bool { - let default = runtime_target() == RuntimeTarget::Wasm; + let default = RuntimeTarget::new() != None; crate::get_bool_environment_variable(crate::WASM_BUILD_STD).unwrap_or(default) } @@ -423,13 +392,30 @@ enum RuntimeTarget { } impl RuntimeTarget { - fn rustc_target(self) -> &'static str { - match self { - RuntimeTarget::Wasm => "wasm32-unknown-unknown", - RuntimeTarget::Riscv => "riscv32ema-unknown-none-elf", + /// Creates a new instance. + fn new() -> Option { + let Some(value) = env::var_os(RUNTIME_TARGET) else { + return Some(Self::Wasm); + }; + if value == "wasm" { + Some(Self::Wasm) + } else if value == "riscv" { + Some(Self::Riscv) + } else { + None } } + /// Figures out the target parameter value for rustc. For the PolkaVM custom targets, apply the + /// full path to the JSON file. + fn value(self) -> String { + if self == RuntimeTarget::Wasm { + return "wasm32-unknown-unknown".to_string(); + } + let path: &'static str = env!("CARGO_MANIFEST_DIR"); + format!("{path}/riscv32emac-unknown-none-polkavm.json") + } + fn build_subdirectory(self) -> &'static str { // Keep the build directories separate so that when switching between // the targets we won't trigger unnecessary rebuilds. @@ -439,20 +425,3 @@ impl RuntimeTarget { } } } - -fn runtime_target() -> RuntimeTarget { - let Some(value) = env::var_os(RUNTIME_TARGET) else { - return RuntimeTarget::Wasm; - }; - - if value == "wasm" { - RuntimeTarget::Wasm - } else if value == "riscv" { - RuntimeTarget::Riscv - } else { - build_helper::warning!( - "the '{RUNTIME_TARGET}' environment variable has an invalid value; it must be either 'wasm' or 'riscv'" - ); - std::process::exit(1); - } -} diff --git a/substrate/utils/wasm-builder/src/prerequisites.rs b/substrate/utils/wasm-builder/src/prerequisites.rs index 4de6b87f618d..e2b436397e80 100644 --- a/substrate/utils/wasm-builder/src/prerequisites.rs +++ b/substrate/utils/wasm-builder/src/prerequisites.rs @@ -115,7 +115,7 @@ impl<'a> DummyCrate<'a> { // by accident - it can happen in some CI environments. cmd.current_dir(&self.temp); cmd.arg(subcommand) - .arg(format!("--target={}", self.target.rustc_target())) + .arg(format!("--target={}", self.target.value())) .args(&["--manifest-path", &self.manifest_path.display().to_string()]); if super::color_output_enabled() { diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index 26edd2ea1f22..5801cff244f3 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -852,7 +852,7 @@ fn build_bloaty_blob( build_cmd .arg("rustc") - .arg(format!("--target={}", target.rustc_target())) + .arg(format!("--target={}", target.value())) .arg(format!("--manifest-path={}", manifest_path.display())) .env("RUSTFLAGS", rustflags) // Manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir @@ -910,7 +910,10 @@ fn build_bloaty_blob( if crate::build_std_required() { // Unfortunately this is still a nightly-only flag, but FWIW it is pretty widely used // so it's unlikely to break without a replacement. - build_cmd.arg("-Z").arg("build-std"); + match target { + RuntimeTarget::Wasm => build_cmd.arg("-Z").arg("build-std"), + RuntimeTarget::Riscv => build_cmd.arg("-Z").arg("build-std=core,alloc") + }; if !cargo_cmd.supports_nightly_features() { build_cmd.env("RUSTC_BOOTSTRAP", "1"); } @@ -932,10 +935,8 @@ fn build_bloaty_blob( } let blob_name = get_blob_name(target, &manifest_path); - let target_directory = project - .join("target") - .join(target.rustc_target()) - .join(blob_build_profile.directory()); + let target_directory = + project.join("target").join(target.value()).join(blob_build_profile.directory()); match target { RuntimeTarget::Riscv => { let elf_path = target_directory.join(&blob_name);