Initial support for building RISC-V runtimes targeting PolkaVM (#3179)

This PR adds initial support for building RISC-V runtimes targeting
PolkaVM.

- Setting the `SUBSTRATE_RUNTIME_TARGET=riscv` environment variable will
now build a RISC-V runtime instead of a WASM runtime.
- This only adds support for *building* runtimes; running them will need
a PolkaVM-based executor, which I will add in a future PR.
- Only building the minimal runtime is supported (building the Polkadot
runtime doesn't work *yet* due to one of the dependencies).
- The builder now sets a `substrate_runtime` cfg flag when building the
runtimes, with the idea being that instead of doing `#[cfg(not(feature =
"std"))]` or `#[cfg(target_arch = "wasm32")]` to detect that we're
building a runtime you'll do `#[cfg(substrate_runtime)]`. (Switching the
whole codebase to use this will be done in a future PR; I deliberately
didn't do this here to keep this PR minimal and reviewable.)
- Further renaming of things (e.g. types, environment variables and proc
macro attributes having "wasm" in their name) to be target-agnostic will
also be done in a future refactoring PR (while keeping backwards
compatibility where it makes sense; I don't intend to break anyone's
workflow or create unnecessary churn).
- This PR also fixes two bugs in the `wasm-builder` crate:
* The `RUSTC` environment variable is now removed when invoking the
compiler. This prevents the toolchain version from being overridden when
called from a `build.rs` script.
* When parsing the `rustup toolchain list` output the `(default)` is now
properly stripped and not treated as part of the version.
- I've also added a minimal CI job that makes sure this doesn't break in
the future. (cc @paritytech/ci)

cc @athei

------

Also, just a fun little tidbit: quickly comparing the size of the built
runtimes it seems that the PolkaVM runtime is slightly smaller than the
WASM one. (`production` build, with the `names` section substracted from
the WASM's size to keep things fair, since for the PolkaVM runtime we're
currently stripping out everything)

- `.wasm`: 625505 bytes
- `.wasm` (after wasm-opt -O3): 563205 bytes
- `.wasm` (after wasm-opt -Os): 562987 bytes
- `.wasm` (after wasm-opt -Oz): 536852 bytes
- `.polkavm`: ~~580338 bytes~~ 550476 bytes (after enabling extra target
features; I'll add those in another PR once we have an executor working)

---------

Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Koute
2024-02-03 13:12:12 +09:00
committed by GitHub
parent 41db45a281
commit e349fc9ef8
17 changed files with 584 additions and 176 deletions
+29 -4
View File
@@ -21,6 +21,8 @@ use std::{
process,
};
use crate::RuntimeTarget;
/// Returns the manifest dir from the `CARGO_MANIFEST_DIR` env.
fn get_manifest_dir() -> PathBuf {
env::var("CARGO_MANIFEST_DIR")
@@ -49,6 +51,8 @@ impl WasmBuilderSelectProject {
project_cargo_toml: get_manifest_dir().join("Cargo.toml"),
features_to_enable: Vec::new(),
disable_runtime_version_section_check: false,
export_heap_base: false,
import_memory: false,
}
}
@@ -65,6 +69,8 @@ impl WasmBuilderSelectProject {
project_cargo_toml: path,
features_to_enable: Vec::new(),
disable_runtime_version_section_check: false,
export_heap_base: false,
import_memory: false,
})
} else {
Err("Project path must point to the `Cargo.toml` of the project")
@@ -97,6 +103,11 @@ pub struct WasmBuilder {
features_to_enable: Vec<String>,
/// Should the builder not check that the `runtime_version` section exists in the wasm binary?
disable_runtime_version_section_check: bool,
/// Whether `__heap_base` should be exported (WASM-only).
export_heap_base: bool,
/// Whether `--import-memory` should be added to the link args (WASM-only).
import_memory: bool,
}
impl WasmBuilder {
@@ -109,7 +120,7 @@ impl WasmBuilder {
///
/// This adds `-Clink-arg=--export=__heap_base` to `RUST_FLAGS`.
pub fn export_heap_base(mut self) -> Self {
self.rust_flags.push("-Clink-arg=--export=__heap_base".into());
self.export_heap_base = true;
self
}
@@ -127,7 +138,7 @@ impl WasmBuilder {
///
/// This adds `-C link-arg=--import-memory` to `RUST_FLAGS`.
pub fn import_memory(mut self) -> Self {
self.rust_flags.push("-C link-arg=--import-memory".into());
self.import_memory = true;
self
}
@@ -159,7 +170,18 @@ impl WasmBuilder {
}
/// Build the WASM binary.
pub fn build(self) {
pub fn build(mut self) {
let target = crate::runtime_target();
if target == RuntimeTarget::Wasm {
if self.export_heap_base {
self.rust_flags.push("-Clink-arg=--export=__heap_base".into());
}
if self.import_memory {
self.rust_flags.push("-C link-arg=--import-memory".into());
}
}
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` is set by cargo!"));
let file_path =
out_dir.join(self.file_name.clone().unwrap_or_else(|| "wasm_binary.rs".into()));
@@ -175,6 +197,7 @@ impl WasmBuilder {
}
build_project(
target,
file_path,
self.project_cargo_toml,
self.rust_flags.into_iter().map(|f| format!("{} ", f)).collect(),
@@ -248,6 +271,7 @@ fn generate_rerun_if_changed_instructions() {
/// `check_for_runtime_version_section` - Should the wasm binary be checked for the
/// `runtime_version` section?
fn build_project(
target: RuntimeTarget,
file_name: PathBuf,
project_cargo_toml: PathBuf,
default_rustflags: String,
@@ -255,7 +279,7 @@ fn build_project(
wasm_binary_name: Option<String>,
check_for_runtime_version_section: bool,
) {
let cargo_cmd = match crate::prerequisites::check() {
let cargo_cmd = match crate::prerequisites::check(target) {
Ok(cmd) => cmd,
Err(err_msg) => {
eprintln!("{}", err_msg);
@@ -264,6 +288,7 @@ fn build_project(
};
let (wasm_binary, bloaty) = crate::wasm_project::create_and_compile(
target,
&project_cargo_toml,
&default_rustflags,
cargo_cmd,