Skip to content

Publish rustc_public crate v0.1 to crates.io #949

@celinval

Description

@celinval

Proposal

Publish a SemVer-compliant rustc_public crate on crates.io that exposes a concise and user-friendly interface to the Rust compiler's interface, decoupling the implementation of sophisticated development tools from the unstable compiler internals.

This proposal extends the 2025H1 StableMIR project goal by defining the publication model, versioning strategy, and maintenance approach for the crate. This MCP focuses on the architectural decisions needed to make the published crate sustainable and useful for the broader ecosystem.

Motivation

Over the past couple of years, the Rustc Librarification Project (formerly StableMIR project) has introduced an API, named rustc_public, to the Rust compiler. This API enables tool developers to analyze and extract information from compiled Rust crates without directly depending on compiler internals. This API provides more stability, reducing maintenance costs, as well as providing a much smaller and friendlier surface API to develop on top of instead of having to reverse engineer the compiler. However, the consumption model is still similar to any other internal compiler crate without explicit versioning, requiring an extern crate statement.

Our next step is to provide a more reliable interface that works across different Rust compiler versions by publishing rustc_public to crates.io with SemVer guarantees. This establishes a foundation for a robust ecosystem where developers can create sophisticated tooling with predictable maintenance costs. Users will be able to rely on semantic versioning to track and adapt to changes, and tools will benefit from better rust-analyzer integration.

Beyond helping tool developers, publishing to crates.io enables library developers to create an ecosystem around rustc_public. For example, stable-mir-json already extends rustc_public with JSON serialization. Without semantic versioning, tools and libraries today must select specific compiler versions, limiting flexibility and adoption.

Since rustc_public was introduced, new tools such as KMIR, RBMC, os-checker distributed verification, and obol have started adopting it, and we have also begun migrating existing tools like Kani and MiniRust.

Architecture Overview

The rustc_public implementation is split between two main crates:

  • rustc_public: Public crate to be published on crates.io, which contains the SemVer-compatible data structures as well as calls to rustc_public_bridge APIs. The translation between stable and internal constructs is also done in this crate.
  • rustc_public_bridge: This crate implements the public APIs to the compiler. It is responsible for gathering all the information requested and providing the data in its unstable form.

Tools should depend on the rustc_public crate, which will then invoke the compiler using APIs defined in rustc_public_bridge.

    ┌────────────────────────────┐           ┌───────────────────────────┐
    │      External Tool         │           │    Rustc Driver library   │
    │            ┌────────────┐  │           │ ┌────────┐                │
    │            │            │  │           │ │        │                │
    │            │rustc_public│  │           │ │rustc   │                │
    │            │            │  ├──────────►| │public  │                │
    │            │            │  │◄──────────┤ │bridge  │                │
    │            │            │  │           │ │        │                │
    │            │            │  │           │ │        │                │
    │            └────────────┘  │           │ └────────┘                │
    └────────────────────────────┘           └───────────────────────────┘

Development model

The key challenge is providing a more stable, versioned interface while not impacting compiler development velocity. We propose a dual-repository model where the compiler maintains an unstable in-tree version that can be freely updated, while a separate repository publishes a SemVer-compliant version to crates.io with multi-compiler-version support.

We will maintain two versions of rustc_public: one in the compiler repository (unstable, serves as the base for the next release candidate) and one in a separate repository (SemVer-compliant, published to crates.io).

┌─────────────────────────────────────────────────────────────┐
│                    rust-lang/rust                           │
│  ┌────────────────────────────────────────────────────┐     │
│  │  rustc_public (in-tree, unstable)                  │     │
│  │  - Bundled with the compiler                       │     │
│  │  - Kept in sync with compiler changes              │     │
│  │  - No stability guarantees                         │     │
│  └────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────┘
                            ▲
                            │
                            │ Periodic sync
                            ▼
┌─────────────────────────────────────────────────────────────┐
│              rust-lang/rustc-public (separate repo)         │
│  ┌────────────────────────────────────────────────────┐     │
│  │  rustc_public (published to crates.io)             │     │
│  │  - SemVer guarantees                               │     │
│  │  - Multi-version compiler support                  │     │
│  │  - Maintained by Rustc Librarification Project     │     │
│  └────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────┘
                            │
                            │ Publishing
                            │ (fixes, new features, new rustc releases)
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                rustc_public @ crates.io                     │
└─────────────────────────────────────────────────────────────┘
                            ▲
                            │
                            │ Cargo dependency
                            │
┌─────────────────────────────────────────────────────────────┐
│                    External Analysis Tools                  │
│              (KMIR, Kani, MiniRust, ...)                    │
└─────────────────────────────────────────────────────────────┘

The in-tree version can be updated freely without SemVer concerns, allowing rustc developers to refactor with minimal friction. The published version provides SemVer guarantees and multi-version support for tool stability. The Rustc Librarification Project can curate API changes before publishing, smoothing out unnecessary churn.

This approach has a maintenance overhead for the Rustc Librarification Project of keeping two versions synchronized, with potential for drift if sync cadence is too slow. The Rustc Librarification Project plans to mitigate this with automated sync tooling.

Nightly distribution

The Rustc Librarification Project plans to keep a version of rustc_public bundled with the nightly rust compiler. This allows tools that want the latest features and don't care about breaking changes to use it directly. However, users should be aware that support for these APIs is minimal and testing is limited.

The Rustc Librarification Project should be able to remove rustc_public from beta and stable releases.

Synchronization strategy

The Rustc Librarification Project will determine sync frequency based on compiler changes affecting APIs, breaking versus non-breaking changes, and community feedback. The Rustc Librarification Project proposes an initial cadence of:

  • Forward sync (rust-lang to rustc_public repo): Every stable release or when needed for bug fixes and new features
  • Backward sync (rustc_public to rust-lang): After each crates.io release or major changes to minimize drift

