{"action":"created","issue":{"url":"https://api.github.com/repos/rust-lang/cargo/issues/1286","labels_url":"https://api.github.com/repos/rust-lang/cargo/issues/1286/labels{/name}","comments_url":"https://api.github.com/repos/rust-lang/cargo/issues/1286/comments","events_url":"https://api.github.com/repos/rust-lang/cargo/issues/1286/events","html_url":"https://github.com/rust-lang/cargo/issues/1286","id":57144439,"number":1286,"title":"RFC: Remove the implicit features associated with dependencies","user":{"login":"sfackler","id":1455697,"avatar_url":"https://avatars.githubusercontent.com/u/1455697?v=3","gravatar_id":"","url":"https://api.github.com/users/sfackler","html_url":"https://github.com/sfackler","followers_url":"https://api.github.com/users/sfackler/followers","following_url":"https://api.github.com/users/sfackler/following{/other_user}","gists_url":"https://api.github.com/users/sfackler/gists{/gist_id}","starred_url":"https://api.github.com/users/sfackler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sfackler/subscriptions","organizations_url":"https://api.github.com/users/sfackler/orgs","repos_url":"https://api.github.com/users/sfackler/repos","events_url":"https://api.github.com/users/sfackler/events{/privacy}","received_events_url":"https://api.github.com/users/sfackler/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rust-lang/cargo/labels/A-features","name":"A-features","color":"fbca04"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":7,"created_at":"2015-02-10T08:29:25Z","updated_at":"2015-02-12T18:34:58Z","closed_at":null,"body":"# Background\r\nFeatures in a Cargo crate setup can currently be created in two ways. Features can be manually added:\r\n```toml\r\n[features]\r\nfoo = []\r\nbar = [\"a/b\", \"c\"]\r\n```\r\nManually added features can depend on other features. `bar` above depends on feature `c` from its own crate, and feature `b` from crate `a`.\r\n\r\nIn addition, all dependencies have an implicit associated feature with the same name. However, these features cannot depend on other features.\r\n\r\n# The Problem\r\nThe current setup misses some important use cases. For example, `rust-postgres` has a `uuid` feature which adds support for the Postgres `UUID` type by linking to the `uuid` crate and generating trait implementations for the `uuid::Uuid` type. A separate crate, `rust-postgres-array` adds support for array types. Here, we would like to have the same setup - a `uuid` feature that adds support for the Postgres `UUID[]` type by linking to the `uuid` crate and adding the appropriate trait implementations. The `uuid` feature of `rust-postgres-array` needs to depend on functionality provided by the `uuid` feature of `rust-postgres`, but this isn't currently possible since `uuid` is a feature implicitly created by the `uuid` dependency.\r\n\r\nThere exists a kind of workaround here, where you define a feature with a different name that depends on `uuid`:\r\n```toml\r\n[features]\r\nuuid_support = [\"uuid\", \"postgres/uuid\"]\r\n```\r\nThat's a bit unfortunate, though. Having the feature name match the crate name avoids a bit of verbosity and makes it explicit that it's using that crate specifically (for example, support for the Postgres `JSON` type is provided via `rustc-serialize::Json`, and naming the feature `rustc-serialize` makes this point more clear than naming it `json` would, as well as keeping room for support via some other crate as well in the future).\r\n\r\nI was initially going to change Cargo to add support for an optional dependency depending on features of other dependencies like so:\r\n```toml\r\n[dependencies]\r\npostgres = \"0.6\"\r\n\r\n[dependencies.uuid]\r\noptional = true\r\nversion = \"0.1\"\r\nfeatures = [\"postgres/uuid\"]\r\n```\r\n\r\nAfter some more thought, I came to the conclusion that this was the wrong way to go about it, and deeper changes to Cargo's feature API would solve both this issue and some other issues:\r\n\r\n# Backwards compatibility hazards\r\nThe fact that all dependencies are also features poses backwards compatibility hazards for a crate author when making changes that would not otherwise be user facing. Imagine Alice makes a crate `foo`:\r\n```toml\r\n[package]\r\nname = \"foo\"\r\nversion = \"0.1.0\"\r\nauthors = []\r\n\r\n[dependencies]\r\nbar = \"0.1\"\r\n```\r\nAnd Bob makes a crate `baz` that depends on `foo`:\r\n```toml\r\n[package]\r\nname = \"baz\"\r\nversion = \"0.0.1\"\r\nauthors = []\r\n\r\n[dependencies.foo]\r\nversion = \"0.1\"\r\nfeatures = [\"bar\"]\r\n```\r\nNote that he's enabled the `bar` feature on the `foo` crate. This is basically a no-op (it defines the `feature = \"bar\"` cfg when compiling `foo`, but let's assume that `foo` doesn't use that anywhere).\r\n\r\nNow imagine Alice does some internal refactoring that allows her to remove the dependency on `bar`. She publishes version 0.1.1, but suddenly a bug report is filed on `foo`. The new release broke Bob's crate, since the `bar` feature no longer exists! Bob should never have enabled that \"feature\" in the first place, but that doesn't make the situation any better for the people that depend on the `baz` crate.\r\n\r\n## So why not forbid the use of features named after non-optional dependencies?\r\nFeatures matching the name of a non-optional dependency are another important use case! `rust-postgres` currently depends on `time` for internal use that doesn't touch the public API. It also implements some traits for `time::Timespec` to enable support for the Postgres `TIMESTAMP` type. However, I want to make the `TIMESTAMP` support opt-in via a feature to enable me to drop the dependency on `time` if future work on `rust-postgres` removes its internal usage. If the user facing part (the trait implementations) is behind a feature, I can make the `time` dependency optional without breaking backwards compatibility.\r\n\r\n# Proposal\r\nAs discussed above, the current feature implementation is both too restrictive to enable some uses and too eager to enable dependency flexibility. Both of these problems boil down to Cargo's intertwining of features and dependencies. It seems like the solution here is to remove that interconnectedness.\r\n\r\nDependencies, mandatory or optional, will no longer automatically have associated features. Features can be defined with two forms. The short form matches visually with current feature syntax, though the meaning will be adjusted:\r\n```toml\r\n[features]\r\nbar = [\"a\", \"b/c\"]\r\n\r\n[dependencies.a]\r\noptional = true\r\n\r\n[dependencies.b]\r\noptional = true\r\n```\r\nThis defines a feature `bar`. While in current Cargo, `bar` would also activate the `a` and `b/c` *features*, it would now activate the optional *dependency* on crate `a`, as well as crate `b`, activating crate `b`'s feature `c`. Note that the behavior here is actually identical between current Cargo and Cargo after the proposed changes. It will make a difference in a case like this:\r\n```toml\r\n[features]\r\nbar = [\"a\"]\r\na = []\r\n```\r\nIn current Cargo, this is valid, and activating feature `bar` causes feature `a` to be activated as well. In this proposal, this would be an error, since `a` is a feature and not a dependency.\r\n\r\nIf a feature needs to activate another feature, a more verbose method is allowed:\r\n```toml\r\n[features]\r\na = []\r\n\r\n[features.b]\r\nfeatures = [\"a\"]\r\ndependencies = [\"foo\"]\r\n\r\n[dependencies.foo]\r\noptional = true\r\n```\r\nHaving this extended form could also be useful in the future to allow the addition of things like descriptions which could be displayed on crates.io:\r\n```toml\r\n[features.foo]\r\ndescription = \"Adds support for the foo thingy\"\r\n```"},"comment":{"url":"https://api.github.com/repos/rust-lang/cargo/issues/comments/74125459","html_url":"https://github.com/rust-lang/cargo/issues/1286#issuecomment-74125459","issue_url":"https://api.github.com/repos/rust-lang/cargo/issues/1286","id":74125459,"user":{"login":"wycats","id":4,"avatar_url":"https://avatars.githubusercontent.com/u/4?v=3","gravatar_id":"","url":"https://api.github.com/users/wycats","html_url":"https://github.com/wycats","followers_url":"https://api.github.com/users/wycats/followers","following_url":"https://api.github.com/users/wycats/following{/other_user}","gists_url":"https://api.github.com/users/wycats/gists{/gist_id}","starred_url":"https://api.github.com/users/wycats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wycats/subscriptions","organizations_url":"https://api.github.com/users/wycats/orgs","repos_url":"https://api.github.com/users/wycats/repos","events_url":"https://api.github.com/users/wycats/events{/privacy}","received_events_url":"https://api.github.com/users/wycats/received_events","type":"User","site_admin":false},"created_at":"2015-02-12T18:34:58Z","updated_at":"2015-02-12T18:34:58Z","body":"@sfackler I agree with @alexcrichton "}}