pe pe
pe pe

Reputation: 31

Using Cargo.lock to effectively manage & pull dependency versions in my crates

My workspace looks like this:

workspace
     |--other_crate <== existing crate relying on tokio
         |-- Cargo.toml
     |--my_crate <== this is a new crate called using "cargo new --lib"
         |-- Cargo.toml
     |--Cargo.lock
     |--Cargo.toml

I want to add this dependency from Cargo.lock in my new crate:

[[package]]
name = "tokio"
version = "1.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d0183f6f6001549ab68f8c7585093bb732beefbcf6d23a10b9b95c73a1dd49"
dependencies = [
...
]

I would like my_crate to always rely on the same tokio version as other_crate, what is the best way to do it? I am guessing Cargo.lock is the solution to do this, but there is not much documentation on how to do so. In other words, is there a solution something like this in my_crate/Cargo.toml:

...
[dependencies]
tokio = {// refer to Cargo.lock's tokio entry and use it}
...

Currently, I just manually looking up Cargo.lock's entry and manually copying the version. However, if I have N crates relying on the same entry, ensuring that there is version consistency (whenever Cargo.lock needs to be updated) will be backbreaking work...

Upvotes: 0

Views: 794

Answers (1)

kmdreko
kmdreko

Reputation: 60493

I feel there's a few misunderstandings here.

First, Cargo.toml is the authoritive description of your package. The Cargo.lock is purely supplemental. Thus there's not a mechanism to defer to the latter; if it could, there would be a circular logic where the .toml relies on something from the lockfile, but the lockfile needs the .toml to work. Imagine if you wanted to regenerate the lockfile in your scenario, there'd be no basis for what version the tokio dependency should be.

Second, Cargo.lock already ensures a single version is used for compatible dependencies. If one crate depends on tokio 1.12, but another depends on 1.14, the Cargo.lock will only contain a single tokio 1.x entry that is compatible with both. Two crates could have completely separate dependency versions and thus have two entries for tokio in Cargo.lock, but only if they are semver incompatible (0.1 vs 1.x vs 2.x).

Thirdly, there is not a way to depend on another crate's dependencies. They are not considered part of a crate's public interface for determining breaking changes (unless of course they are publically exposed). A crate should be free to update internal-only dependencies without worry of breaking another.


That being said, there is a mechanism that would accomplish this: workspace dependencies. Within a workspace, you can allow crates to defer to a single source of truth for their dependencies by putting them in your root workspace's Cargo.toml:

# workspace/Cargo.toml
[workspace.dependencies]
tokio = { version = "1.14.1" }
# workspace/other_crate/Cargo.toml and
# workspace/my_crate/Cargo.toml
[dependencies]
tokio = { workspace = true }

Upvotes: 4

Related Questions