Help us test the breaking bug-fix to Cargo features


#1

TL;DR: if you use any of --package, --feature, --all-features, --no-default-features flags in your build, could you check that on the latest nightly, if you add -Z package-features flag as well, everything continues to work?

Hi! We’ve recently noticed a rather surprising interaction of Cargo --feature and --package flags. For command like cargo build --package foo --feature feat, the feature would be activated not for the foo package, but for the package at current working directory. Moreover, features of current package were always activated, so cargo build --package foo might have activated more features than strictly necessary for building foo! We would like to make this behavior more intuitive, and always apply features to the explicitly selected package. This is a change in behavior, so, for now, it is hidden behind an opt-in -Z package-features flag. We would like to access the real-world impact of this change, so please try building your projects with this opt-in!

Tracking issue: https://github.com/rust-lang/cargo/issues/5364 implementation PR: https://github.com/rust-lang/cargo/pull/5353 (includes more details about what exactly has changed)


#2

Oh, as usual, we are interested in both “my build is broken!!!111” and “everything works!” reports :slight_smile:


#3

Does this also affect virtual manifest handling? I’ve definitely noticed when working with futures that there is no way to activate features for sub-packages.

If yes, I assume this would allow changing all the --manifest-path <package>/Cargo.toml in https://github.com/rust-lang-nursery/futures-rs/blob/master/.travis.yml#L21 to just --package <package> (at least on nightly).


#4

Yep, -Z package-features -p package should work with virtual manifests just fine!


#5

And testing it myself, it seems to work perfectly for futures, having --no-default-features apply to all packages and --features actually error out insteads of just being ignored is great :smile:

Even playing round with a non-virtual workspace I noticed that --features without --package correctly detects when there’s a single or multiple default-members to apply to :+1:

One potential addition: allow specifying features on packages in the current workspace when doing a full build by referring to them via <package>/<feature>, e.g. instead of having to run cargo build --package futures --features nightly it could be possible to run cargo build --features futures/nightly and have that enable the correct features on all packages based on the features specified on the command line.

Not sure how useful that would be in practice, just an idea I had while thinking about how futures Travis config could be changed with this.


#6

Yeah, it is true that today there’s simply no syntax for specifying features for different packages, and that we should probably add it. However, we might need to fix https://github.com/rust-lang/cargo/issues/4463 first, which would be not so trivial :frowning:


#7

Testing Rand since we have quite a few feature configurations and multiple crates.

I see this is no longer possible (though the command may not have worked correctly before anyway — I guess we have to test each crate individually):

$ cargo test --all --features=alloc -Z package-features
error: cannot specify features for more than one package

This happens to fix a “bug” we had when testing with the following command, plus “std” enabled by default in rand_core:

cargo test --tests --no-default-features --features=alloc --all

Other than that, no problems. I guess we just have to update our Travis scripts.


#8

Indeed. The previous semantics for this was … curious, now it just errors :0)


#9

This fixes the behavior in my case! I was also using the --manifest-path workaround.


#10

Thanks! It seems to work properly in my virtual workspace (for a no_std OS project).

However, I can’t figure out how to specify features for multiple packages within my workspace. For example, I’d like to do the following:

cargo build -Z package-features --package crate1 --feature featA --package crate2 --feature featB

This gives me the error:

error: The argument '--features <FEATURES>' was provided more than once, but cannot be used multiple times

or if I try to enable the same feature for multiple packages, like so:

cargo build -Z package-features --package crate1 --package crate2 --feature myfeat

I get the error:

error: cannot specify features for more than one package

I assume there’s a way to do this, but it’s not clear from the new package-features discussion.


#11

No, there’s no syntax to enable several specific features for several packages, you’ll need to invoke cargo build multiple times.


#12

I see, thanks. BTW, it also doesn’t work at all with cargo build --all, whereas the old way of doing things with --manifest-path did work.


#13

Could you elaborate what exactly stopped working? If you specify -all, then only -all-features and -no-default-features flags are supported. —features does not work, because it is ambiguous as to which package the feature should apply.

I guess previously it was possible to do something like Cargo build —all —manifest-path foo/Cargo.toml —feature bar, but it doesn’t look that useful?


#14

Yes, it does make sense that --features wouldn’t work by itself with --all, that’s why I was hoping to use the -Z package-features flag to specify which packages a given feature should apply to.

Yep, that’s exactly it. It’s useful to me because I can (currently) issue a single very quick cargo build command form a top-level Makefile while specifying one feature in a subcrate of my workspace (the makefile is doing other non-Rust stuff for my OS). It’d be even better to issue a single cargo build command with multiple features specified for multiple packages, but I understand if y’all don’t wish to support that.


#15

We definitely wish to support that! However, we need to fix one small and one big problem before it is possible :slight_smile:

The small problem is that we just don’t have syntax for it yet. --package foo --features "foo/bar" seems a plausible option though!

The bigger problem is that features selection works weirdly depending on the precise set of packages that you are compiling. That end result is that cargo build -p foo and cargo build -p foo -p bar can produce different artifacts for foo, because, currently, Cargo unions all the features for packages being compiled.

We’ve also decided to go ahead and flip the behavior hear, without explicit opt-in, so, when Cargo is updated at rust-lang/rust, the next nightly would have the new behavior. If it turns out to break code in the wild, we’ll have time to revert the behavior.