How do I pin indirect dependencies of a crate?

My project A depends on library B that depends on library C.

Library B sets the dependency version to "*" (any) so Cargo will download the latest version of C.

How can I instruct Cargo to build library B using a specific version of library C?


I'm trying to build iron.

The current build is failing, but I can see the last successful build, including Rust and Cargo package versions.

I downloaded the specific Rust nightly used in the build and I've set the the direct dependencies of iron to the ones used in that build by editing Cargo.toml:

[dependencies]
hyper = "0.0.18"
typemap = "0.0.5"
url = "0.2.9"

rust-serialized, which is a dependency of the url and time packages, is downloaded as the latest version which doesn't compile with my specific Rust version.

If I used the version used in the Travis build above I'm sure it will compile successfully.


Manual editing

You can check out Iron, modify Cargo.toml to specify versions (as you have already done). Then you repeat the process, checking out url, modifying its Cargo.toml, then make sure you are using your version of url in Iron's Cargo.toml. Rinse and repeat.

Patch overrides

From the Cargo docs:

The [patch] section of Cargo.toml can be used to override dependencies with other copies. The syntax is similar to the [dependencies] section:

[patch.crates-io]
foo = { git = 'https://github.com/example/foo' }
bar = { path = 'my/local/bar' }

Sources can be patched with versions of crates that do not exist, and they can also be patched with versions of crates that already exist. If a source is patched with a crate version that already exists in the source, then the source's original crate is replaced.

Path overrides

From the Cargo docs:

Sometimes you're only temporarily working on a crate and you don't want to have to modify Cargo.toml like with the [patch] section above. For this use case Cargo offers a much more limited version of overrides called path overrides.

Path overrides are specified through .cargo/config.toml instead of Cargo.toml. Inside of .cargo/config.toml you'll specify a key called paths:

paths = ["/path/to/uuid"]

Specific versions

You might be able to simply specify versions (or SHA hashes) for each dependency that you know works with your Rust version. Cargo should be able to resolve the transitive dependencies and lock you to a previous version if there is one that fits all the requirements.

Alternatively, you can use cargo update -p somecrate --precise major.minor.patch to specify the exact version of a crate and record it in your Cargo.lock.

This may not work in all cases; Rust can have multiple versions of the same library compiled into one binary. That would mean that there's no one place you can specify a version that applies all over.

Addressing the bounty

John adds:

I have a crate that depends on zstd. zstd depends on zstd-safe. zstd-safe depends on zstd-sys. My crate gets linked into a C++ binary that also links zstd as a C library. The versions of the zstd C library and the zstd vendored by zstd-sys must match exactly, or I get link errors. So I want to pin an exact version of zstd-sys

This case can follow the "specific versions" example above, but because zstd-sys uses a links key, there can only ever be exactly one of that crate in the entire crate graph. That means you can add zstd-sys to your top-level dependencies and feel comfortable that Cargo will complain if a conflicting version is introduced:

[dependencies]
zstd = "0.9.0"
zstd-sys = "=1.6.1"

If I edit this to specify version 1.6.0, I get an error:

error: failed to select a version for `zstd-sys`.
    ... required by package `zstd-safe v4.1.1+zstd.1.5.0`
    ... which is depended on by `zstd v0.9.0+zstd.1.5.0`
    ... which is depended on by `so v0.1.0 (/private/tmp/so)`
versions that meet the requirements `=1.6.1` are: 1.6.1+zstd.1.5.0

the package `zstd-sys` links to the native library `zstd`, but it conflicts with a previous package which links to `zstd` as well:
package `zstd-sys v1.6.0+zstd.1.5.0`
    ... which is depended on by `so v0.1.0 (/private/tmp/so)`

Since the anwser provided, Cargo has added the [patch] section to the manifest which allows you to do this use case.

overriding-dependencies