Summary

This RFC is to gather final feedback on stabilizing the new feature resolver in Cargo. This new feature resolver introduces a new algorithm for computing

計算する
package features that helps to avoid
避ける、回避する
some unwanted unification that happens in the current resolver. This also includes some changes in how features are enabled on the command-line.

These changes have already been implemented

実装する
and are available on the nightly channel as an unstable feature. See the unstable feature docs for information on how to test out the new resolver, and the unstable package flags for information on the new flag behavior.
ふるまい

Note: The new feature resolver does not address all of the enhancement requests for feature resolution. Some of these are listed

リスト、列挙する
below in the Feature resolver enhancements section.
These are explicitly
明示的に
deferred for future work.

Motivation

Feature unification

Currently, when features are computed

計算する
for a package, Cargo takes
とる
the union of all requested features in all situations for that package. This is relatively easy to understand, and ensures that packages are only built once during a single
単一の
build. However, this has problems when features introduce unwanted behavior,
ふるまい
dependencies,
依存、依存関係
or other requirements. The following three situations illustrate
描写する、示す
some of the unwanted feature unification that the new resolver aims to solve:

  • Unused targets: If a dependency

    依存、依存関係
    shows up multiple
    複数の
    times in the resolve
    解決する
    graph, and one of those situations is a target-specific dependency,
    依存、依存関係
    the features of the target-specific dependency
    依存、依存関係
    are enabled on all platforms. See target dependencies
    依存、依存関係
    below for how this problem is solved.

  • Dev-dependencies: If a dependency

    依存、依存関係
    is shared as a normal dependency
    依存、依存関係
    and a dev-dependency, then any features enabled on the dev-dependency will also show up when used as a normal dependency.
    依存、依存関係
    This only applies
    適用する
    to workspace packages; dev-dependencies in packages on registries like crates.io have always been ignored.
    無視する
    cargo install has also always ignored
    無視する
    dev-dependencies. See dev-dependencies below for how this problem is solved.

  • Host-dependencies: Similarly

    同様に
    to dev-dependencies, if a build-dependency or proc-macro has a shared dependency
    依存、依存関係
    with a normal dependency,
    依存、依存関係
    then the features are unified with the normal dependency.
    依存、依存関係
    See host dependencies
    依存、依存関係
    below for how this problem is solved.

Command-line feature selection
選択

Cargo has several flags for choosing which features are enabled during a build. --features allows

許可する、可能にする
enabling individual
個々の、それぞれの
features, --all-features enables all features, and --no-default-features ensures the "default" feature is not automatically
自動的に
enabled.

These are fairly straightforward when used with a single

単一の
package, but in a workspace the current behavior
ふるまい
is limited and confusing. There are several problems in a workspace:

  • cargo build -p other_member --features The listed
    リスト、列挙する
    features are for the package in the current directory, even if that package isn't being built! This also makes it difficult or impossible to build multiple
    複数の
    packages at once with different features enabled.
  • --features and --no-default-features flags are not allowed
    許可する、可能にする
    in the root of a virtual workspace.

See New command-line behavior

below for how these problems are solved.

Guide-level explanation

New resolver behavior
ふるまい

When the new feature resolver is enabled, features are not always unified when a dependency

依存、依存関係
appears
現れる
multiple
複数の
times in the dependency
依存、依存関係
graph. The new behaviors
ふるまい
are described
記述する
below.

For target dependencies

and dev-dependencies, the general
一般
rule is, if a dependency
依存、依存関係
is not built, it does not affect feature resolution. For host dependencies
依存、依存関係
, the general
一般
rule is that packages used for building (like proc-macros) do not affect the packages being built.

The following three sections

describe
記述する
the new behavior
ふるまい
for three difference situations.

Target dependencies
依存、依存関係

When a package appears

現れる
multiple
複数の
times in the build graph, and one of those instances
実例
is a target-specific dependency,
依存、依存関係
then the features of the target-specific dependency
依存、依存関係
are only enabled if the target is currently being built. For example:

[dependency.common] version = "1.0" features = ["f1"] [target.'cfg(windows)'.dependencies.common] version = "1.0" features = ["f2"]

When building this example for a non-Windows platform, the f2 feature will not be enabled.

dev-dependencies

When a package is shared as a normal dependency

依存、依存関係
and a dev-dependency, the dev-dependency features are only enabled if the current build is including dev-dependencies. For example:

[dependencies] serde = {version = "1.0", default-features = false} [dev-dependencies] serde = {version = "1.0", features = ["std"]}

In this situation, a normal cargo build will build serde without any features. When built with cargo test, Cargo will build serde with its default features plus the "std" feature.

Note that this is a global decision. So a command like cargo build --all-targets will include examples and tests, and thus

それゆえに、従って、
features from dev-dependencies will be enabled.

Host dependencies
依存、依存関係

When a package is shared as a normal dependency

依存、依存関係
and a build-dependency or proc-macro, the features for the normal dependency
依存、依存関係
are kept independent of the build-dependency or proc-macro. For example:

[dependencies] log = "0.4" [build-dependencies] log = {version = "0.4", features=['std']}

In this situation, the log package will be built with the default features for the normal dependencies.

依存、依存関係
As a build-dependency, it will have the std feature enabled. This means that log will be built twice,
2回
once without std and once with std.

Note that a dependency

依存、依存関係
shared between a build-dependency and proc-macro are still unified. This is intended to help reduce build times, and is expected to be unlikely to cause
起こす
problems that feature unification usually cause
起こす
because they are both being built for the host platform, and are only used at build time.

Resolver opt-in

Testing has been performed on various

さまざまな
projects. Some were found to fail to compile with the new resolver. This is because some dependencies
依存、依存関係
are written to assume
仮定する
that features are enabled from another part of the graph. Because the new resolver results
結果、戻り値
in a backwards-incompatible change in resolver behavior,
ふるまい
the user must opt-in to use the new resolver. This can be done with the resolver field in Cargo.toml:

[package] name = "my-package" version = "1.0.0" resolver = "2"

Setting

セットする、集合
the resolver to "2" switches Cargo to use the new feature resolver. It also enables backwards-incompatible behavior
ふるまい
detailed in New command-line behavior
ふるまい
. A value of "1" uses the previous
前の
resolver behavior,
ふるまい
which is the default if not specified.
特定する、指定する、規定する

The value is a string (instead of an integer) to allow

許可する、可能にする
for possible extensions in the future.

The resolver field is only honored in the top-level package or workspace, it is ignored

無視する
in dependencies.
依存、依存関係
This is because feature-unification is an inherently global decision.

If using a virtual workspace, the root definition

定義
should be in the [workspace] table like this:

[workspace] members = ["member1", "member2"] resolver = "2"

For packages that encounter

出会う
a problem due to missing feature declarations,
宣言
it is backwards-compatible to add the missing features. Adding
たす
those missing features should not affect projects using the old resolver.

It is intended that resolver = "2" will likely become the default setting

セットする、集合
in a future Rust Edition. See "Default opt-in" below for more details.

New command-line behavior
ふるまい

The following changes are made to the behavior

ふるまい
of selecting features on the command-line.

  • Features listed

    リスト、列挙する
    in the --features flag no longer pay attention to the package in the current directory. Instead, it only enables the given
    与えられた
    features for the selected packages. Additionally, the features are enabled only if the the package defines
    定義する
    the given
    与えられた
    features.

    For example:

    cargo build -p member1 -p member2 --features foo,bar

    In this situation, features "foo" and "bar" are enabled on the given

    与えられた
    members only if the member defines
    定義する
    that feature. It is still an error if none of the selected packages defines
    定義する
    a given
    与えられた
    feature.

  • Features for individual

    個々の、それぞれの
    packages can be enabled by using member_name/feature_name syntax.
    文法
    For example, cargo build --workspace --feature member_name/feature_name will build all packages in a workspace, and enable the given
    与えられた
    feature only for the given
    与えられた
    member.

  • The --features and --no-default-features flags may now be used in the root of a virtual workspace.

The ability to set

セットする、集合
features for non-workspace members is not allowed,
許可する、可能にする
as the resolver fundamentally does not support that ability.

The first change is only enabled if the resolver = "2" value is set

セットする、集合
in the workspace manifest because it is a backwards-incompatible change. The other changes are intended to be stabilized for everyone, as they only extend
拡張する
previously invalid usage.

cargo metadata

At this time, the cargo metadata command will not be changed to expose the new feature resolver. The "features" field will continue to display the features as computed

計算する
by the original dependency
依存、依存関係
resolver.

Properly expressing the dependency

依存、依存関係
graph with features would require a number of changes to cargo metadata that can add complexity to the interface. For example, the following flags would need to be added
たす
to properly show how features are selected:

  • Workspace selection
    選択
    flags (-p, --workspace, --exclude).
  • Whether or not dev-dependencies are included (--dep-kinds?).

Additionally, the current graph structure does not expose the host-vs-target dependency

依存、依存関係
relationship, among other issues.

It is intended that this will be addressed at some point in the future. Feedback on desired use cases for feature information will help define

定義する
the solution. A possible alternative
代わりのもの、選択肢
is to stabilize the --unit-graph flag, which exposes Cargo's internal graph structure, which accurately
正確に
indicates the actual
実際の
dependency
依存、依存関係
relationships and uses the new feature resolver.

For non-parseable output, cargo tree will show features from the new resolver.

Drawbacks

