cargo-autoinherit
is a new Cargo subcommand that automatically DRYs up your workspace dependencies using dependency inheritance.
You can find prebuilt binaries on GitHub's Releases page.
Alternatively, you can build from source:
cargo install --locked cargo-autoinherit
anchorTable of contents
anchorThe problem
When you have multiple packages in a Cargo workspace, you often end up depending on the same packages in multiple Cargo.toml
files.
This duplication can become an issue:
- When you want to update a dependency, you have to update it in multiple places.
- When you need to add a new dependency, you first have to check if it's already used in another package of your workspace to keep versions in sync.
This process is error-prone and tedious.
If you mess it up, you end up with different versions of the same dependency within your workspace. This can lead to hard-to-debug compilation errors or bloat your artifacts with unnecessary copies of the same package.
anchorThe solution
The solution to this problem is to use dependency inheritance, a recent Cargo feature: you can specify dependencies once, in the root Cargo.toml
of your workspace, and then refer to that centralized list from the members' Cargo.toml
files.
In practice, it looks like this:
# In the root `Cargo.toml`
[workspace.dependencies]
log = "0.4"
# In a member's `Cargo.toml`
[dependencies]
log = { workspace = true }
Nice and DRY!
anchorThe casus belli
A couple of weeks ago I had some maintenance work on the agenda: update all dependencies in Mainmatter's Rust telemetry workshop. Each step of the workshop is a separate Cargo package, for a grand total of 30 Cargo.toml
files in a single workspace.
When I wrote the workshop, I didn't have the foresight to use dependency inheritance. I now had to go through each Cargo.toml
file, centralize the dependencies in the root Cargo.toml
, and then update the members' Cargo.toml
files to use the new workspace
syntax.
The work was beyond tedious and I thought: "There must be a tool to automate this!"
There wasn't, so I wrote one.
anchorcargo-autoinherit
cargo-autoinherit
is a Cargo subcommand that helps you to keep your dependencies DRY.
You invoke it from the root of your workspace:
# From the root of your workspace
cargo autoinherit
It collects all the dependencies used by your workspace members, determines which ones can be DRYed and moves them to the [workspace.dependencies]
section of the root Cargo.toml
. It also takes care of updating the members' Cargo.toml
files, setting the correct features
field for each package.
anchorInstallation
You can find prebuilt binaries on GitHub's Releases page.
Alternatively, you can build from source:
cargo install --locked cargo-autoinherit
anchorLimitations
There are a few limitations to be aware of when using cargo-autoinherit
:
- It won't auto-inherit path dependencies.
- It won't auto-inherit dependencies from private registries.
- It will only merge version requirements that are obviously compatible (e.g.
^1.0.0
and^1.1.5
will be merged to^1.1.5
, but^1.0.0
and>=1,<2
won't be merged).
Beyond known limitations, keep in mind that cargo-autoinherit
is a young project. We tested it on a few workspaces, but there might be edge cases we haven't encountered yet. If you find a bug, please open an issue on the GitHub repository.