Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upFeature selection in workspace depends on the set of packages compiled #4463
Comments
matklad
added
the
C-bug
label
Sep 3, 2017
This comment has been minimized.
This comment has been minimized.
|
So, it has to do with features. Namely, two cargo invocations produce two different libcs:
The only difference is So, I get two different libcs in target:
But I get a single memchr:
The file name is the same for both cargo commands, but the actual contents differs. |
This comment has been minimized.
This comment has been minimized.
|
Hm, so this looks like more serious then spurious rebuild! Depending on what |
This comment has been minimized.
This comment has been minimized.
|
Minimized example here: https://github.com/matklad/workspace-vs-feaures |
matklad
added
A-features
A-workspaces
labels
Sep 3, 2017
matklad
referenced this issue
Sep 5, 2017
Merged
Hashed dependencies of metadata into the metadata of a lib #4469
matklad
changed the title
Spurious rebuilds when testing different packages of a workspace
Feature selection in workspace depends on the set of packages compiled
Sep 5, 2017
This comment has been minimized.
This comment has been minimized.
|
@alexcrichton continuing discussion here, instead of #4469 which is somewhat orthogonal, as you've rightly pointed out!
Yeah, it looks like what we ideally want here is that each final artifact gets the minimal set of features. And this should work even withing a single package: currently, activating feature in Though such fine-grained feature activation will cause more compilation work overall, so using union of featues might be a pragmatic choice, as long as we keep features additive, and it sort of makes sense, because crates in workspace share dependencies anyway. And seems better then definitely some random unrelated target activating features for you depending on the command line flags. |
This comment has been minimized.
This comment has been minimized.
|
I think one of the main problems right now is that we're doing feature resolution far too soon, during the crate graph resolution. Instead what we should be doing is assuming all features are activated until we actually start compiling crates. That way if you have multiple targets all requesting different sets of features they'll all get separately compiled copies with the correct set of features. Does that make sense? Or perhaps solving a different problem? |
This comment has been minimized.
This comment has been minimized.
Yeah, totally, "they'll all get separately compiled copies with the correct set of features" is the perfect solution here, and it could be implemented by moving feature selection after the dependency resolution. But I am really worried about additional work to get separately compiled copies, because it is multiplicative. Let's say you have a workspace with the following layout:
Because A and B require different features from libc, and because libc happens to be at the bottom of the dependency graph, that means that for So it's not that only libc will get duplicated, the whole graph may be duplicated in the worst case. |
This comment has been minimized.
This comment has been minimized.
|
If we assume that features are additive (as intended), then the innermost crate could be compiled once with the union of all features. Additive features are a bit of a subtle point though (see #3620). Recompiling is the safest way, though expensive. |
This comment has been minimized.
This comment has been minimized.
|
@matklad yeah you're definitely right that the more aggressively we cache the more we end up caching :). @nipunn1313 you're also right that it should be safe for features to be unioned, but they often come with runtime or linkage implications. For example if a workspace has a I basically see this as there's a specification of what Cargo should be doing here. We've got, for example, two crates in a workspace, each which activates various sets of features in shared dependencies. Today Cargo does the "thing that caches too much" if you compile each separately (and also suffers a bug when you switch between projects it recompiles too much). Cargo also does the "union all the features" if you build both crates simultaneously (e.g. I'd advocate that Cargo should try to stick to the "caches too much" solution as it's following the letter of the law of what you wrote down for a workspace. It also means that crates in a workspace don't need to worry too much about interfering with other crates in a workspace. Projects that run into problems of the "too much is cached" nature I'd imagine could then do the investigation to figure out what features are turned on where, and try to get each workspace member to share more dependencies by unifying the features. |
This comment has been minimized.
This comment has been minimized.
This somewhat resolves my concern about build times, but not entirely. I am worried that it might not be easy to unify features manually, if they are turned on by private transitive dependencies. It would be possible to do by adding this private transitive dependency as an explicit and unused dependency, but this looks accidental. But now I too lean towards fine-grained features solution. |
This comment has been minimized.
This comment has been minimized.
|
For what it's worth, we've done that exact trick with the parallel feature
of the gcc crate. It does happen, but the workaround is ok.
…On Wed, Sep 6, 2017 at 12:45 AM Aleksey Kladov ***@***.***> wrote:
Projects that run into problems of the "too much is cached" nature I'd
imagine could then do the investigation to figure out what features are
turned on where, and try to get each workspace member to share more
dependencies by unifying the features.
This somewhat resolves my concern about build times, but not entirely. I
am worried that it might not be easy to unify features manually, if they
are turned on by private transitive dependencies. It would be possible to
do by adding this private transitive dependency as an explicit and unused
dependency, but this looks accidental.
But now I too lean towards fine-grained features solution.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4463 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABPXoxPIsKCCcH5DEgqtKzPt9ek34uLeks5sfk2EgaJpZM4PLGrK>
.
|
matklad
referenced this issue
Sep 18, 2017
Closed
Add a 'worskpace.default-packages' config to override implied --all? #4507
This comment has been minimized.
This comment has been minimized.
|
Servo relies on the current behavior to some extent: two "top-level" crates (one executable and one C-compatible static library) depend on a shared library crate but enable different Cargo features. These features are mutually exclusive, enabling the union would not work. Maybe the "right" thing to do here is to have separate workspaces for the different top-level things? Does it make sense for shared (Servo’s build system sets |
This comment has been minimized.
This comment has been minimized.
|
I would be in support of What makes this problem so insidious is that there's no way to enforce or even encourage the union property of features. If a project pulls in even one dependency that doesn't obey this property, it could potentially create an incorrect binary. In @SimonSapin's case with Servo, I think Servo is lucky that the feature'd crate (
then I believe that compiling Our project at Dropbox ran into a similar issue with itertools -> libeither, where libeither was compiled with two different features. Lucky for us, libeither's features are union-safe, so the code was correct, but it did create spurious recompiles depending on which sub-crate we were compiling. |
This comment has been minimized.
This comment has been minimized.
|
I agree with @nipunn1313 -- I think |
SimonSapin
referenced this issue
Oct 13, 2017
Merged
Make optional the usage of some unstable features #18854
This comment has been minimized.
This comment has been minimized.
|
This all sounds like agreement on what should happen. @alexcrichton, what code changes need to happen (on a high level) to get there? |
This comment has been minimized.
This comment has been minimized.
|
That's what I was discussing with @alexcrichton at the RustFest impl days, and I have a bunch of refactoring done that I'm still tweaking. Will post a PR ASAP. Do you have a particular dependency/urgency relating to Gecko or Servo on this? |
This comment has been minimized.
This comment has been minimized.
|
Nothing urgent. I thought this bug could cause spurious rebuilds after selectively building a crate with |
This comment has been minimized.
This comment has been minimized.
|
We've had to fork some deps to unify feature selection to work around this
issue. It's definitely not sustainable for us, but not urgent yet.
…--Nipunn
On Sat, Oct 14, 2017 at 5:27 AM Simon Sapin ***@***.***> wrote:
Nothing urgent. I thought this bug could cause spurious rebuilds after
selectively building a crate with -p, but I couldn’t reproduce. Anyway,
thanks for working on this!
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4463 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABPXo7HL7OuZhSaMgZMtY9Y5IxnY7dHFks5ssKjIgaJpZM4PLGrK>
.
|
This comment has been minimized.
This comment has been minimized.
|
@nipunn1313 for my understanding, can you point me at a commit or otherwise elaborate on what problems you've had due to this issue? |
This comment has been minimized.
This comment has been minimized.
|
Here's an example of a problem we had to work around In that particular case, either and itertools were both present in our workspace. |
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin taking on this issue will require a relatively significant refactoring of Cargo's backend. Right now feature resolution happens during crate graph resolution, but we need to defer it all the way until the very end when we're actually compiling crates. |
SimonSapin
referenced this issue
Oct 28, 2017
Open
build: Don't build clap if we're being used as a library. #1111
SimonSapin
added a commit
to servo/servo
that referenced
this issue
Dec 4, 2017
SimonSapin
added a commit
to servo/servo
that referenced
this issue
Dec 4, 2017
SimonSapin
added a commit
to servo/servo
that referenced
this issue
Dec 4, 2017
SimonSapin
added a commit
to servo/servo
that referenced
this issue
Dec 5, 2017
bors-servo
added a commit
to servo/servo
that referenced
this issue
Dec 5, 2017
bors-servo
added a commit
to servo/servo
that referenced
this issue
Dec 5, 2017
SimonSapin
added a commit
to servo/servo
that referenced
this issue
Dec 5, 2017
SimonSapin
added a commit
to servo/servo
that referenced
this issue
Dec 5, 2017
SimonSapin
added a commit
to servo/servo
that referenced
this issue
Dec 5, 2017
SimonSapin
added a commit
to servo/servo
that referenced
this issue
Dec 7, 2017
bors-servo
added a commit
to servo/servo
that referenced
this issue
Dec 7, 2017
SimonSapin
added a commit
to servo/servo
that referenced
this issue
Dec 7, 2017
bors-servo
added a commit
to servo/servo
that referenced
this issue
Dec 7, 2017
moz-v2v-gh
pushed a commit
to mozilla/gecko-dev
that referenced
this issue
Dec 8, 2017
xeonchen
pushed a commit
to xeonchen/gecko-cinnabar
that referenced
this issue
Dec 8, 2017
aethanyc
pushed a commit
to aethanyc/gecko-dev
that referenced
this issue
Dec 19, 2017
hcpl
added a commit
to hcpl/mtproto-rs
that referenced
this issue
Dec 30, 2017
SimonSapin
referenced this issue
Mar 9, 2018
Open
build-dependencies and dependencies should not have features unified #4866
ishitatsuyuki
referenced this issue
Mar 20, 2018
Open
Resolve feature and optional dependencies for workspace as a whole #5210
This comment has been minimized.
This comment has been minimized.
driftluo
commented
Mar 27, 2018
•
|
Today, I encountered a problem with the overall compilation of the workspace and the inconsistent compilation of each crate. We have a public logger crate, the default is output to a file, open Some crates in the workspace have this feature turned on, while others do not need to be turned on. But This behavior makes me very confused. |
matklad
referenced this issue
Mar 29, 2018
Closed
Spurious rebuild in crate repo with workspace #5262
driftluo
added a commit
to cryptape/cita-common
that referenced
this issue
Mar 30, 2018
driftluo
added a commit
to cryptape/cita-common
that referenced
this issue
Mar 30, 2018
driftluo
referenced this issue
Mar 30, 2018
Merged
Due to cargo issue, rollback logger, undo features #52
u2
added a commit
to cryptape/cita-common
that referenced
this issue
Apr 4, 2018
This was referenced Apr 28, 2018
acmcarther
referenced this issue
Jun 21, 2018
Open
CrateContext.features needs to be specialized using the target_triple #53
ehuss
referenced this issue
Oct 20, 2018
Open
Testing whole workspace with features enabled in some crate(s) #6195
This comment has been minimized.
This comment has been minimized.
idubrov
commented
Mar 8, 2019
|
Regarding:
I hacked together a crude tool that compares output of multiple
[enable-features] # some better name
# for all the dependencies of `syn` in the workspace matching version `0.15`,
# forcefully enable "visit-mut" and "extra-traits" features.
syn = { version = "0.15", features = ["visit-mut", "extra-traits"] }? This is pretty much to avoid crude solution I outlined here: https://users.rust-lang.org/t/forcing-set-of-features-for-shared-dependencies-across-targets-in-workspace/25899 (I don't really want to have "fake" dependencies or tune features across multiple
First, it improves compilation times (as explained in my post on users.rust-lang.org). Second, I found that inconsistent features break the following use-case I have (which might be a not fully valid one?):
So, when features are consistent on However, when features are not consistent (say, It seems like dynamic libraries is still an unfinished story in Rust, so I don't know what really I could be asking here (it might be that it "works" only accidentally?). |
matklad commentedSep 3, 2017
Reproduction:
Check out this commit: matklad/fall@3022be4
Build some test with
cargo test -p fall_test -p fall_test -p lang_rust -p lang_rust -p lang_json --verbose --no-runBuild other tests with
cargo test --all --verbose --no-runRun
cargo test -p fall_test -p fall_test -p lang_rust -p lang_rust -p lang_json --verbose --no-runagain and observe thatmemchrand some other dependencies are recompiled.Run
cargo test --all --verbose --no-runand observememchrrecompiled again.The verbose flag gives the following commands for
memchr:Here's the single difference:
Versions (whyyyyy cargo is 0.21 and rustc is 1.20??? This is soo confusing)