How can I run cargo check/test individually on each feature of my Cargo.toml? - rust

Cargo features allow conditional compilation, so the final build will have just specific groups of features which can be filtered by the final user.
Now depending on the complexity of a library crate, you may end with several features forming a dependency tree, something like:
[features]
banana = []
avocado = []
pineapple = ["avocado"]
orange = ["pineapple", "banana"]
It's natural that, beyond cargo check|test --all-features, I will want to run cargo check|test --features banana on each one of the individual features, to ensure they can live on their own. Currently I'm doing this with a crude shell script, manually fed with the features. If I add a new feature and I forget to add it to the script, I'm in trouble.
FEATS=(banana avocado pineapple orange)
for FEAT in "${FEATS[#]}" ; do
echo "$FEAT..."
cargo check --features "$FEAT"
#cargo test --features "$FEAT"
done
So, is there any automated way to run cargo check|test --features banana on each feature, one by one, then report the warnings/errors which have been found?

I recently found taiki-e/cargo-hack which claims to handle this problem. I haven't tried it myself.
cargo-hack is basically wrapper of cargo that propagates subcommand and most of the passed flags to cargo, but provides additional flags and changes the behavior of some existing flags.
--each-feature
Perform for each feature which includes default features and --no-default-features of the package.
This is useful to check that each feature is working properly.

There is the cargo-all-features crate that provides commands for using all combination of features, not only individual features:
> cargo install cargo-all-features --locked
With it installed, you can run the following cargo commands to check, test, and build:
> cargo check-all-features
> cargo test-all-features
> cargo build-all-features
Further customizations (like skipping features or combinations) can be set by configuring the [package.metadata.cargo-all-features] section in your Cargo.toml.

Related

How can I run the rustdoc lints on every crate in my workspace?

Rustdoc offers some pretty useful lints for documentation. I'd like to check these lints as part of continuous integration for all of the crates in my Cargo workspace.
Unfortunately, I've not been able to find a way to run these lints for all of my crates. You can do e.g.
cargo rustdoc -p crate -- -D rustdoc::broken-intra-doc-links
to run on a specific crate, but there's no --workspace flag on cargo rustdoc. Obviously I could do some hacky thing with xargs here, but that's pretty slow & annoying. Is there a supported way to run this check?
You can use RUSTDOCFLAGS and cargo doc:
RUSTDOCFLAGS="-D rustdoc::broken-intra-doc-links" cargo doc

How to activate an optional dependency?

Cargo.toml:
[features]
parallel = ["rayon"]
[dependencies.rayon]
version = "1.5"
optional = true
lib.rs:
#[cfg(feature = "parallel")]
pub mod par;
Rust Analyzer:
code is inactive due to #[cfg] directives: feature = "parallel" is disabled
How to enable the optional dependency?
You can set the Rust Analyzer configuration option rust-analyzer.cargo.features to an array containing a list of features that you want RA to consider active.
You can also set rust-analyzer.cargo.allFeatures to true, in order to enable all features in the project.
Methods for setting these vary according to the IDE you are using - for example, if using VS Code, you can set it via the "Extension Settings" for Rust Analyzer.
This assumes you are asking how to activate the features within Rust Analyzer - to activate them when building or running from Cargo, just use the --features option.
See: Rust Analyzer Manual
All non-default features need to be specified when running. So run with:
# Option 1
cargo run --features parallel
# Option 2
cargo run --all-features
Check cargo run --help for more help.

Determine Cargo build configuration

I'm implementing a custom Cargo subcommand that mostly runs cargo build followed by some processing on a successful invocation. Cargo itself supports several ways to customize defaults, (e.g. the --target selected when omitted), which this subcommand exposes as well.
The challenge now is to find the defaults that cargo build uses from the subcommand implementation. With build scripts getting access to all sorts of information, this isn't the case for subcommands. Running cargo metadata doesn't seem to produce that information either (such as the TARGET).
Is there any way to query Cargo about the configuration it will be using for a cargo build invocation, and make that available to a Cargo custom subcommand?

Using multiple flags with cargo

I want to run tests with release optimisations using 1 test thread.
I can do these individually:
cargo test -- --test-threads=1
cargo test --release
How would I put these together?
You can use both in a single command like this:
cargo test --release -- --test-threads=1
How Cargo interprets these arguments ?
According to test subcommand's synopsis in reference :
cargo test [OPTIONS] [TESTNAME] [-- TEST-OPTIONS]
Cargo interprets input as :
Arguments before separator (--) will be used as an option for test subcommand. In your case cargo test accepts profile parameter as an option since it builds the project. Available options can be found under this title, or by running cargo test --help.
Arguments after the separator will be passed to the test binaries. In Rust project, Cargo uses rustc's libtest to run unit tests. In your case --test-threads=1 will be an argument for libtest.
This interpretation might not be valid for other subcommands, it is best to check other cargo commands from here. Checking synopsis section will give you a huge hint about capabilities of cargo's subcommands.
See also:
Since arguments after the dash will be sent to the rustc's libtest you can see available options for testing by: cargo test -- --help.
Profile options can be found under this title

How can I optionally pass rustc flags depending on a Cargo feature?

The program I'm writing runs much faster when the -C target-cpu=native flag is passed to rustc. I want to give users a simple, platform-independent way to enable this when compiling, so I added a Cargo feature cpu_native = [] in Cargo.toml and created this Cargo config in my project:
[target.'cfg(cpu_native)']
rustflags = ["-C", "target-cpu=native"]
However, this has no effect on my program, and passing --features cpu_native to Cargo does not even trigger a recompile. Changing to the following Cargo config does force re-compilation with faster instructions:
[build]
rustflags = ["-C", "target-cpu=native"]
However, this will compile with target-cpu=native with the default Cargo features, which was not what I wanted. From the Cargo book, what I want seems to be possible, but I don't see what I'm doing wrong.
I don't think this is supported (yet?). I enhanced Cargo to print out what config flags are checked against when resolving:
[
Name("debug_assertions"),
Name("proc_macro"),
KeyPair("target_arch", "x86_64"),
KeyPair("target_endian", "little"),
KeyPair("target_env", ""),
KeyPair("target_family", "unix"),
KeyPair("target_os", "macos"),
KeyPair("target_pointer_width", "64"),
Name("unix"),
]
[target.'cfg(cpu_native)']
This is the incorrect syntax for a Cargo feature; it would normally be cfg(feature = "cpu_native").

Resources