Skip to content
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

panic not always tracked in built dependencies #5445

Closed
ehuss opened this issue May 1, 2018 · 11 comments · Fixed by #5458
Closed

panic not always tracked in built dependencies #5445

ehuss opened this issue May 1, 2018 · 11 comments · Fixed by #5458

Comments

@ehuss
Copy link
Contributor

ehuss commented May 1, 2018

Whether or not panic was used is not always tracked in the metadata hash. This can cause cargo to mistakenly reuse a lib with the wrong settings.

In particular, build-dependencies, plugins, and proc-macros and their dependencies do not encode that they were compiled without panic.

This can creep up in a variety of ways, but here is a relatively small repro:

mkdir ws
cd ws
cargo new --lib a
cargo new --lib pm
cat > Cargo.toml <<EOL
[workspace]
members = ["a", "pm"]
[profile.dev]
panic = "abort"
EOL

cat >> pm/Cargo.toml <<EOL
a = {path="../a"}
[lib]
proc-macro = true
EOL

echo "extern crate a;" >> pm/src/lib.rs

# This builds `a` with panic.
cargo build -p a -v
# This fails with wrong panic strategy since it reuses `a`.
cargo build -p pm -v
# Note: Compiling these in the other order works.

Fixing this is partially blocked by #5444, and possibly other issues.

@alexcrichton
Copy link
Member

Hm this is somewhat surprising, the fingerprint hash contains the entire Profile, right? which contains the panic setting?

@ehuss
Copy link
Contributor Author

ehuss commented May 1, 2018

Panic is set in the profile for proc-macros. It is only cleared at the end when the args are constructed here:

if let Some(panic) = panic.as_ref() {
if !cx.used_in_plugin.contains(unit) {
cmd.arg("-C").arg(format!("panic={}", panic));
}
}

Nothing in the hash indicates that a dependency is used by a proc-macro.

@alexcrichton
Copy link
Member

Ah ok makes sense! I think we should probably just include cx.used_in_plugin.contains(unit) in the fingerprint, right?

@alexcrichton
Copy link
Member

This should be fixed at #5458

alexcrichton added a commit to alexcrichton/cargo that referenced this issue May 2, 2018
Ensure that if we've previously compiled a crate with panic=abort and we later
need it for panic=unwind we correctly recompile it.

Closes rust-lang#5445
bors added a commit that referenced this issue May 2, 2018
Track panic mode in fingerprint

Ensure that if we've previously compiled a crate with panic=abort and we later
need it for panic=unwind we correctly recompile it.

Closes #5445
@ehuss
Copy link
Contributor Author

ehuss commented May 2, 2018

I was thinking about clearing the panic flag when the profile is constructed. That would fix dependencies shared with proc-macro dependencies (currently shared dependencies are built without panic set).

@alexcrichton
Copy link
Member

@ehuss ah yes I think that'd probably be the best solution, I was hoping for a quick fix as this is a pretty serious bug and beta is being branched this weekend. That sounds like a good follow-up though!

@ehuss
Copy link
Contributor Author

ehuss commented May 2, 2018

@alexcrichton kk, i'm working on it now, will hopefully get the bugs nailed down before then.

@alexcrichton
Copy link
Member

Awesome, thanks!

@bors bors closed this as completed in #5458 May 2, 2018
@alexcrichton
Copy link
Member

@ehuss btw do you have an example which still fails to build after #5458? If so I can reopen

@ehuss
Copy link
Contributor Author

ehuss commented May 2, 2018

@alexcrichton Shared dependencies will be built w/o panic:

cargo new --bin foo
cd foo
cargo new --lib shared
cargo new --lib pm

cat >> pm/Cargo.toml <<EOF
shared = {path = "../shared"}
[lib]
proc-macro = true
EOF

cat >> Cargo.toml <<EOF
pm = {path = "pm"}
shared = {path = "shared"}

[profile.dev]
panic = "abort"
EOF

# `shared` will be built without panic.
cargo build -v

This doesn't cause any errors since linking with unwind dependencies doesn't fail.

I can't remember if I asked already, but what are the specific problems with linking with a lib built with unwind? It sure would be easier if we could just set panic for bins.

@alexcrichton
Copy link
Member

@ehuss oh that's the previous behavior of Cargo, right?

It's totally ok to link a panic=abort final artifact to intermediate libraries that are compiled as panic=unwind, but you just can't do the reverse.

I do think though that it'd be best to compile the lib twice, once with unwind and once with abort, but if it's not a regression then that at least buys us some more time!

bors added a commit that referenced this issue Oct 15, 2018
Track `panic` in Unit early.

This is an alternate solution for #5445. It ensures that `panic` is cleared in the Profile for "for_host" targets (proc-macro/plugin/build-scripts) and dependencies. This helps avoid unnecessary recompiles in some situations (though does add extra units in some situations, see below).

Some examples where extra rebuilds are now avoided:
* A workspace with a dependency shared with normal and build-deps.  `build --all` should build everything, and then `build -p foo` was causing a recompile because the shared dep was no longer in the `used_in_plugin` set. Now it should not recompile.
* `panic=abort`, with a shared dependency in build and dev, `build` would cause that shared dependency to be built twice (exactly the same without panic set). Now it should only build once.

Some examples where `panic` is now set correctly:
* `panic=abort`, with a binary with a shared dependency in build and normal, `test` would cause that shared dependency to be built twice (exactly the same without panic set).  Now it is still built twice, but the one for the normal (bin) dependency will correctly have `panic` set.

Some examples where new units are now generated:
* `panic=abort`, with shared dependency between normal and proc-macro or build. Previously the shared dependency was built once with `panic=unwind`. Now it is built separately (once with `panic`, once without). I feel like that this is more correct behavior — that now the normal dependency avoids adding landing pads.

   For `panic=abort` cross-compiling, this makes no difference in compile time since it was already built twice.

Additional notes:
- I left build-scripts with the old behavior where `panic` is cleared for it and all its dependencies. There could be arguments made to change that (#5436), but it doesn't seem important to me.
- Renamed and refactored `ProfileFor` to `UnitFor`. I expect this API to continue to evolve in the future.

Closes #6143, closes #6154.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants