Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
78c5f4c
feat(wasm-builder): add support for new `wasm32v1-none` target
StackOverflowExcept1on Dec 27, 2024
dcfbeb7
fix typo
StackOverflowExcept1on Dec 27, 2024
03714a0
trying to fix CI
StackOverflowExcept1on Dec 27, 2024
2410530
Merge branch 'master' into wasm32v1-none
StackOverflowExcept1on Dec 27, 2024
575d805
Update prdoc/pr_7008.prdoc
bkchr Dec 30, 2024
8fffe18
Merge branch 'master' into wasm32v1-none
bkchr Jan 2, 2025
ce0fb1d
Merge branch 'master' into wasm32v1-none
bkchr Jan 6, 2025
3d26ce9
Merge branch 'master' into wasm32v1-none
bkchr Jan 8, 2025
4c3b0ea
git apply patch from CI
StackOverflowExcept1on Jan 8, 2025
486be73
Revert "git apply patch from CI"
StackOverflowExcept1on Jan 8, 2025
21245bc
just changle location of substrate-wasm-builder
StackOverflowExcept1on Jan 9, 2025
d044efc
Merge branch 'master' into wasm32v1-none
bkchr Jan 9, 2025
1f34087
Fix umbrella script
bkchr Jan 9, 2025
8ae5e7b
Update prdoc/pr_7008.prdoc
bkchr Jan 10, 2025
f154742
add sp-consensus-beefy bump patch to prdoc
StackOverflowExcept1on Jan 10, 2025
6bfea51
use wasm32v1-none target only if installed
StackOverflowExcept1on Jan 13, 2025
5838f1e
Merge remote-tracking branch 'origin/master' into wasm32v1-none
StackOverflowExcept1on Jan 13, 2025
b21ffdf
Merge branch 'master' into wasm32v1-none
StackOverflowExcept1on Jan 16, 2025
3628105
resolve conversations
StackOverflowExcept1on Jan 18, 2025
a804037
Merge remote-tracking branch 'origin/master' into wasm32v1-none
StackOverflowExcept1on Jan 18, 2025
d8b1363
Merge branch 'master' into wasm32v1-none
StackOverflowExcept1on Jan 23, 2025
929e755
Merge branch 'master' into wasm32v1-none
StackOverflowExcept1on Jan 25, 2025
94e1fd1
Merge remote-tracking branch 'origin/master' into wasm32v1-none
StackOverflowExcept1on Jan 30, 2025
f5fa789
move `is_target_installed` method to `DummyCrate`
StackOverflowExcept1on Jan 30, 2025
6c058a9
Merge branch 'master' into wasm32v1-none
StackOverflowExcept1on Feb 4, 2025
3bab473
Merge branch 'master' into wasm32v1-none
StackOverflowExcept1on Feb 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions prdoc/pr_7008.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 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: 'feat(wasm-builder): add support for new `wasm32v1-none` target'
doc:
- audience: Runtime Dev
description: |
Resolves [#5777](https://github.com/paritytech/polkadot-sdk/issues/5777)

Previously `wasm-builder` used hacks such as `-Zbuild-std` (required `rust-src` component) and `RUSTC_BOOTSTRAP=1` to build WASM runtime without WASM features: `sign-ext`, `multivalue` and `reference-types`, but since Rust 1.84 (will be stable on 9 January, 2025) the situation has improved as there is new [`wasm32v1-none`](https://doc.rust-lang.org/beta/rustc/platform-support/wasm32v1-none.html) target that disables all "post-MVP" WASM features except `mutable-globals`.

Wasm builder requires the following prerequisites for building the WASM binary:
- Rust >= 1.68 and Rust < 1.84:
- `wasm32-unknown-unknown` target
- `rust-src` component
- Rust >= 1.84:
- `wasm32v1-none` target
- no more `-Zbuild-std` and `RUSTC_BOOTSTRAP=1` hacks and `rust-src` component requirements!

crates:
- name: substrate-wasm-builder
bump: minor
validate: false
- name: sp-consensus-beefy
bump: patch
14 changes: 10 additions & 4 deletions scripts/generate-umbrella.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,17 @@ def main(path, version):

# No search for a no_std attribute:
with open(lib_path, "r") as f:
content = f.read()
if "#![no_std]" in content or '#![cfg_attr(not(feature = "std"), no_std)]' in content:
nostd_crate = False
for line in f:
line = line.strip()
if line == "#![no_std]" or line == '#![cfg_attr(not(feature = "std"), no_std)]':
nostd_crate = True
break
elif "no_std" in line:
print(line)

if nostd_crate:
nostd_crates.append((crate, path))
elif 'no_std' in content:
raise Exception(f"Found 'no_std' in {lib_path} without knowing how to handle it")
else:
std_crates.append((crate, path))

Expand Down
8 changes: 4 additions & 4 deletions substrate/utils/wasm-builder/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl WasmBuilder {

/// Enable exporting `__heap_base` as global variable in the WASM binary.
///
/// This adds `-Clink-arg=--export=__heap_base` to `RUST_FLAGS`.
/// This adds `-C link-arg=--export=__heap_base` to `RUST_FLAGS`.
pub fn export_heap_base(mut self) -> Self {
self.export_heap_base = true;
self
Expand Down Expand Up @@ -239,7 +239,7 @@ impl WasmBuilder {

if target == RuntimeTarget::Wasm {
if self.export_heap_base {
self.rust_flags.push("-Clink-arg=--export=__heap_base".into());
self.rust_flags.push("-C link-arg=--export=__heap_base".into());
}

if self.import_memory {
Expand All @@ -265,7 +265,7 @@ impl WasmBuilder {
target,
file_path,
self.project_cargo_toml,
self.rust_flags.into_iter().map(|f| format!("{} ", f)).collect(),
self.rust_flags.join(" "),
self.features_to_enable,
self.file_name,
!self.disable_runtime_version_section_check,
Expand Down Expand Up @@ -353,7 +353,7 @@ fn build_project(
let cargo_cmd = match crate::prerequisites::check(target) {
Ok(cmd) => cmd,
Err(err_msg) => {
eprintln!("{}", err_msg);
eprintln!("{err_msg}");
process::exit(1);
},
};
Expand Down
99 changes: 70 additions & 29 deletions substrate/utils/wasm-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
//!
//! By using environment variables, you can configure which Wasm binaries are built and how:
//!
//! - `SUBSTRATE_RUNTIME_TARGET` - Sets the target for building runtime. Supported values are `wasm`
//! or `riscv` (experimental, do not use it in production!). By default the target is equal to
//! `wasm`.
//! - `SKIP_WASM_BUILD` - Skips building any Wasm binary. This is useful when only native should be
//! recompiled. If this is the first run and there doesn't exist a Wasm binary, this will set both
//! variables to `None`.
Expand All @@ -78,14 +81,15 @@
//! - `WASM_TARGET_DIRECTORY` - Will copy any build Wasm binary to the given directory. The path
//! needs to be absolute.
//! - `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The
//! format needs to be the same as used by cargo, e.g. `nightly-2020-02-20`.
//! format needs to be the same as used by cargo, e.g. `nightly-2024-12-26`.
//! - `WASM_BUILD_WORKSPACE_HINT` - Hint the workspace that is being built. This is normally not
//! required as we walk up from the target directory until we find a `Cargo.toml`. If the target
//! directory is changed for the build, this environment variable can be used to point to the
//! actual workspace.
//! - `WASM_BUILD_STD` - Sets whether the Rust's standard library crates will also be built. This is
//! necessary to make sure the standard library crates only use the exact WASM feature set that
//! our executor supports. Enabled by default.
//! - `WASM_BUILD_STD` - Sets whether the Rust's standard library crates (`core` and `alloc`) will
//! also be built. This is necessary to make sure the standard library crates only use the exact
//! WASM feature set that our executor supports. Enabled by default for RISC-V target and WASM
//! target (but only if Rust < 1.84). Disabled by default for WASM target and Rust >= 1.84.
//! - `WASM_BUILD_CARGO_ARGS` - This can take a string as space separated list of `cargo` arguments.
//! It was added specifically for the use case of enabling JSON diagnostic messages during the
//! build phase, to be used by IDEs that parse them, but it might be useful for other cases too.
Expand All @@ -99,18 +103,21 @@
//! ## Prerequisites:
//!
//! Wasm builder requires the following prerequisites for building the Wasm binary:
//! - Rust >= 1.68 and Rust < 1.84:
//! - `wasm32-unknown-unknown` target
//! - `rust-src` component
//! - Rust >= 1.84:
//! - `wasm32v1-none` target
//!
//! - rust nightly + `wasm32-unknown-unknown` toolchain
//!
//! or
//!
//! - rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` toolchain
//!
//! If a specific rust is installed with `rustup`, it is important that the wasm target is
//! installed as well. For example if installing the rust from 20.02.2020 using `rustup
//! install nightly-2020-02-20`, the wasm target needs to be installed as well `rustup target add
//! wasm32-unknown-unknown --toolchain nightly-2020-02-20`.

//! If a specific Rust is installed with `rustup`, it is important that the WASM
//! target is installed as well. For example if installing the Rust from
//! 26.12.2024 using `rustup install nightly-2024-12-26`, the WASM target
//! (`wasm32-unknown-unknown` or `wasm32v1-none`) needs to be installed as well
//! `rustup target add wasm32-unknown-unknown --toolchain nightly-2024-12-26`.
//! To install the `rust-src` component, use `rustup component add rust-src
//! --toolchain nightly-2024-12-26`.

use prerequisites::DummyCrate;
use std::{
env, fs,
io::BufRead,
Expand Down Expand Up @@ -162,7 +169,7 @@ const FORCE_WASM_BUILD_ENV: &str = "FORCE_WASM_BUILD";
/// Environment variable that hints the workspace we are building.
const WASM_BUILD_WORKSPACE_HINT: &str = "WASM_BUILD_WORKSPACE_HINT";

/// Environment variable to set whether we'll build `core`/`std`.
/// Environment variable to set whether we'll build `core`/`alloc`.
const WASM_BUILD_STD: &str = "WASM_BUILD_STD";

/// Environment variable to set additional cargo arguments that might be useful
Expand Down Expand Up @@ -327,6 +334,27 @@ impl CargoCommand {
// Check if major and minor are greater or equal than 1.68 or this is a nightly.
version.major > 1 || (version.major == 1 && version.minor >= 68) || version.is_nightly
}

/// Returns whether this version of the toolchain supports the `wasm32v1-none` target.
fn supports_wasm32v1_none_target(&self) -> bool {
self.version.map_or(false, |version| {
// Check if major and minor are greater or equal than 1.84.
version.major > 1 || (version.major == 1 && version.minor >= 84)
})
}

/// Returns whether the `wasm32v1-none` target is installed in this version of the toolchain.
fn is_wasm32v1_none_target_installed(&self) -> bool {
let dummy_crate = DummyCrate::new(self, RuntimeTarget::Wasm, true);
dummy_crate.is_target_installed("wasm32v1-none").unwrap_or(false)
}

/// Returns whether the `wasm32v1-none` target is available in this version of the toolchain.
fn is_wasm32v1_none_target_available(&self) -> bool {
// Check if major and minor are greater or equal than 1.84 and that the `wasm32v1-none`
// target is installed for this toolchain.
self.supports_wasm32v1_none_target() && self.is_wasm32v1_none_target_installed()
}
}

/// Wraps a [`CargoCommand`] and the version of `rustc` the cargo command uses.
Expand Down Expand Up @@ -371,8 +399,7 @@ fn get_bool_environment_variable(name: &str) -> Option<bool> {
Some(false)
} else {
build_helper::warning!(
"the '{}' environment variable has an invalid value; it must be either '1' or '0'",
name
"the '{name}' environment variable has an invalid value; it must be either '1' or '0'",
);
std::process::exit(1);
}
Expand Down Expand Up @@ -404,9 +431,14 @@ impl RuntimeTarget {
}

/// Figures out the target parameter value for rustc.
fn rustc_target(self) -> String {
fn rustc_target(self, cargo_command: &CargoCommand) -> String {
match self {
RuntimeTarget::Wasm => "wasm32-unknown-unknown".to_string(),
RuntimeTarget::Wasm =>
if cargo_command.is_wasm32v1_none_target_available() {
"wasm32v1-none".into()
} else {
"wasm32-unknown-unknown".into()
},
RuntimeTarget::Riscv => {
let path = polkavm_linker::target_json_32_path().expect("riscv not found");
path.into_os_string().into_string().unwrap()
Expand All @@ -415,25 +447,34 @@ impl RuntimeTarget {
}

/// Figures out the target directory name used by cargo.
fn rustc_target_dir(self) -> &'static str {
fn rustc_target_dir(self, cargo_command: &CargoCommand) -> &'static str {
match self {
RuntimeTarget::Wasm => "wasm32-unknown-unknown",
RuntimeTarget::Wasm =>
if cargo_command.is_wasm32v1_none_target_available() {
"wasm32v1-none".into()
} else {
"wasm32-unknown-unknown".into()
},
RuntimeTarget::Riscv => "riscv32emac-unknown-none-polkavm",
}
}

/// Figures out the build-std argument.
fn rustc_target_build_std(self) -> Option<&'static str> {
if !crate::get_bool_environment_variable(crate::WASM_BUILD_STD).unwrap_or(true) {
fn rustc_target_build_std(self, cargo_command: &CargoCommand) -> Option<&'static str> {
if !crate::get_bool_environment_variable(crate::WASM_BUILD_STD).unwrap_or_else(
|| match self {
RuntimeTarget::Wasm => !cargo_command.is_wasm32v1_none_target_available(),
RuntimeTarget::Riscv => true,
},
) {
return None;
}

// This is a nightly-only flag.
let arg = match self {
RuntimeTarget::Wasm => "build-std",
RuntimeTarget::Riscv => "build-std=core,alloc",
};

Some(arg)
// We only build `core` and `alloc` crates since wasm-builder disables `std` featue for
// runtime. Thus the runtime is `#![no_std]` crate.

Some("build-std=core,alloc")
}
}
Loading
Loading