There are a number of drawbacks to this approach:

  • In some situations, dependencies

    依存、依存関係
    will be built multiple
    複数の
    times where they were previously only built once. This causes two problems: increased build times, and potentially broken builds when transitioning to the new resolver. It is intended that if the user wants to build a dependency
    依存、依存関係
    once that now has non-unified features, they will need to add feature declarations
    宣言
    within their dependencies
    依存、依存関係
    so that they once again have the same features. The cargo tree command has been added
    たす
    to help the user identify
    同定する、特定する
    and remedy these situations. cargo tree -d will expose dependencies
    依存、依存関係
    that are built multiple
    複数の
    times, and the -e features flag can be used to see which packages are enabling which features.

    Unfortunately the error message is not very clear when a feature that was previously assumed to be enabled is no longer enabled. Typically

    一般的に、典型的に
    these appear
    現れる
    in the form
    形式、形態、形作る
    of unresolved paths. In testing so far, this has come up occasionally, but is usually fairly easy to identify
    同定する、特定する
    what is wrong. Once more of the ecosystem starts using the new resolver, these errors should become less frequent.

  • Feature unification with dev-dependencies being a global decision can result

    結果、戻り値
    in some artifacts including features that may not be desired. For example, a project with a binary
    2進数
    and a shared dependency
    依存、依存関係
    that is used as a dev-dependency and a normal dependency.
    依存、依存関係
    When running cargo test the binary
    2進数
    will include the shared dev-dependency features. Compare this to a normal cargo build --bin name, where the binary
    2進数
    will be built without those features. This means that if you are testing a binary
    2進数
    with an integration test, you end up not testing the same thing as what is normally built. Changing this has significant drawbacks. Cargo's dependency
    依存、依存関係
    graph construction
    構築
    will require fundamental changes to support this scenario. Additionally, it has a high risk that will cause
    起こす
    increased build times for many projects that aren't affected or don't care that it may have slightly different features enabled.

  • This adds complexity to Cargo, and adds boilerplate to Cargo.toml. It can also be confusing when switching between projects that use different settings. It is intended in the future that new resolver will become the default via the "edition" declaration.

    宣言
    This will remove the extra boilerplate, and hopefully most projects will eventually adopt the new edition, so that there will be consistency between projects. See "Default opt-in" below for more details

  • This may not cover all of the backwards-incompatible changes that we may want to make to the feature resolver. At this time, we do not have any specific

    特定の
    enhancements planned that are backwards-incompatible, but there is a risk that additional
    追加の
    enhancements will require a bump to version "3" of the resolver field, causing further
    さらなる、それ以上
    ecosystem churn. Since there aren't any specific
    特定の
    changes on the horizon that we know will cause
    起こす
    problems, I am reluctant to force the new resolver to wait until some uncertain point in the future. See Future possibilities for a list
    リスト、列挙する
    of possible changes.

  • The new resolver has not had widespread testing. It is unclear if it covers most of the concerns that motivated it, or if there are shortcomings or problems. It is difficult to get sufficient testing, particularly when only available as an unstable feature.

Subtle behaviors
ふるまい

The following are behaviors

ふるまい
that may be confusing or surprising, and are highlighted here as potential concerns.

Optional
必須でない
dependency
依存、依存関係
feature names

  • dep_name/feat_name will always enable the feature dep_name, even if it is an inactive optional

    必須でない
    dependency
    依存、依存関係
    (such as a dependency
    依存、依存関係
    for another platform). The intent here is to be consistent where features are always activated when explicitly
    明示的に
    written, but the dependency
    依存、依存関係
    is not activated.

  • --all-features enables features for inactive optional

    必須でない
    dependencies
    依存、依存関係
    (but does not activate the dependency
    依存、依存関係
    ). This is consistent with --features foo enabling foo, even if the foo dependency
    依存、依存関係
    is not activated.

Code that needs to have a cfg expression

for a dependency
依存、依存関係
of this kind should use a cfg that matches
一致する、マッチさせる
the condition
条件
(like cfg(windows)) or use cfg(accessible(dep_name)) when that syntax
文法
is stabilized.

This is somewhat intertwined with the upcoming namespaced features. For an optional

必須でない
dependency,
依存、依存関係
the feature is decoupled from the activating of the dependency
依存、依存関係
itself.

Proc-macro unification in a workspace

If there is a proc-macro in a workspace, and the proc-macro is included as a "root" package along with other packages in a workspace (for example with cargo build --workspace), then there can be some potentially surprising feature unification between the proc-macro and the other members of the workspace. This is because proc-macros may have normal targets such as binaries

2進数
or tests, which need feature unification with the rest of the workspace.

This issue is detailed in issue #8312.

At this time, there isn't a clear solution to this problem. If this is an issue, projects are encouraged to avoid

避ける、回避する
using --workspace or use --exclude or otherwise
さもなければ
avoid
避ける、回避する
building multiple
複数の
workspace members together. This is also related to the workspace unification issue.

