Rust Custom Cfg Names
A custom cfg name is a condition name that a project invents for itself. A custom name covers a choice the machine cannot know, like a beta switch or a licence tier.
A build script turns the name on
One printed line in build.rs sets the name for the whole build. The double colon is the modern spelling. The older cargo: form still works:
// build.rs
fn main() {
println!("cargo::rustc-cfg=turbo_mode");
}Use the name like any built-in
Code asks with cfg! or guards items with #[cfg], exactly as it does with target_os. With the script above in place, this program prints on:
if cfg!(turbo_mode) {
println!("turbo = on");
} else {
println!("turbo = off");
}The warning: unexpected cfg
Miss one step out, and the build still works — but the compiler warns. It has never heard of your name, and it says so:
// warning: unexpected `cfg` condition name: `turbo_mode`Declare the name in the same script
A second printed line registers the name as legal. The build then runs with no warning:
// build.rs
fn main() {
println!("cargo::rustc-check-cfg=cfg(turbo_mode)");
println!("cargo::rustc-cfg=turbo_mode");
}Or declare it in Cargo.toml
A lints table does the same job, in the open. This is also where a name set by hand with RUSTFLAGS gets declared:
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(turbo_mode)'] }Values can be declared too
A name may carry values, and you can list the legal ones. A value outside the list earns the same warning, so typos get caught:
println!("cargo::rustc-check-cfg=cfg(flavour, values(\"fast\", \"slow\"))");Example
// build.rs
// fn main() {
// println!("cargo::rustc-check-cfg=cfg(turbo_mode)");
// println!("cargo::rustc-cfg=turbo_mode");
// }
// src/main.rs:
fn main() {
if cfg!(turbo_mode) {
println!("turbo = on");
} else {
println!("turbo = off");
}
}Key points
- Setting and declaring are two jobs.
- rustc-cfg switches a name on.
- rustc-check-cfg tells the compiler the name exists.
- The lints table can do that job too
- In a Cargo build, even a typo in a built-in value warns: cfg!(target_os = "linus") is flagged, and the warning lists the legal values
- A name set by hand travels in RUSTFLAGS: RUSTFLAGS="--cfg turbo_mode" cargo build.
- It still needs declaring, or the warning returns
- A cfg name is crate-local.
- It switches code inside your crate only.
- It never becomes part of your public API.
- A feature does become part of it
- Each crate's build script speaks only for its own package.
- Built-in cfg names describe the machine.
- A custom cfg name is a project-invented condition for choices beyond the machine.
In this example, the build script does two jobs. Its first printed line declares turbo_mode, so the compiler accepts the name in silence. Its second line switches the name on for this build. The main program then asks with cfg! and prints turbo = on. Delete the declaration line and the same build prints a warning about an unexpected cfg name. Delete the rustc-cfg line instead, and the program quietly prints turbo = off.
Note
Turning a name on for one crate does not turn it on for its neighbours.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
Your build warns: unexpected `cfg` condition name: `turbo_mode`. What is missing?