Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit ae37329

Browse files
bkchrkoute
authored andcommitted
Support stable rust for compiling the runtime (#13580)
* Support stable rust for compiling the runtime This pull request brings support for compiling the runtime with stable Rust. This requires at least rust 1.68.0 to work on stable. The code is written in a way that it is backwards compatible and should automatically work when someone compiles with 1.68.0+ stable. * We always support nightlies! * 🤦 * Sort by version * Review feedback * Review feedback * Fix version parsing * Apply suggestions from code review Co-authored-by: Koute <[email protected]> --------- Co-authored-by: Koute <[email protected]>
1 parent 8b7d667 commit ae37329

File tree

8 files changed

+327
-51
lines changed

8 files changed

+327
-51
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

primitives/io/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ repository = "https://github.com/paritytech/substrate/"
99
description = "I/O for Substrate runtimes"
1010
documentation = "https://docs.rs/sp-io"
1111
readme = "README.md"
12+
build = "build.rs"
1213

1314
[package.metadata.docs.rs]
1415
targets = ["x86_64-unknown-linux-gnu"]
@@ -37,6 +38,9 @@ ed25519-dalek = { version = "1.0.1", default-features = false, optional = true }
3738
# Force the usage of ed25519, this is being used in `ed25519-dalek`.
3839
ed25519 = { version = "1.5.2", optional = true }
3940

41+
[build-dependencies]
42+
rustversion = "1.0.6"
43+
4044
[features]
4145
default = ["std"]
4246
std = [

primitives/io/build.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) Parity Technologies (UK) Ltd.
4+
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5+
6+
// This program is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 3 of the License, or
9+
// (at your option) any later version.
10+
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
16+
// You should have received a copy of the GNU General Public License
17+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
19+
#[rustversion::before(1.68)]
20+
fn main() {
21+
if !cfg!(feature = "std") {
22+
println!("cargo:rustc-cfg=enable_alloc_error_handler");
23+
}
24+
}
25+
26+
#[rustversion::since(1.68)]
27+
fn main() {}

primitives/io/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
2020
#![warn(missing_docs)]
2121
#![cfg_attr(not(feature = "std"), no_std)]
22-
#![cfg_attr(not(feature = "std"), feature(alloc_error_handler))]
22+
#![cfg_attr(enable_alloc_error_handler, feature(alloc_error_handler))]
2323
#![cfg_attr(
2424
feature = "std",
2525
doc = "Substrate runtime standard library as compiled when linked with Rust's standard library."
@@ -1643,7 +1643,7 @@ pub fn panic(info: &core::panic::PanicInfo) -> ! {
16431643
}
16441644

16451645
/// A default OOM handler for WASM environment.
1646-
#[cfg(all(not(feature = "disable_oom"), not(feature = "std")))]
1646+
#[cfg(all(not(feature = "disable_oom"), enable_alloc_error_handler))]
16471647
#[alloc_error_handler]
16481648
pub fn oom(_: core::alloc::Layout) -> ! {
16491649
#[cfg(feature = "improved_panic_error_reporting")]

utils/wasm-builder/README.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,13 @@ Wasm builder requires the following prerequisites for building the Wasm binary:
7777

7878
- rust nightly + `wasm32-unknown-unknown` toolchain
7979

80-
If a specific rust nightly is installed with `rustup`, it is important that the wasm target is installed
81-
as well. For example if installing the rust nightly from 20.02.2020 using `rustup install nightly-2020-02-20`,
82-
the wasm target needs to be installed as well `rustup target add wasm32-unknown-unknown --toolchain nightly-2020-02-20`.
80+
or
81+
82+
- rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` toolchain
83+
84+
If a specific rust is installed with `rustup`, it is important that the wasm target is
85+
installed as well. For example if installing the rust from 20.02.2020 using `rustup
86+
install nightly-2020-02-20`, the wasm target needs to be installed as well `rustup target add
87+
wasm32-unknown-unknown --toolchain nightly-2020-02-20`.
8388

8489
License: Apache-2.0

utils/wasm-builder/src/lib.rs

+81-43
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,12 @@
100100
//!
101101
//! - rust nightly + `wasm32-unknown-unknown` toolchain
102102
//!
103-
//! If a specific rust nightly is installed with `rustup`, it is important that the wasm target is
104-
//! installed as well. For example if installing the rust nightly from 20.02.2020 using `rustup
103+
//! or
104+
//!
105+
//! - rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` toolchain
106+
//!
107+
//! If a specific rust is installed with `rustup`, it is important that the wasm target is
108+
//! installed as well. For example if installing the rust from 20.02.2020 using `rustup
105109
//! install nightly-2020-02-20`, the wasm target needs to be installed as well `rustup target add
106110
//! wasm32-unknown-unknown --toolchain nightly-2020-02-20`.
107111
@@ -111,9 +115,11 @@ use std::{
111115
path::{Path, PathBuf},
112116
process::Command,
113117
};
118+
use version::Version;
114119

115120
mod builder;
116121
mod prerequisites;
122+
mod version;
117123
mod wasm_project;
118124

119125
pub use builder::{WasmBuilder, WasmBuilderSelectProject};
@@ -172,53 +178,59 @@ fn copy_file_if_changed(src: PathBuf, dst: PathBuf) {
172178
}
173179
}
174180

175-
/// Get a cargo command that compiles with nightly
176-
fn get_nightly_cargo() -> CargoCommand {
181+
/// Get a cargo command that should be used to invoke the compilation.
182+
fn get_cargo_command() -> CargoCommand {
177183
let env_cargo =
178184
CargoCommand::new(&env::var("CARGO").expect("`CARGO` env variable is always set by cargo"));
179185
let default_cargo = CargoCommand::new("cargo");
180-
let rustup_run_nightly = CargoCommand::new_with_args("rustup", &["run", "nightly", "cargo"]);
181186
let wasm_toolchain = env::var(WASM_BUILD_TOOLCHAIN).ok();
182187

183188
// First check if the user requested a specific toolchain
184-
if let Some(cmd) = wasm_toolchain.and_then(|t| get_rustup_nightly(Some(t))) {
189+
if let Some(cmd) =
190+
wasm_toolchain.map(|t| CargoCommand::new_with_args("rustup", &["run", &t, "cargo"]))
191+
{
185192
cmd
186-
} else if env_cargo.is_nightly() {
193+
} else if env_cargo.supports_substrate_wasm_env() {
187194
env_cargo
188-
} else if default_cargo.is_nightly() {
195+
} else if default_cargo.supports_substrate_wasm_env() {
189196
default_cargo
190-
} else if rustup_run_nightly.is_nightly() {
191-
rustup_run_nightly
192197
} else {
193-
// If no command before provided us with a nightly compiler, we try to search one
194-
// with rustup. If that fails as well, we return the default cargo and let the prequisities
195-
// check fail.
196-
get_rustup_nightly(None).unwrap_or(default_cargo)
198+
// If no command before provided us with a cargo that supports our Substrate wasm env, we
199+
// try to search one with rustup. If that fails as well, we return the default cargo and let
200+
// the prequisities check fail.
201+
get_rustup_command().unwrap_or(default_cargo)
197202
}
198203
}
199204

200-
/// Get a nightly from rustup. If `selected` is `Some(_)`, a `CargoCommand` using the given
201-
/// nightly is returned.
202-
fn get_rustup_nightly(selected: Option<String>) -> Option<CargoCommand> {
205+
/// Get the newest rustup command that supports our Substrate wasm env.
206+
///
207+
/// Stable versions are always favored over nightly versions even if the nightly versions are
208+
/// newer.
209+
fn get_rustup_command() -> Option<CargoCommand> {
203210
let host = format!("-{}", env::var("HOST").expect("`HOST` is always set by cargo"));
204211

205-
let version = match selected {
206-
Some(selected) => selected,
207-
None => {
208-
let output = Command::new("rustup").args(&["toolchain", "list"]).output().ok()?.stdout;
209-
let lines = output.as_slice().lines();
212+
let output = Command::new("rustup").args(&["toolchain", "list"]).output().ok()?.stdout;
213+
let lines = output.as_slice().lines();
214+
215+
let mut versions = Vec::new();
216+
for line in lines.filter_map(|l| l.ok()) {
217+
let rustup_version = line.trim_end_matches(&host);
218+
219+
let cmd = CargoCommand::new_with_args("rustup", &["run", &rustup_version, "cargo"]);
210220

211-
let mut latest_nightly = None;
212-
for line in lines.filter_map(|l| l.ok()) {
213-
if line.starts_with("nightly-") && line.ends_with(&host) {
214-
// Rustup prints them sorted
215-
latest_nightly = Some(line.clone());
216-
}
217-
}
221+
if !cmd.supports_substrate_wasm_env() {
222+
continue
223+
}
224+
225+
let Some(cargo_version) = cmd.version() else { continue; };
218226

219-
latest_nightly?.trim_end_matches(&host).into()
220-
},
221-
};
227+
versions.push((cargo_version, rustup_version.to_string()));
228+
}
229+
230+
// Sort by the parsed version to get the latest version (greatest version) at the end of the
231+
// vec.
232+
versions.sort_by_key(|v| v.0);
233+
let version = &versions.last()?.1;
222234

223235
Some(CargoCommand::new_with_args("rustup", &["run", &version, "cargo"]))
224236
}
@@ -228,17 +240,23 @@ fn get_rustup_nightly(selected: Option<String>) -> Option<CargoCommand> {
228240
struct CargoCommand {
229241
program: String,
230242
args: Vec<String>,
243+
version: Option<Version>,
231244
}
232245

233246
impl CargoCommand {
234247
fn new(program: &str) -> Self {
235-
CargoCommand { program: program.into(), args: Vec::new() }
248+
let version = Self::extract_version(program, &[]);
249+
250+
CargoCommand { program: program.into(), args: Vec::new(), version }
236251
}
237252

238253
fn new_with_args(program: &str, args: &[&str]) -> Self {
254+
let version = Self::extract_version(program, args);
255+
239256
CargoCommand {
240257
program: program.into(),
241258
args: args.iter().map(ToString::to_string).collect(),
259+
version,
242260
}
243261
}
244262

@@ -248,20 +266,40 @@ impl CargoCommand {
248266
cmd
249267
}
250268

251-
/// Check if the supplied cargo command is a nightly version
252-
fn is_nightly(&self) -> bool {
269+
fn extract_version(program: &str, args: &[&str]) -> Option<Version> {
270+
let version = Command::new(program)
271+
.args(args)
272+
.arg("--version")
273+
.output()
274+
.ok()
275+
.and_then(|o| String::from_utf8(o.stdout).ok())?;
276+
277+
Version::extract(&version)
278+
}
279+
280+
/// Returns the version of this cargo command or `None` if it failed to extract the version.
281+
fn version(&self) -> Option<Version> {
282+
self.version
283+
}
284+
285+
/// Check if the supplied cargo command supports our Substrate wasm environment.
286+
///
287+
/// This means that either the cargo version is at minimum 1.68.0 or this is a nightly cargo.
288+
///
289+
/// Assumes that cargo version matches the rustc version.
290+
fn supports_substrate_wasm_env(&self) -> bool {
253291
// `RUSTC_BOOTSTRAP` tells a stable compiler to behave like a nightly. So, when this env
254292
// variable is set, we can assume that whatever rust compiler we have, it is a nightly
255293
// compiler. For "more" information, see:
256294
// https://github.com/rust-lang/rust/blob/fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f/src/libsyntax/feature_gate/check.rs#L891
257-
env::var("RUSTC_BOOTSTRAP").is_ok() ||
258-
self.command()
259-
.arg("--version")
260-
.output()
261-
.map_err(|_| ())
262-
.and_then(|o| String::from_utf8(o.stdout).map_err(|_| ()))
263-
.unwrap_or_default()
264-
.contains("-nightly")
295+
if env::var("RUSTC_BOOTSTRAP").is_ok() {
296+
return true
297+
}
298+
299+
let Some(version) = self.version() else { return false };
300+
301+
// Check if major and minor are greater or equal than 1.68 or this is a nightly.
302+
version.major > 1 || (version.major == 1 && version.minor >= 68) || version.is_nightly
265303
}
266304
}
267305

utils/wasm-builder/src/prerequisites.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,13 @@ fn print_error_message(message: &str) -> String {
3535
///
3636
/// Returns the versioned cargo command on success.
3737
pub(crate) fn check() -> Result<CargoCommandVersioned, String> {
38-
let cargo_command = crate::get_nightly_cargo();
38+
let cargo_command = crate::get_cargo_command();
3939

40-
if !cargo_command.is_nightly() {
41-
return Err(print_error_message("Rust nightly not installed, please install it!"))
40+
if !cargo_command.supports_substrate_wasm_env() {
41+
return Err(print_error_message(
42+
"Cannot compile the WASM runtime: no compatible Rust compiler found!\n\
43+
Install at least Rust 1.68.0 or a recent nightly version.",
44+
))
4245
}
4346

4447
check_wasm_toolchain_installed(cargo_command)

0 commit comments

Comments
 (0)