Rationale and alternatives
代わりのもの、選択肢

  • These changes could be forced on all users without an opt-in. The amount of breakage is not expected to be widespread, though limited testing has exposed that it will happen some of the time. Generally, Cargo tries to avoid

    避ける、回避する
    breaking changes that affect a significant portion of users, and we feel that breakage will come up often enough that an opt-in is the best route.

  • An alternative

    代わりのもの、選択肢
    approach would be to give the user manual
    マニュアル、手動
    control
    制御する
    over which specific
    特定の
    dependencies
    依存、依存関係
    are unified and which aren't. A similar
    似ている、同様の
    option would be feature masks.
    マスク、隠す
    This would likely be a tedious process, whereas hopefully this RFC's approach is more automatic
    自動の
    and streamlined for the common case.

Prior art

Other tools have various

さまざまな
ways of controlling
制御する
conditional
条件付き、条件的
compilation, but none are quite exactly
正確に
like Cargo to our knowledge. The following is a survey of a few tools with similar
似ている、同様の
capabilities.

Unresolved questions

None at this time.

Motivating issues

The Cargo issue tracker contains

含む
historical context
文脈、背景
for some of the requests that have motivated these changes:

  • #8088 Features 2.0 meta tracking issue.
  • #7914 Tracking issue for -Z features=itarget
    • #1197 Target-specific features
    • #2524 Conditional
      条件付き、条件的
      compilation of dependency
      依存、依存関係
      feature based
      基となる、基底(の)
      on target doesn't work
  • #7915 Tracking issue for -Z features=host_dep
    • #2589 Build Deps getting mixed in with dependencies
      依存、依存関係
    • #4361 Shared build+target dependency
      依存、依存関係
      crates conflate features
    • #4866 build-dependencies and dependencies
      依存、依存関係
      should not have features unified
    • #5730 Features of dependencies
      依存、依存関係
      are enabled if they're enabled in build-dependencies; breaks no_std libs
  • #7916 Tracking issue for -Z features=dev_dep
    • #1796 Incorrect dev-dependency feature resolution
    • #4664 Don't pass --features from dev-dependencies to dependencies
      依存、依存関係
  • #5364 New behavior
    ふるまい
    of --feature + --package combination
    • #4106 Testing workspace package with features expects the root package to have those features
    • #4753 Add support for --features and --no-default-features flags in workspace builds
    • #5015 building workspaces can't use --features flag
    • #5362 Cargo sometimes doesn't ungate crate features
    • #6195 Testing whole workspace with features enabled in some crate(s)

Future possibilities

Feature resolver enhancements

The following changes are things we are thinking about, but are not in a fully-baked state. It is uncertain if they will require backwards-incompatible changes or not.

  • Workspace feature unification. Currently the features enabled in a workspace depend on which workspace members are built (and those members' dependency
    依存、依存関係
    tree). Sometimes projects want to ensure
    保証する
    a dependency
    依存、依存関係
    is only built once, regardless
    〜に関わらず
    of which member included it, to avoid
    避ける、回避する
    duplicate builds, or surprising changes in behavior.
    ふるまい
    Sometimes projects want to ensure
    保証する
    dependencies
    依存、依存関係
    are not unified, since they don't want unrelated workspace members to affect one another. It seems likely this may require explicit
    明示的な
    notation
    記法
    to control
    制御する
    the behavior,
    ふるまい
    so it may be possible to add in a backwards-compatible fashion. There are also workarounds for this behavior,
    ふるまい
    so it is not as urgent.
  • Automatic
    自動の
    features. This allows
    許可する、可能にする
    a dependency
    依存、依存関係
    to automatically
    自動的に
    be enabled if it is already enabled somewhere else in the graph. rfc#1787
  • Profile and target default features.
  • Namespaced features. rust-lang/cargo#5565
  • Mutually-exclusive features. rust-lang/cargo#2980
  • Private and unstable features.
  • And many other issues and enhancements in the Cargo tracker: A-features

Default opt-in

We are planning to make it so that in the next Rust Edition, Cargo will automatically

自動的に
use the new resolver. It will assume
仮定する
you specify
特定する、指定する、規定する
resolver = "2" when a workspace specifies
特定する、指定する、規定する
the next edition. This may help reduce the boilerplate in the manifest, and make the preferred behavior
ふるまい
the default for new projects. Cargo has some precedent for this, as in the 2018 edition several defaults were changed. It is unclear how this would work in a virtual workspace, or if this will cause
起こす
additional
追加の
confusion, so this is left as a possibility to be explored in the future.

Default cargo new

In the short term,

項、用語
cargo new (and init) will not set
セットする、集合
the resolver field. After this feature has had some time on stable and more projects have some experience with it, the default manifest for cargo new will be modified to set
セットする、集合
resolver = "2".