The relation between using `std` and `no_std` attributes and including WASM

Viewed 430

I've just started to study substrate, and the Add a Pallet tutorial already has me seriously confused:

It is important to note that the Substrate runtime compiles to both a native Rust std binary and a WebAssembly (Wasm) binary. For more information about compiling std and no_std features, see XXX.

This is fine, I'm familiar with std and no_std. My impression is that you either have std enabled and compile to native Rust binary, or you don't and compile to WASM binary.

But then, when I check out the runtime's lib.rs, I find the following:

#![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]

// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));

// ...

This confuses me: Why is the WASM binary "made available" when std is enabled? I would have expected the opposite. And what exactly does "made available" mean in this context?

I dug a little deeper and found the following in an older version of the tutorial, which goes a little more into detail, causing even more grievous mental confusion:

This is important to enable the Substrate runtime to compile to both native binaries (which support Rust std) and Wasm binaries (which do not: no_std).

(Again, this is fine, although I'm not sure what they mean by "support".) And then later, refering to the file whose first lines I've posted above:

You can see that at the top of the file, we define that we will use no_std when we are not using the std feature. A few lines lower you can see #[cfg(feature = "std")] above the wasm_binary.rs import, which is a flag saying to only import the WASM binary when we have enabled the std feature.

What?!

So, if std is enabled, then we use the Rust std library and WASM? And when std is not enabled, then we only use libcore? This seems to completely contradict the earlier statements.

I am absolutely certain that all of this is the result of a seriously stupid mistake on my part, but I can't figure it out.

Edit. I've had an extremely enlightening conversation with Shawn Tabrizi on this topic: https://github.com/substrate-developer-hub/substrate-docs/issues/531

1 Answers

The Substrate runtime code (including the pallets) has two compilation target: std for the native binary and no_std for the wasm binary. This is necessary because Substrate supports to run both the wasm runtime for upgradability, and the native binary for performance (or for testing easily).

When you compile a blockchain, it will call the custom build script (build.rs in your runtime crate) to build the wasm binary first, save it in the build dir, and then build the native binary with the wasm binary embedded in wasm_binary.rs. This answered your question about "made available".

Therefore the following code means, if it's in std mode, it will include the wasm file built in no_std mode, embedded in the wasm_binary.rs file.

#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
Related