Inconsistent feature resolution with artifact dependencies (bindeps) depending on whether or not the target
key is specified
#11547
Labels
C-bug
Category: bug
S-needs-mentor
Status: Issue or feature is accepted, but needs a team member to commit to helping and reviewing.
Z-bindeps
Nightly: binary artifact dependencies
The issue here can be reproduced by the following repo: https://github.com/bstrie/bindeperror6 (you will need to manually comment out one of the two duplicate bindep lines in Cargo.toml, which demonstrate different behavior).
Assume the following conditions:
There are two questions to answer here:
Let's continue using the repo linked above.
With the line
mybindep = { path = "mybindep", artifact = "bin" }
in Cargo.toml, we can runcargo clean && cargo build -v
and observe only a single invocation ofrustc
, which features the flag--cfg 'feature="XXX"'
, demonstrating that features have been merged in the shared dependency.However, with the line
mybindep = { path = "mybindep", artifact = "bin", target = "x86_64-unknown-linux-gnu" }
(note the explicittarget
key), we can runcargo clean && cargo build -v
to observe that rustc is invoked twice, where the only difference between the invocation is--cfg 'feature="XXX"'
(as well as a different hash value, to uniquely identify the compiled artifacts). This produces two versions of the shared dependency with different feature profiles. This would be ordinary if the host/default target were different from the target listed for the bindep, but in this case both targets arex86_64-unknown-linux-gnu
.We can show that this is due to the presence of the
target
key in Cargo.toml, rather than due to an edge case of the listed target being equal to the host target. With the linemybindep = { path = "mybindep", artifact = "bin", target = "x86_64-unknown-linux-musl" }
(note that the target is now musl), we can runcargo clean && cargo build -v --target x86_64-unknown-linux-musl
to show that the shared dependency is once again compiled twice, with two distinct feature sets.Intuitively, it seems like users should be able to assume that the behavior here should depend on the targets that are ultimately selected, rather than presence or absence of the
target
key itself. Thus, this is a bug regardless of which behavior is correct.As for resolving this inconsistency, we need to determine which behavior is actually desired. On the one hand, aggressively unifying features can reduce compilation times and disk usage. On the other hand, it was an over-aggressive approach to feature unification that led to the introduction of the 2.0 feature resolver, which deliberately reduces the amount of unification that is done between artifacts of different categories (dev-dependencies, build-dependencies, etc.), even at the potential expense of build times. We can argue that artifact dependencies are just such a "different category" of artifact, which should be allowed to have independent, non-unified feature profiles. The advantages of this are: it makes the bindeps feature a drop-in replacement for the current stable workaround (shelling out to Cargo in a build script); it potentially reduces the binary size of artifact dependencies by eliminating features that are entirely unused; and it allows users reduce the number of transitive dependencies (via optional dependencies) relied upon by an artifact dependency, thus decreasing its trusted computing base, which matters in a world where awareness of supply chain attacks is rapidly increasing. (This last point is of particular concern for our use case specifically, since our bindeps are run in a more secure context than the main crate.)
The text was updated successfully, but these errors were encountered: