Skip to content

--extern-location to specify where an --extern dependency is defined #303

Closed
@jsgf

Description

@jsgf

What is this issue?

This is a major change proposal, which means a proposal to make a notable change to the compiler -- one that either alters the architecture of some component, affects a lot of people, or makes a small but noticeable public change (e.g., adding a compiler flag). You can read more about the MCP process on https://forge.rust-lang.org/.

This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed.

MCP Checklist

  • MCP filed. Automatically, as a result of filing this issue:
    • The @rust-lang/wg-prioritization group will add this to the triage meeting agenda so folks see it.
    • A Zulip topic in the stream #t-compiler/major changes will be created for this issue.
  • MCP seconded. The MCP is "seconded" when a compiler team member or contributor issues the @rustbot second command. This should only be done by someone knowledgable with the area -- before seconding, it may be a good idea to cc other stakeholders as well and get their opinion.
  • Final comment period (FCP). Once the MCP is approved, the FCP begins and lasts for 10 days. This is a time for other members to review and raise concerns -- concerns that should block acceptance should be noted as comments on the thread, ideally with a link to Zulip for further discussion.
  • MCP Accepted. At the end of the FCP, a compiler team lead will review the comments and discussion and decide whether to accept the MCP.
    • At this point, the major-change-accepted label is added and the issue is closed. You can link to it for future reference.

A note on stability. If your change is proposing a new stable feature, such as a -C flag, then a full team checkoff will be required before the feature can be landed. Often it is better to start with an unstable flag, like a -Z flag, and then move to stabilize as a secondary step.

TL;DR

--extern-location allows a build system to provide better detail about how a unused-crate-dependency warning can be resolved - eg with details on how the Cargo.toml can be updated to remove an unused dependency.

Links and Details

PR rust-lang/rust#72342 introduced the unused-crate-dependency warning, which warns if a crate was specified on the command line with --extern name=path, but that name wasn't referenced in the source. The diagnostic suggests either removing the dependency or adding a dummy reference of the form use name as _;.

The problem is that the "removing dependency" suggestion is vague, as rustc has no idea about how the dependency was specified in the first place, as it is specific to the build system and is out of scope for rustc itself. Also, assuming that removing the dependency is almost always the right course of action, this should be easily automated so that unused dependencies can be mass-removed.

This MCP proposes a --extern-location option which passes information from the build system to rustc, primarily so that rustc can echo it back to the user via a diagnostic message, or back to tooling via json diagnostics.

These options would be paired with --extern options, so a typical use would be --extern foo=path/to/libfoo.rlib --extern-location foo=raw:Cargo.toml:123, where the name foo is the key which joins them.

--extern-location is not used for pathless (sysroot) --extern (eg --extern proc_macro). These are not subject to unused-crate-dependencies warnings and are typically added implicitly anyway.

The goal is to make this build-system independent, rather than just assuming we're always building with Cargo. As such, it needs enough flexibility to be able to express the definition of a dependency in a build-system-generic way.

I have several proposed forms of location:

  • file:<path>:<lineno> - reference a specific line in a file
  • span:<path>:<startbyte>:<endbyte> - reference a span of bytes in a file
  • raw:<string> - uninterpreted text string which is emitted via the diagnostic and json
  • json:<jsondata> - json with an arbitrary schema which is emitted only via json diagnostics

file and span both allow rustc to construct Spans internally, so it can actually display the build specification file as part of the diagnostic. This assumes that a dependency can actually be referenced with a single file coordinate.

json requires the schema of json diagnostics to change. I propose a new tool_metadata key which is added to the Diagnostic. By default this is null, but is populated when arbitrary json is passed through. The intent of json is that enough detail can be attached to the diagnostic to pass through to a tool which can act on it - for example, auto-fix the problem, or present a lint or code-review comment.

raw is simple emitted into the rendered stream, but is also put into tool_metadata as a plain json string. This might be better named text.

tool_metadata is also used for an implicit location - if --extern-location isn't specified at all, it is populated with {"name":<crate name>,"path":<crate path>} from the --extern option.

An initial prototype PR is in rust-lang/rust#72603

Notes

I'm primarily testing with the Buck build system, where the most convenient way to express unused dependencies is with a (rule name, dependency) tuple, rather than a file coordinate. As such json is the most interesting form for me.

Discussion with various people on the Cargo team shows that unused-crate-dependencies - and hence --extern-location - are not very useful at the moment, as Cargo doesn't have a way to precisely specify dependencies for specific targets in a Cargo package, and so will result in many spurious warnings. (Cargo would prefer a mechanism to indicate whether a given dependency is unused in all targets rather than specific ones.) Conversation is ongoing about if and how this work can be adapted to Cargo.

Since the general format of --extern-location name=<type>:<data> is extensible, we can remove all the currently unused forms (file, span) and add them back later if needed.

Even though this is a non-Z --extern-location option, the PR still requires -Zunstable-options to be set before its accepted.

Open questions

  • What's the best way to represent the tool_metadata in the json diagnostics? Right now its pretty ugly as it appears in every sub-diagnostic. Perhaps it should be a single field in the top-level diagnostic.
  • Would it make sense to be able to specify multiple --extern-location arguments per crate, to allow reporting in different forms? For example, if json is always for tools only, then the rendered version of the diagnostic lacks detail. It could make sense to provide both machine and human-readable info in different forms.
  • Will all the --extern-location options bloat the command line too much? They're only needed for direct dependencies (not transitive), but they could be very redundant. For example, if every dependency is in the same file, the specifying that file path every time is just a waste of space. I think this is something that can be deferred once we have more practice in experience. We could add a way to back-refer to a previous entry, for example (effectively "foo has the same path as bar").
  • There may be other cases where being able to refer to the build dependency specs is useful, but I haven't thought about that much.

Mentors or Reviewers

@petrochenkov reviewed the original unused-crate-dependencies PR (rust-lang/rust#72342) and has given initial comments on rust-lang/rust#72603.

@est31 and @ehuss have been commenting from a Cargo perspective.

@nikomatsakis suggested it should go through the MCP process.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-compilerAdd this label so rfcbot knows to poll the compiler teammajor-changeA proposal to make a major change to rustcmajor-change-acceptedA major change proposal that was accepted

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions