Skip to content

Commit

Permalink
wasm-builder: Use riscv32emac-unknown-none-polkavm.json target (#6419)
Browse files Browse the repository at this point in the history
# Description

Closes #6335.

## Integration

N/A

## Review Notes

`RuntimeTarget` is converted to return path to the custom target JSON
file

---------

Signed-off-by: Jarkko Sakkinen <jarkko@parity.io>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
Co-authored-by: Koute <koute@users.noreply.github.com>
  • Loading branch information
3 people authored Dec 4, 2024
1 parent 2779043 commit 82117ad
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 84 deletions.
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1090,8 +1090,8 @@ polkadot-test-client = { path = "polkadot/node/test/client" }
polkadot-test-runtime = { path = "polkadot/runtime/test-runtime" }
polkadot-test-service = { path = "polkadot/node/test/service" }
polkavm = { version = "0.9.3", default-features = false }
polkavm-derive = "0.9.1"
polkavm-linker = "0.9.2"
polkavm-derive = "0.17.0"
polkavm-linker = "0.17.1"
portpicker = { version = "0.1.1" }
pretty_assertions = { version = "1.3.0" }
primitive-types = { version = "0.13.1", default-features = false, features = [
Expand Down
12 changes: 12 additions & 0 deletions prdoc/pr_6419.prdoc
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion substrate/utils/wasm-builder/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ impl WasmBuilder {

/// Build the WASM binary.
pub fn build(mut self) {
let target = crate::runtime_target();
let target = RuntimeTarget::new();

if target == RuntimeTarget::Wasm {
if self.export_heap_base {
self.rust_flags.push("-Clink-arg=--export=__heap_base".into());
Expand Down
105 changes: 43 additions & 62 deletions substrate/utils/wasm-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@
//! wasm32-unknown-unknown --toolchain nightly-2020-02-20`.
use std::{
collections::BTreeSet,
env, fs,
io::BufRead,
path::{Path, PathBuf},
Expand Down Expand Up @@ -254,26 +253,22 @@ struct CargoCommand {
program: String,
args: Vec<String>,
version: Option<Version>,
target_list: Option<BTreeSet<String>>,
}

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,
}
}

Expand All @@ -294,23 +289,6 @@ impl CargoCommand {
Version::extract(&version)
}

fn extract_target_list(program: &str, args: &[&str]) -> Option<BTreeSet<String>> {
// 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<Version> {
self.version
Expand All @@ -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.
Expand Down Expand Up @@ -409,50 +378,62 @@ fn get_bool_environment_variable(name: &str) -> Option<bool> {
}
}

/// 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;

crate::get_bool_environment_variable(crate::WASM_BUILD_STD).unwrap_or(default)
}

#[derive(Copy, Clone, PartialEq, Eq)]
enum RuntimeTarget {
Wasm,
Riscv,
}

impl RuntimeTarget {
fn rustc_target(self) -> &'static str {
/// Creates a new instance.
fn new() -> Self {
let Some(value) = env::var_os(RUNTIME_TARGET) else {
return Self::Wasm;
};

if value == "wasm" {
Self::Wasm
} else if value == "riscv" {
Self::Riscv
} else {
build_helper::warning!(
"RUNTIME_TARGET environment variable must be set to either \"wasm\" or \"riscv\""
);
std::process::exit(1);
}
}

/// Figures out the target parameter value for rustc.
fn rustc_target(self) -> String {
match self {
RuntimeTarget::Wasm => "wasm32-unknown-unknown",
RuntimeTarget::Riscv => "riscv32ema-unknown-none-elf",
RuntimeTarget::Wasm => "wasm32-unknown-unknown".to_string(),
RuntimeTarget::Riscv => {
let path = polkavm_linker::target_json_32_path().expect("riscv not found");
path.into_os_string().into_string().unwrap()
},
}
}

fn build_subdirectory(self) -> &'static str {
// Keep the build directories separate so that when switching between
// the targets we won't trigger unnecessary rebuilds.
/// Figures out the target directory name used by cargo.
fn rustc_target_dir(self) -> &'static str {
match self {
RuntimeTarget::Wasm => "wbuild",
RuntimeTarget::Riscv => "rbuild",
RuntimeTarget::Wasm => "wasm32-unknown-unknown",
RuntimeTarget::Riscv => "riscv32emac-unknown-none-polkavm",
}
}
}

fn runtime_target() -> RuntimeTarget {
let Some(value) = env::var_os(RUNTIME_TARGET) else {
return RuntimeTarget::Wasm;
};
/// 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) {
return None;
}

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

Some(arg)
}
}
7 changes: 5 additions & 2 deletions substrate/utils/wasm-builder/src/prerequisites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,14 @@ fn check_wasm_toolchain_installed(
error,
colorize_aux_message(&"-".repeat(60)),
))
}
};
}

let version = dummy_crate.get_rustc_version();
if crate::build_std_required() {

let target = RuntimeTarget::new();
assert!(target == RuntimeTarget::Wasm);
if target.rustc_target_build_std().is_some() {
if let Some(sysroot) = dummy_crate.get_sysroot() {
let src_path =
Path::new(sysroot.trim()).join("lib").join("rustlib").join("src").join("rust");
Expand Down
28 changes: 17 additions & 11 deletions substrate/utils/wasm-builder/src/wasm_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ fn crate_metadata(cargo_manifest: &Path) -> Metadata {
crate_metadata
}

/// Keep the build directories separate so that when switching between the
/// targets we won't trigger unnecessary rebuilds.
fn build_subdirectory(target: RuntimeTarget) -> &'static str {
match target {
RuntimeTarget::Wasm => "wbuild",
RuntimeTarget::Riscv => "rbuild",
}
}

/// Creates the WASM project, compiles the WASM binary and compacts the WASM binary.
///
/// # Returns
Expand All @@ -125,7 +134,7 @@ pub(crate) fn create_and_compile(
#[cfg(feature = "metadata-hash")] enable_metadata_hash: Option<MetadataExtraInfo>,
) -> (Option<WasmBinary>, WasmBinaryBloaty) {
let runtime_workspace_root = get_wasm_workspace_root();
let runtime_workspace = runtime_workspace_root.join(target.build_subdirectory());
let runtime_workspace = runtime_workspace_root.join(build_subdirectory(target));

let crate_metadata = crate_metadata(orig_project_cargo_toml);

Expand Down Expand Up @@ -770,7 +779,7 @@ impl BuildConfiguration {
.collect::<Vec<_>>()
.iter()
.rev()
.take_while(|c| c.as_os_str() != target.build_subdirectory())
.take_while(|c| c.as_os_str() != build_subdirectory(target))
.last()
.expect("We put the runtime project within a `target/.../[rw]build` path; qed")
.as_os_str()
Expand Down Expand Up @@ -841,9 +850,7 @@ fn build_bloaty_blob(
"-C target-cpu=mvp -C target-feature=-sign-ext -C link-arg=--export-table ",
);
},
RuntimeTarget::Riscv => {
rustflags.push_str("-C target-feature=+lui-addi-fusion -C relocation-model=pie -C link-arg=--emit-relocs -C link-arg=--unique ");
},
RuntimeTarget::Riscv => (),
}

rustflags.push_str(default_rustflags);
Expand Down Expand Up @@ -907,10 +914,9 @@ fn build_bloaty_blob(
//
// So here we force the compiler to also compile the standard library crates for us
// to make sure that they also only use the MVP features.
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");
if let Some(arg) = target.rustc_target_build_std() {
build_cmd.arg("-Z").arg(arg);

if !cargo_cmd.supports_nightly_features() {
build_cmd.env("RUSTC_BOOTSTRAP", "1");
}
Expand All @@ -934,7 +940,7 @@ fn build_bloaty_blob(
let blob_name = get_blob_name(target, &manifest_path);
let target_directory = project
.join("target")
.join(target.rustc_target())
.join(target.rustc_target_dir())
.join(blob_build_profile.directory());
match target {
RuntimeTarget::Riscv => {
Expand Down Expand Up @@ -968,7 +974,7 @@ fn build_bloaty_blob(
},
};

std::fs::write(&polkavm_path, program.as_bytes())
std::fs::write(&polkavm_path, program)
.expect("writing the blob to a file always works");
}

Expand Down

0 comments on commit 82117ad

Please sign in to comment.