This provides flexibility to batch changes and minimize breaking releases, opportunity to redesign APIs for better ergonomics before publishing, and balance between freshness and stability.

Versioning schema

Semantic versioning will only apply to the public APIs. Compiler version compatibility will be considered a minor incompatibility per Cargo's SemVer compatibility guidelines.

Each rustc_public version will declare the minimum supported rust-version using Cargo's rust-version field. The range of known compatible stable compiler versions will be documented in the crate. New stable compiler releases will trigger either minor or major version bumps depending on whether breaking changes to the public interface are required. The versioning scheme would look like the following:

rustc_public: 0.3.0 rust-version: 1.90.0 supports 1.90.0 - 1.92.0
rustc_public: 0.3.1 rust-version: 1.90.0 supports 1.90.0 - 1.93.0
rustc_public: 0.4.0 rust-version: 1.94.0 supports 1.94.0 - 1.94.0 (breaking API change)

The crate's build.rs will check the compiler version and emit warnings or errors for incompatible versions, providing actionable error messages directing users to compatible versions.

The goal is to maintain major versions that cover the latest 3 stable releases at any given point. This provides predictable updates where tools know when they need to update based on their compiler version.

Escape hatches for incomplete coverage

The Rustc Librarification Project will provide two feature flags (disabled by default) that are excluded from SemVer guarantees to help users handle cases where the stable rustc_public interface is insufficient.

rustc_internal feature: This feature exposes some rustc internal APIs that have no stability guarantee. It is designed to help users migrate to rustc_public incrementally or handle cases where the rustc_public interface does not provide enough functionality. This allows gradual migration where tools can migrate piece by piece, using internal APIs only where necessary. However, code using this feature may break with any compiler update.

unstable feature: This feature exposes experimental rustc_public APIs under development or APIs that reflect unstable Rust features. It provides early access to new features and allows iteration before committing to SemVer compatibility. APIs under this feature may change or be removed without notice.

This approach ensures tools aren't blocked by incomplete coverage while they transition to the stable interface. However, there is a risk of tools over-relying on these escape hatches rather than requesting improvements to the stable API.

Compilation model

The primary challenge for publishing rustc_public to crates.io is that it requires access to compiler internals, which are only available through unstable features. We need a robust mechanism to enable rustc_public functionality on stable compiler releases, as the current approach relies on internal compiler infrastructure that should not be exposed to external tools.

Until we establish a permanent solution, we have identified two possible approaches:

  1. Recommend users to use rustc_public published on crates.io with a stable compiler version by exporting RUSTC_BOOTSTRAP=rustc_public_bridge when building their crates. This is the more user-friendly approach, but relies on bootstrap logic that is internal to the compiler infrastructure. Alternatively, we could use RUSTC_ALLOW_UNSTABLE_RUSTC_PUBLIC if the RFC proposal gets accepted.

  2. Track the nightly version from which a release branch was cut and require users to match their stable compiler version accordingly. Users would need to determine which versions those are, which we could document and provide helpful error messages for, but this approach is significantly less user-friendly.

The preferred approach is the first option since it provides a better user experience. The Rustc Librarification Project will implement validation for both stable compiler versions and their corresponding nightly version bases to ensure compatibility. The Rustc Librarification Project hopes this will serve as a temporary solution while exploring better alternatives with the compiler team.

Compiler team responsibilities

The ask for the compiler team is minimal and focused on enabling the Rustc Librarification Project to maintain rustc_public:

The compiler team should keep the information used by rustc_public visible and keep the in-tree rustc_public implementation in sync with changes to rustc.

The Rustc Librarification Project explicitly is not requesting that the compiler team maintain SemVer compatibility, support multiple rustc_public versions, or block compiler refactorings. The goal is to avoid any impact on compiler development velocity.

Occasionally, the Rustc Librarification Project may require review from the compiler team to ensure rustc_public matches the MIR semantics. These are expected to be standard reviews, not large or complicated.

PR reviews related to adding or removing features from in-tree rustc_public and rustc_public_bridge, as well as synchronization PRs, will be owned by the Librarification Project.

The Rustc Librarification Project also requests feedback on the compilation model to help identify better solutions for the RUSTC_BOOTSTRAP requirement.

Open questions

Several questions remain open for community feedback:

  1. What is the best long-term solution for the RUSTC_BOOTSTRAP requirement? Should the compiler provide a blessed mechanism for this use case?
  2. Should we keep a forked version of rustc_public_bridge in rustc_public repository? Most new APIs to rustc_public require changes to rustc_public_bridge, so forking both might alleviate the number of PRs cut to the rust-lang/rust repository.
  3. What will be the policy on minimum compiler version support? Should the Rustc Librarification Project require support for the last 3 stable releases?
  4. Should the in-tree rustc_public continue being distributed with nightly toolchains for tools that want bleeding-edge access?
  5. What is the acceptable overhead for the abstraction layer? Should there be performance benchmarks as a gate for changes?

Mentors or Reviewers

@oli-obk

Process

The main points of the Major Change Process are as follows:

  • File an issue describing the proposal.
  • A compiler team member who is knowledgeable in the area can second by writing @rustbot second or kickoff a team FCP with @rfcbot fcp $RESOLUTION.
  • Once an MCP is seconded, the Final Comment Period begins.
    • Final Comment Period lasts for 10 days after all outstanding concerns are solved.
    • Outstanding concerns will block the Final Comment Period from finishing. Once all concerns are resolved, the 10 day countdown is restarted.
    • If no concerns are raised after 10 days since the resolution of the last outstanding concern, the MCP is considered approved.

You can read more about Major Change Proposals on forge.

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 rustcto-announceAnnounce this issue on triage meeting

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions