Expand description
Advice for configuring your development environment for Substrate development.
§Development Environment Advice
Large Rust projects are known for sometimes long compile times and sluggish dev tooling, and polkadot-sdk is no exception.
This page contains some advice to improve your workflow when using common tooling.
§Rust Analyzer Configuration
Rust Analyzer is the defacto LSP for Rust. Its default settings are fine for smaller projects, but not well optimised for polkadot-sdk.
Below is a suggested configuration for VSCode:
{
// Use a separate target dir for Rust Analyzer. Helpful if you want to use Rust
// Analyzer and cargo on the command line at the same time,
// at the expense of duplicating build artifacts.
"rust-analyzer.cargo.targetDir": "target/vscode-rust-analyzer",
// Improve stability
"rust-analyzer.server.extraEnv": {
"CHALK_OVERFLOW_DEPTH": "100000000",
"CHALK_SOLVER_MAX_SIZE": "10000000"
},
// Check feature-gated code
"rust-analyzer.cargo.features": "all",
"rust-analyzer.cargo.extraEnv": {
// Skip building WASM, there is never need for it here
"SKIP_WASM_BUILD": "1"
},
// Don't expand some problematic proc_macros
"rust-analyzer.procMacro.ignored": {
"async-trait": ["async_trait"],
"napi-derive": ["napi"],
"async-recursion": ["async_recursion"],
"async-std": ["async_std"]
},
// Use nightly formatting.
// See the polkadot-sdk CI job that checks formatting for the current version used in
// polkadot-sdk.
"rust-analyzer.rustfmt.extraArgs": ["+nightly-2024-04-10"],
}
and the same in Lua for neovim/nvim-lspconfig
:
["rust-analyzer"] = {
rust = {
# Use a separate target dir for Rust Analyzer. Helpful if you want to use Rust
# Analyzer and cargo on the command line at the same time.
analyzerTargetDir = "target/nvim-rust-analyzer",
},
server = {
# Improve stability
extraEnv = {
["CHALK_OVERFLOW_DEPTH"] = "100000000",
["CHALK_SOLVER_MAX_SIZE"] = "100000000",
},
},
cargo = {
# Check feature-gated code
features = "all",
extraEnv = {
# Skip building WASM, there is never need for it here
["SKIP_WASM_BUILD"] = "1",
},
},
procMacro = {
# Don't expand some problematic proc_macros
ignored = {
["async-trait"] = { "async_trait" },
["napi-derive"] = { "napi" },
["async-recursion"] = { "async_recursion" },
["async-std"] = { "async_std" },
},
},
rustfmt = {
# Use nightly formatting.
# See the polkadot-sdk CI job that checks formatting for the current version used in
# polkadot-sdk.
extraArgs = { "+nightly-2024-04-10" },
},
},
For the full set of configuration options see https://rust-analyzer.github.io/manual.html#configuration.
§Cargo Usage
§Using --package
(a.k.a. -p
)
polkadot-sdk is a monorepo containing many crates. When you run a cargo command without
-p
, you will almost certainly compile crates outside of the scope you are working.
Instead, you should identify the name of the crate you are working on by checking the name
field in the closest Cargo.toml
file. Then, use -p
with your cargo commands to only compile
that crate.
§SKIP_WASM_BUILD=1
environment variable
When cargo touches a runtime crate, by default it will also compile the WASM binary, approximately doubling the compilation time.
The WASM binary is usually not needed, especially when running check
or test
. To skip the
WASM build, set the SKIP_WASM_BUILD
environment variable to 1
. For example:
SKIP_WASM_BUILD=1 cargo check -p frame-support
.
§Cargo Remote
If you have a powerful remote server available, you may consider using
cargo-remote to execute cargo commands on it,
freeing up local resources for other tasks like rust-analyzer
.
When using cargo-remote
, you can configure your editor to perform the the typical
“check-on-save” remotely as well. The configuration for VSCode is as follows:
{
"rust-analyzer.cargo.buildScripts.overrideCommand": [
"cargo",
"remote",
"--build-env",
"SKIP_WASM_BUILD=1",
"--",
"check",
"--message-format=json",
"--all-targets",
"--all-features",
"--target-dir=target/rust-analyzer"
],
"rust-analyzer.check.overrideCommand": [
"cargo",
"remote",
"--build-env",
"SKIP_WASM_BUILD=1",
"--",
"check",
"--workspace",
"--message-format=json",
"--all-targets",
"--all-features",
"--target-dir=target/rust-analyzer"
],
}
and the same in Lua for neovim/nvim-lspconfig
:
["rust-analyzer"] = {
cargo = {
buildScripts = {
overrideCommand = {
"cargo",
"remote",
"--build-env",
"SKIP_WASM_BUILD=1",
"--",
"check",
"--message-format=json",
"--all-targets",
"--all-features",
"--target-dir=target/rust-analyzer"
},
},
check = {
overrideCommand = {
"cargo",
"remote",
"--build-env",
"SKIP_WASM_BUILD=1",
"--",
"check",
"--workspace",
"--message-format=json",
"--all-targets",
"--all-features",
"--target-dir=target/rust-analyzer"
},
},
},
},