-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow specifying features of the implicit lib dependency #3020
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
- Feature Name: `cargo_target_lib_features` | ||
- Start Date: 2020-11-15 | ||
- RFC PR: [rust-lang/rfcs#3020](https://github.com/rust-lang/rfcs/pull/3020) | ||
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
Allow specifying features of the implicit lib dependency that need to be enabled by default on non-lib targets (`[[bin]]`, `[[example]]`, etc) in a single crate. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
When developing a crate, there are several scenarios where the user might want one of the non-library targets to activate certain features in their library. This can either be when one of the examples in the crate is documenting a non-default feature or when a user might want to have both a library and a binary in the same crate - for example, if the user wants to implement a command line tool and also to export the underlying functionality as a library so that it may be easily used by other developers. | ||
|
||
The second case is currently possible by adding a `[[bin]]` target to the crate's `Cargo.toml`, and adding any binary specific dependencies (ex: `clap`) as optional dependencies of the library (to reduce unnecessary bloat) under a feature flag (ex: `cli`), and then adding `required-features` to the binary target. But the issue here is that if the end-user does not specify the `cli` feature, then the binary target gets skipped because of how `required-features` is designed. | ||
|
||
Similarly, with examples, benches and test targets. | ||
|
||
# Guide-level explanation | ||
[guide-level-explanation]: #guide-level-explanation | ||
|
||
A single project may include multiple artifacts - zero or one libraries, and any number of other targets, like the following `Cargo.toml`: | ||
|
||
```toml | ||
[package] | ||
name = "myproject" | ||
version = "0.1.0" | ||
edition = "2018" | ||
|
||
[lib] | ||
name = "myproject" | ||
path = "src/lib.rs" | ||
|
||
[[example]] | ||
name = "yaml" | ||
path = "src/examples/yaml.rs" | ||
required-features = ["yaml"] | ||
|
||
[dependencies] | ||
yaml-rust = { version = "*", optional = true } | ||
|
||
[features] | ||
default = [] | ||
yaml = ["yaml-rust"] | ||
``` | ||
|
||
This project contains a library usable by other crates, and an example that can be run to showcase one of the non-default features of the library. | ||
|
||
Running `cargo run --example yaml` in the crate gives us a compiler error since the `yaml` feature of the library has not been activated. | ||
|
||
To solve this, we can specify the library features for specific targets, like so: | ||
|
||
```toml | ||
[package] | ||
name = "myproject" | ||
version = "0.1.0" | ||
edition = "2018" | ||
|
||
[lib] | ||
name = "myproject" | ||
path = "src/lib.rs" | ||
|
||
[[example]] | ||
name = "yaml" | ||
path = "src/examples/yaml.rs" | ||
required-features = ["yaml"] | ||
lib-features = ["default", "yaml"] | ||
|
||
[dependencies] | ||
yaml-rust = { version = "*", optional = true } | ||
|
||
[features] | ||
default = [] | ||
yaml = ["yaml-rust"] | ||
``` | ||
|
||
Now, when a user tries `cargo run --example yaml`, the `yaml` feature and the default features of the library will be implicity activated and thus the example will compile and execute as designed. | ||
|
||
For a target, specifying `lib-features` does not implicity activate the default features of the library dependency. If needed, the target can specify `default` in the list of values for `lib-features`. | ||
|
||
# Reference-level explanation | ||
[reference-level-explanation]: #reference-level-explanation | ||
|
||
This feature would add a new `lib-features` key to the `bin`, `test`, `bench`, and `example` sections of the `Cargo.toml` file, a list of strings that represent the features that should be activated for the implicit library dependency. | ||
|
||
```toml | ||
[[example]] | ||
name = "yaml" | ||
lib-features = ["yaml"] | ||
``` | ||
|
||
Adding `lib-features` to a target changes the behaviour of `cargo-run`, `cargo-test` and `cargo-install` subcommands to implicity activate only the described features thus making `no-default-features` flag irrelevant. | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
- None as of yet | ||
|
||
# Rationale and alternatives | ||
[rationale-and-alternatives]: #rationale-and-alternatives | ||
|
||
While the `required-features` key offers similar functionality, the feature flags must be manually enabled at compile time, and still apply to the entire crate. This adds friction for both project developers, who need to properly separate their dependencies with features and test that these configurations work properly, as well as for users, who need to manually enable the features for their use case. | ||
|
||
We could automatically enable the required features when compiling that specific target, but it still does not solve the issue of disabling library's default features for that target. | ||
|
||
Also, we find that `required-features` and skipping targets has their own niche use cases. | ||
|
||
# Prior art | ||
[prior-art]: #prior-art | ||
|
||
- Cargo allows users to specify the features that need to be activated for dependencies as described in the [reference](https://doc.rust-lang.org/cargo/reference/features.html#features) | ||
|
||
# Unresolved questions | ||
[unresolved-questions]: #unresolved-questions | ||
|
||
- Currently, using feature flags for some targets results in them being disabled/enabled for all targets of the given crate. Since we will be doing implicit activation of features in this RFC, can we find a way to make them not activated for other targets? | ||
|
||
# Future possibilities | ||
[future-possibilities]: #future-possibilities | ||
|
||
- Specified features can be used with the new [feature resolver](https://doc.rust-lang.org/cargo/reference/unstable.html#features). |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This statement is a little confusing to me. This isn't enabling features for the
lib
exactly, is it? For example, if you have aclap
feature, it needs to also be enabled for the binary, too, right?In general, I would probably like to see this framed as just changing the set of features enabled on a package. Cargo's features work at the resolution of packages, and changing that might be quite difficult.
Or maybe I am not understanding what the RFC is proposing. I am assuming that the features for the package would still be the union of the features enabled by the selected targets. I'm not sure I understand how this intends target selection to interact with the enable set of features.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
But the statement talks about enabling features on non-lib targets. I am not sure what exactly caused the confusion here. Do you think you can explain a bit more on what you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess my confusion boils down to, I don't understand why this RFC is talking about the implicit "lib" dependency at all.
The phrase "specifying features of the implicit lib dependency" implies to me that this is specifying the features of
lib.rs
. But it seems to be the opposite of that; that it is specifying the features of the binary/example targets? Or is it specifying the features for the whole package?For example, let's say there is a package with 3 binaries and no
lib.rs
, what would specifyinglib-features
do? Why does it have the word "lib" in it, if a package doesn't even have a library?The only thing that I see that is special about "lib" is that it is required in all circumstances, so setting features on the
[lib]
table doesn't make sense (which is also the case withrequired-features
).