mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 22:51:13 +00:00
Build the standard library crates when building the runtimes (#2217)
Our executor currently only supports the WASM MVP feature set, however nowadays when compiling WASM the Rust compiler has more features enabled by default. We do set the `-C target-cpu=mvp` flag to make sure that *our* code gets compiled in a way that is compatible with our executor, however this doesn't affect Rust's standard library crates (`std`, `core` and `alloc`) which are by default precompiled and still can make use of these extra features. So in this PR we force the compiler to also compile the standard library crates for us to make sure that they also only use the MVP features. I've added the `WASM_BUILD_STD` environment variable which can be used to disable this behavior if set to `0`. Unfortunately this *will* slow down the compile times when building runtimes, but there isn't much that we can do about that. Fixes https://github.com/paritytech/polkadot-sdk/issues/1755 --------- Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
@@ -47,14 +47,11 @@ pub(crate) fn check() -> Result<CargoCommandVersioned, String> {
|
||||
check_wasm_toolchain_installed(cargo_command)
|
||||
}
|
||||
|
||||
/// Create the project that will be used to check that the wasm toolchain is installed and to
|
||||
/// extract the rustc version.
|
||||
fn create_check_toolchain_project(project_dir: &Path) {
|
||||
let lib_rs_file = project_dir.join("src/lib.rs");
|
||||
let main_rs_file = project_dir.join("src/main.rs");
|
||||
let build_rs_file = project_dir.join("build.rs");
|
||||
let manifest_path = project_dir.join("Cargo.toml");
|
||||
/// Creates a minimal dummy crate at the given path and returns the manifest path.
|
||||
fn create_minimal_crate(project_dir: &Path) -> std::path::PathBuf {
|
||||
fs::create_dir_all(project_dir.join("src")).expect("Creating src dir does not fail; qed");
|
||||
|
||||
let manifest_path = project_dir.join("Cargo.toml");
|
||||
write_file_if_changed(
|
||||
&manifest_path,
|
||||
r#"
|
||||
@@ -62,120 +59,99 @@ fn create_check_toolchain_project(project_dir: &Path) {
|
||||
name = "wasm-test"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
[lib]
|
||||
name = "wasm_test"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[workspace]
|
||||
"#,
|
||||
);
|
||||
write_file_if_changed(lib_rs_file, "pub fn test() {}");
|
||||
|
||||
// We want to know the rustc version of the rustc that is being used by our cargo command.
|
||||
// The cargo command is determined by some *very* complex algorithm to find the cargo command
|
||||
// that supports nightly.
|
||||
// The best solution would be if there is a `cargo rustc --version` command, which sadly
|
||||
// doesn't exists. So, the only available way of getting the rustc version is to build a project
|
||||
// and capture the rustc version in this build process. This `build.rs` is exactly doing this.
|
||||
// It gets the rustc version by calling `rustc --version` and exposing it in the `RUSTC_VERSION`
|
||||
// environment variable.
|
||||
write_file_if_changed(
|
||||
build_rs_file,
|
||||
r#"
|
||||
fn main() {
|
||||
let rustc_cmd = std::env::var("RUSTC").ok().unwrap_or_else(|| "rustc".into());
|
||||
|
||||
let rustc_version = std::process::Command::new(rustc_cmd)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|o| String::from_utf8(o.stdout).ok());
|
||||
|
||||
println!(
|
||||
"cargo:rustc-env=RUSTC_VERSION={}",
|
||||
rustc_version.unwrap_or_else(|| "unknown rustc version".into()),
|
||||
);
|
||||
}
|
||||
"#,
|
||||
);
|
||||
// Just prints the `RURSTC_VERSION` environment variable that is being created by the
|
||||
// `build.rs` script.
|
||||
write_file_if_changed(
|
||||
main_rs_file,
|
||||
r#"
|
||||
fn main() {
|
||||
println!("{}", env!("RUSTC_VERSION"));
|
||||
}
|
||||
"#,
|
||||
);
|
||||
write_file_if_changed(project_dir.join("src/main.rs"), "fn main() {}");
|
||||
manifest_path
|
||||
}
|
||||
|
||||
fn check_wasm_toolchain_installed(
|
||||
cargo_command: CargoCommand,
|
||||
) -> Result<CargoCommandVersioned, String> {
|
||||
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");
|
||||
create_check_toolchain_project(temp.path());
|
||||
let manifest_path = create_minimal_crate(temp.path()).display().to_string();
|
||||
|
||||
let err_msg = print_error_message("Rust WASM toolchain not installed, please install it!");
|
||||
let manifest_path = temp.path().join("Cargo.toml").display().to_string();
|
||||
let prepare_command = |subcommand| {
|
||||
let mut cmd = cargo_command.command();
|
||||
// Chdir to temp to avoid including project's .cargo/config.toml
|
||||
// by accident - it can happen in some CI environments.
|
||||
cmd.current_dir(&temp);
|
||||
cmd.args(&[
|
||||
subcommand,
|
||||
"--target=wasm32-unknown-unknown",
|
||||
"--manifest-path",
|
||||
&manifest_path,
|
||||
]);
|
||||
|
||||
let mut build_cmd = cargo_command.command();
|
||||
// Chdir to temp to avoid including project's .cargo/config.toml
|
||||
// by accident - it can happen in some CI environments.
|
||||
build_cmd.current_dir(&temp);
|
||||
build_cmd.args(&[
|
||||
"build",
|
||||
"--target=wasm32-unknown-unknown",
|
||||
"--manifest-path",
|
||||
&manifest_path,
|
||||
]);
|
||||
if super::color_output_enabled() {
|
||||
cmd.arg("--color=always");
|
||||
}
|
||||
|
||||
if super::color_output_enabled() {
|
||||
build_cmd.arg("--color=always");
|
||||
// manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock
|
||||
let target_dir = temp.path().join("target").display().to_string();
|
||||
cmd.env("CARGO_TARGET_DIR", &target_dir);
|
||||
|
||||
// Make sure the host's flags aren't used here, e.g. if an alternative linker is specified
|
||||
// in the RUSTFLAGS then the check we do here will break unless we clear these.
|
||||
cmd.env_remove("CARGO_ENCODED_RUSTFLAGS");
|
||||
cmd.env_remove("RUSTFLAGS");
|
||||
cmd
|
||||
};
|
||||
|
||||
let err_msg =
|
||||
print_error_message("Rust WASM toolchain is not properly installed; please install it!");
|
||||
let build_result = prepare_command("build").output().map_err(|_| err_msg.clone())?;
|
||||
if !build_result.status.success() {
|
||||
return match String::from_utf8(build_result.stderr) {
|
||||
Ok(ref err) if err.contains("the `wasm32-unknown-unknown` target may not be installed") =>
|
||||
Err(print_error_message("Cannot compile the WASM runtime: the `wasm32-unknown-unknown` target is not installed!\n\
|
||||
You can install it with `rustup target add wasm32-unknown-unknown` if you're using `rustup`.")),
|
||||
|
||||
// Apparently this can happen when we're running on a non Tier 1 platform.
|
||||
Ok(ref err) if err.contains("linker `rust-lld` not found") =>
|
||||
Err(print_error_message("Cannot compile the WASM runtime: `rust-lld` not found!")),
|
||||
|
||||
Ok(ref err) => Err(format!(
|
||||
"{}\n\n{}\n{}\n{}{}\n",
|
||||
err_msg,
|
||||
Color::Yellow.bold().paint("Further error information:"),
|
||||
Color::Yellow.bold().paint("-".repeat(60)),
|
||||
err,
|
||||
Color::Yellow.bold().paint("-".repeat(60)),
|
||||
)),
|
||||
|
||||
Err(_) => Err(err_msg),
|
||||
};
|
||||
}
|
||||
|
||||
let mut run_cmd = cargo_command.command();
|
||||
// Chdir to temp to avoid including project's .cargo/config.toml
|
||||
// by accident - it can happen in some CI environments.
|
||||
run_cmd.current_dir(&temp);
|
||||
run_cmd.args(&["run", "--manifest-path", &manifest_path]);
|
||||
let mut run_cmd = prepare_command("rustc");
|
||||
run_cmd.args(&["-q", "--", "--version"]);
|
||||
|
||||
// manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock
|
||||
let target_dir = temp.path().join("target").display().to_string();
|
||||
build_cmd.env("CARGO_TARGET_DIR", &target_dir);
|
||||
run_cmd.env("CARGO_TARGET_DIR", &target_dir);
|
||||
let version = run_cmd
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|o| String::from_utf8(o.stdout).ok())
|
||||
.unwrap_or_else(|| "unknown rustc version".into());
|
||||
|
||||
// Make sure the host's flags aren't used here, e.g. if an alternative linker is specified
|
||||
// in the RUSTFLAGS then the check we do here will break unless we clear these.
|
||||
build_cmd.env_remove("CARGO_ENCODED_RUSTFLAGS");
|
||||
run_cmd.env_remove("CARGO_ENCODED_RUSTFLAGS");
|
||||
build_cmd.env_remove("RUSTFLAGS");
|
||||
run_cmd.env_remove("RUSTFLAGS");
|
||||
|
||||
build_cmd.output().map_err(|_| err_msg.clone()).and_then(|s| {
|
||||
if s.status.success() {
|
||||
let version = run_cmd.output().ok().and_then(|o| String::from_utf8(o.stdout).ok());
|
||||
Ok(CargoCommandVersioned::new(
|
||||
cargo_command,
|
||||
version.unwrap_or_else(|| "unknown rustc version".into()),
|
||||
))
|
||||
} else {
|
||||
match String::from_utf8(s.stderr) {
|
||||
Ok(ref err) if err.contains("linker `rust-lld` not found") =>
|
||||
Err(print_error_message("`rust-lld` not found, please install it!")),
|
||||
Ok(ref err) => Err(format!(
|
||||
"{}\n\n{}\n{}\n{}{}\n",
|
||||
err_msg,
|
||||
Color::Yellow.bold().paint("Further error information:"),
|
||||
Color::Yellow.bold().paint("-".repeat(60)),
|
||||
err,
|
||||
Color::Yellow.bold().paint("-".repeat(60)),
|
||||
)),
|
||||
Err(_) => Err(err_msg),
|
||||
if crate::build_std_required() {
|
||||
let mut sysroot_cmd = prepare_command("rustc");
|
||||
sysroot_cmd.args(&["-q", "--", "--print", "sysroot"]);
|
||||
if let Some(sysroot) =
|
||||
sysroot_cmd.output().ok().and_then(|o| String::from_utf8(o.stdout).ok())
|
||||
{
|
||||
let src_path =
|
||||
Path::new(sysroot.trim()).join("lib").join("rustlib").join("src").join("rust");
|
||||
if !src_path.exists() {
|
||||
return Err(print_error_message(
|
||||
"Cannot compile the WASM runtime: no standard library sources found!\n\
|
||||
You can install them with `rustup component add rust-src` if you're using `rustup`.",
|
||||
))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Ok(CargoCommandVersioned::new(cargo_command, version))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user