in my embedded rust code, I fix a prestart assembly function at very start.
The prestart function varies for rom build and ram build. What would be the equivalent of #ifdef in rust?
How and where these ifdef config parameters should be defined?
the compiler support the #[cfg(custom_cfg_attr)] attribute to enable conditional compilation. the basic usage is like this:
// This function only gets compiled if the target OS is linux
#[cfg(target_os = "linux")]
fn are_you_on_linux() {
println!("You are running linux!");
}
// And this function only gets compiled if the target OS is *not* linux
#[cfg(not(target_os = "linux"))]
fn are_you_on_linux() {
println!("You are *not* running linux!");
}
you can use some attrs predefined by rustc or cargo (such as target_os), or you can use whatever you deem suitable. see:
alternatively you can use the cfg!() macro, which evaluates to a compile-time boolean constant so you can use it in control flow statements like if-else:
fn are_you_on_linux() {
if cfg!(target_os = "linux") {
println!("You are running linux!");
} else {
println!("You are *not* running linux!");
}
}
it is also often suggested to check out the cfg-if crate:
I'd suggest a cargo feature is preferred over custom cfg attributes. see below.
as for the custom cfg flags, eventually, a compiler flag need to be passed down to rustc, like this (you need to properly escape the quotes, which is not a trivial task especially on Windows):
$ rustc --cfg 'build="rom"' ...
there's plenty methods you can pass the flag, for example:
if possible, you should prefer cargo features to custom cfg attributes. as you can see, passing custom command line flags to rustc isn't as easy as we would it like to be. but cargo features are fairly easy to use, and you put it into the Cargo.toml manifest instead of a config file (e.g. .cargo/config.toml) so it allows other crates to easily integrate with your crate. your example can be rewritten using a feature cfg flag instead of the custom build flag, like so:
#[cfg(feature = "build-rom")]
and you declare the feature in your Cargo.toml manifest file like so:
[features]
# leave the default feature depends on nothing
# so neither feature will be selected if you don't explicit enable
# or you can specify a feature as the default like this:
# default = ["build-ram"]
default = []
build-rom = []
build-ram = []
run cargo with --features command line flag like so:
$ cargo build --features build-ram
$ cargo build --features build-rom
# if you have non-empty default feature set,
# you need to use `--no-default-features` too
$ cargo build --no-default-features --features build-rom
The second approach of adding feature flags seems to be difficult on my cargo workspace as it my cargo workspace has multiple cargo.toml files. I assume this feature flag should go into all of these. right? and keeping all in sync I assume to be manual. Is there a way to propogate this feature flag defined in one cargo.toml in workspace to all?
no necessarily. feature flags are defined per-crate, it really only matters for those direct list the crate as dependencies. for example, in a workspace like this: