Avoid multiple usage of the same crate?

I noticed that sometimes the same crate gets compiled multiple times in a project, just in different versions. Is it possible to avoid that? Especially if only the patch number is different like 0.2.1 and 0.2.2

This increases the build time and probably also the binary size. It would be nice to avoid that and just use the highest patch version or even the highest minor version for all crates. Something like 0.2.* or 0.*

I personally have this handy Python3 script around to get the list of duplicate dependencies in the dependency tree:

  • requires a python3 -m pip install --user plumbum, although the script is easy to tweak to make metadata read from sys.stdin, say, and then invoke the script as cargo metadata --format-version 1 | python3 duplicates.py

This won't happen: the dependency tree only showcases duplicates for semver-incompatible versions; in other words, what you are suggesting is already the default behavior. Thus, if you do have duplicates in the dependency tree, it's because the versions in question are not semver compatible, and you need to patch / amend the intermediate dependencies so that they upgrade their own deps, to unify onto the highest possible version (this process can obviously not be automated, since breakage may follow from upgrading a dependency to a new potentially breaking version).

It's not possible to have duplicate copies of a crate that differ only by a patch version number. If one crate requires 0.2.1 and another 0.2.2, then your project will either have only 0.2.2 (Cargo will unify both versions) or the project will not build at all due to a conflict.

Cargo will only allow more than one copy of a crate if the versions are incompatible (differ by semver-major version, or 0.x version, e.g. 0.2.2 and 0.3.0).

You can find these with:

cargo tree -d

Also keep in mind how Cargo parses version requirements:

foo = "0.2.1"

is parsed as >= 0.2.1, < 0.3.0, i.e. "any stable version equal or greater than 0.2.1 and lower than 0.3.0", so crate authors don't have to do anything to relax version requirements.

1 Like

Changing minor version or even patch shouldn't break anything because minor versions only add new features, but not change the API. At least it should be like that.

Only if the major version changes I would expect that something breaks

Ok, maybe Rust uses a different approach for versioning. Usually I use the major.minor.patch where patch only fixes bugs, minor only adds new features and major can break the API.

So a library that requires a version 0.2.4 should also compile with 0.6.8 because all functions of 0.2.4 still exist in 0.6.8

For semver purposes, Cargo ignores leading zeros: 0.0.major, 0.major.minor, major.minor.patch (if major > 0).

  • 1.0.0 is compatible with 1.1.0, but not 2.0.0
  • 0.1.0 is compatible with 0.1.1, but not 0.2.0
  • 0.0.1 not compatible with anything.
6 Likes

Strictly speaking the semver allows breaking change on any versionup before 1.0.0 but the cargo have different semantics for them.

3 Likes

Ok, if the major version is 0 the minor version can breaker the API, if the major version is >=1 the minor version shouldn't break the API.

Thanks for clarification.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.