-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Add an unstable --json=unused-externs flag to print unused externs #73945
Conversation
r? @davidtwco (rust_highfive has picked a reviewer for you, use r? to override) |
This is an interesting approach. I can see a possible path to making Buck support this, but it would need some philosophical discussion about how concerns should be separated (ie, is it really up to Buck to diagnose unused dependencies?). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation looks good to me.
r? @estebank |
I haven't had a chance to test and review this in depth, but one minor thing I think would be good to discuss is adding some kind of tag to the JSON messages so they can be easily distinguished. For example, Cargo uses the
Can you say more? I was assuming #72342 would be sufficient for your use case, and Buck wouldn't need to use this extra flag. |
Yeah currently cargo tries to deserialize each message by its type one after another https://github.com/rust-lang/cargo/blob/0506d8d5c9dd229c94641dd39a37bd947dc0a770/src/cargo/core/compiler/mod.rs#L1192 One could put everything into an enum that's internally tagged. This would create a tag value for each of the messages. Tools that invoke rustc can then do with it whatever they want. Ignore it, or create an enum of their own. https://serde.rs/enum-representations.html#internally-tagged If there's support, I can make a PR to add an enum to rustc. |
@ehuss Well, it would be ideal if we can make one mechanism work well for everything. As I see it the pros and cons of the two approaches are: -Wunused-crate-dependencies:
--json=unused-externs:
Strictly speaking, --json=unused-externs isn't necessary if you have -Wunused-crate-dependencies, since in principle Cargo could parse the diagnostics output and look for the appropriate messages and consume/process/filter them. But it does leave awkwardness like the number of warnings being wrong unless Cargo also corrects those which is messy. |
This comment has been minimized.
This comment has been minimized.
Huh, tests still failing. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@bors r+ Sorry for the delay here. This looks good to me. |
📌 Commit d018ef1 has been approved by |
⌛ Testing commit d018ef1 with merge 1efaea80dd096579f012c5fc418efd2f3e0554a3... |
💔 Test failed - checks-actions |
@bors retry |
A job failed! Check out the build log: (web) (plain) Click to see the possible cause of the failure (guessed by this bot)
|
…crum Add an unstable --json=unused-externs flag to print unused externs This adds an unstable flag to print a list of the extern names not used by cargo. This PR will enable cargo to collect unused dependencies from all units and provide warnings. The companion PR to cargo is: rust-lang/cargo#8437 The goal is eventual stabilization of this flag in rustc as well as in cargo. Discussion of this feature is mostly contained inside these threads: rust-lang#57274 rust-lang#72342 rust-lang#72603 The feature builds upon the internal datastructures added by rust-lang#72342 Externs are uniquely identified by name and the information is sufficient for cargo. If the mode is enabled, rustc will print json messages like: ``` {"unused_extern_names":["byteorder","openssl","webpki"]} ``` For a crate that got passed byteorder, openssl and webpki dependencies but needed none of them. ### Q: Why not pass -Wunused-crate-dependencies? A: See [ehuss's comment here](rust-lang#57274 (comment)) TLDR: it's cleaner. Rust's warning system wasn't built to be filtered or edited by cargo. Even a basic implementation of the feature would have to change the "n warnings emitted" line that rustc prints at the end. Cargo ideally wants to synthesize its own warnings anyways. For example, it would be hard for rustc to emit warnings like "dependency foo is only used by dev targets", suggesting to make it a dev-dependency instead. ### Q: Make rustc emit used or unused externs? A: Emitting used externs has the advantage that it simplifies cargo's collection job. However, emitting unused externs creates less data to be communicated between rustc and cargo. Often you want to paste a cargo command obtained from `cargo build -vv` for doing something completely unrelated. The message is emitted always, even if no warning or error is emitted. At that point, even this tiny difference in "noise" matters. That's why I went with emitting unused externs. ### Q: One json msg per extern or a collective json msg? A: Same as above, the data format should be concise. Having 30 lines for the 30 crates a crate uses would be disturbing to readers. Also it helps the cargo implementation to know that there aren't more unused deps coming. ### Q: Why use names of externs instead of e.g. paths? A: Names are both sufficient as well as neccessary to uniquely identify a passed `--extern` arg. Names are sufficient because you *must* pass a name when passing an `--extern` arg. Passing a path is optional on the other hand so rustc might also figure out a crate's location from the file system. You can also put multiple paths for the same extern name, via e.g. `--extern hello=/usr/lib/hello.rmeta --extern hello=/usr/local/lib/hello.rmeta`, but rustc will only ever use one of those paths. Also, paths don't identify a dependency uniquely as it is possible to have multiple different extern names point to the same path. So paths are ill-suited for identification. ### Q: What about 2015 edition crates? A: They are fully supported. Even on the 2015 edition, an explicit `--extern` flag is is required to enable `extern crate foo;` to work (outside of sysroot crates, which this flag doesn't warn about anyways). So the lint would still fire on 2015 edition crates if you haven't included a dependency specified in Cargo.toml using `extern crate foo;` or similar. The lint won't fire if your sole use in the crate is through a `extern crate foo;` statement, but that's not its job. For detecting unused `extern crate foo` statements, there is the `unused_extern_crates` lint which can be enabled by `#![warn(unused_extern_crates)]` or similar. cc `@jsgf` `@ehuss` `@petrochenkov` `@estebank`
…crum Add an unstable --json=unused-externs flag to print unused externs This adds an unstable flag to print a list of the extern names not used by cargo. This PR will enable cargo to collect unused dependencies from all units and provide warnings. The companion PR to cargo is: rust-lang/cargo#8437 The goal is eventual stabilization of this flag in rustc as well as in cargo. Discussion of this feature is mostly contained inside these threads: rust-lang#57274 rust-lang#72342 rust-lang#72603 The feature builds upon the internal datastructures added by rust-lang#72342 Externs are uniquely identified by name and the information is sufficient for cargo. If the mode is enabled, rustc will print json messages like: ``` {"unused_extern_names":["byteorder","openssl","webpki"]} ``` For a crate that got passed byteorder, openssl and webpki dependencies but needed none of them. ### Q: Why not pass -Wunused-crate-dependencies? A: See [ehuss's comment here](rust-lang#57274 (comment)) TLDR: it's cleaner. Rust's warning system wasn't built to be filtered or edited by cargo. Even a basic implementation of the feature would have to change the "n warnings emitted" line that rustc prints at the end. Cargo ideally wants to synthesize its own warnings anyways. For example, it would be hard for rustc to emit warnings like "dependency foo is only used by dev targets", suggesting to make it a dev-dependency instead. ### Q: Make rustc emit used or unused externs? A: Emitting used externs has the advantage that it simplifies cargo's collection job. However, emitting unused externs creates less data to be communicated between rustc and cargo. Often you want to paste a cargo command obtained from `cargo build -vv` for doing something completely unrelated. The message is emitted always, even if no warning or error is emitted. At that point, even this tiny difference in "noise" matters. That's why I went with emitting unused externs. ### Q: One json msg per extern or a collective json msg? A: Same as above, the data format should be concise. Having 30 lines for the 30 crates a crate uses would be disturbing to readers. Also it helps the cargo implementation to know that there aren't more unused deps coming. ### Q: Why use names of externs instead of e.g. paths? A: Names are both sufficient as well as neccessary to uniquely identify a passed `--extern` arg. Names are sufficient because you *must* pass a name when passing an `--extern` arg. Passing a path is optional on the other hand so rustc might also figure out a crate's location from the file system. You can also put multiple paths for the same extern name, via e.g. `--extern hello=/usr/lib/hello.rmeta --extern hello=/usr/local/lib/hello.rmeta`, but rustc will only ever use one of those paths. Also, paths don't identify a dependency uniquely as it is possible to have multiple different extern names point to the same path. So paths are ill-suited for identification. ### Q: What about 2015 edition crates? A: They are fully supported. Even on the 2015 edition, an explicit `--extern` flag is is required to enable `extern crate foo;` to work (outside of sysroot crates, which this flag doesn't warn about anyways). So the lint would still fire on 2015 edition crates if you haven't included a dependency specified in Cargo.toml using `extern crate foo;` or similar. The lint won't fire if your sole use in the crate is through a `extern crate foo;` statement, but that's not its job. For detecting unused `extern crate foo` statements, there is the `unused_extern_crates` lint which can be enabled by `#![warn(unused_extern_crates)]` or similar. cc ``@jsgf`` ``@ehuss`` ``@petrochenkov`` ``@estebank``
Rollup of 8 pull requests Successful merges: - rust-lang#73945 (Add an unstable --json=unused-externs flag to print unused externs) - rust-lang#81619 (Implement `SourceIterator` and `InPlaceIterable` for `ResultShunt`) - rust-lang#82726 (BTree: move blocks around in node.rs) - rust-lang#83521 (2229: Fix diagnostic issue when using FakeReads in closures) - rust-lang#83532 (Fix compiletest on FreeBSD) - rust-lang#83793 (rustdoc: highlight macros more efficiently) - rust-lang#83809 (Remove unneeded INITIAL_IDS const) - rust-lang#83827 (cleanup leak after test to make miri happy) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
BTW I've been using this in some experiments and it works out really well in our new build system. |
This adds an unstable flag to print a list of the extern names not used by cargo.
This PR will enable cargo to collect unused dependencies from all units and provide warnings.
The companion PR to cargo is: rust-lang/cargo#8437
The goal is eventual stabilization of this flag in rustc as well as in cargo.
Discussion of this feature is mostly contained inside these threads: #57274 #72342 #72603
The feature builds upon the internal datastructures added by #72342
Externs are uniquely identified by name and the information is sufficient for cargo.
If the mode is enabled, rustc will print json messages like:
For a crate that got passed byteorder, openssl and webpki dependencies but needed none of them.
Q: Why not pass -Wunused-crate-dependencies?
A: See ehuss's comment here
TLDR: it's cleaner. Rust's warning system wasn't built to be filtered or edited by cargo.
Even a basic implementation of the feature would have to change the "n warnings emitted" line that rustc prints at the end.
Cargo ideally wants to synthesize its own warnings anyways. For example, it would be hard for rustc to emit warnings like
"dependency foo is only used by dev targets", suggesting to make it a dev-dependency instead.
Q: Make rustc emit used or unused externs?
A: Emitting used externs has the advantage that it simplifies cargo's collection job.
However, emitting unused externs creates less data to be communicated between rustc and cargo.
Often you want to paste a cargo command obtained from
cargo build -vv
for doing somethingcompletely unrelated. The message is emitted always, even if no warning or error is emitted.
At that point, even this tiny difference in "noise" matters. That's why I went with emitting unused externs.
Q: One json msg per extern or a collective json msg?
A: Same as above, the data format should be concise. Having 30 lines for the 30 crates a crate uses would be disturbing to readers.
Also it helps the cargo implementation to know that there aren't more unused deps coming.
Q: Why use names of externs instead of e.g. paths?
A: Names are both sufficient as well as neccessary to uniquely identify a passed
--extern
arg.Names are sufficient because you must pass a name when passing an
--extern
arg.Passing a path is optional on the other hand so rustc might also figure out a crate's location from the file system.
You can also put multiple paths for the same extern name, via e.g.
--extern hello=/usr/lib/hello.rmeta --extern hello=/usr/local/lib/hello.rmeta
,but rustc will only ever use one of those paths.
Also, paths don't identify a dependency uniquely as it is possible to have multiple different extern names point to the same path.
So paths are ill-suited for identification.
Q: What about 2015 edition crates?
A: They are fully supported.
Even on the 2015 edition, an explicit
--extern
flag is is required to enableextern crate foo;
to work (outside of sysroot crates, which this flag doesn't warn about anyways).So the lint would still fire on 2015 edition crates if you haven't included a dependency specified in Cargo.toml using
extern crate foo;
or similar.The lint won't fire if your sole use in the crate is through a
extern crate foo;
statement, but that's not its job.For detecting unused
extern crate foo
statements, there is theunused_extern_crates
lintwhich can be enabled by
#![warn(unused_extern_crates)]
or similar.cc @jsgf @ehuss @petrochenkov @estebank