Version solving
Version solving consists in finding a set of packages and versions that satisfy
all the constraints of a given project dependencies. In Rust, it is the package
manager Cargo that takes the dependencies specified in the Cargo.toml
file
and deduces the complete list of exact versions of packages needed for your code
to run. That includes direct dependencies but also indirect ones, which are
dependencies of your dependencies. Packages and versions are not restricted to
code libraries though. In fact they could refer to anything where "packages" act
as a general name for things, and "versions" describe the evolution of those
things. Such things could be office documents, laws, cooking recipes etc. Though
if you version cooking recipes, well you are a very organized person.
Semantic versioning
The most common form of versioning scheme for dependencies is called semantic
versioning. The base idea of semantic versioning is to provide versions
as triplets of the form Major.Minor.Patch
such as 2.4.1
. The "semantic" term
comes from the meaning of each part of the versioning system. Publishing a new
patch version, for example from 2.4.1
to 2.4.2
means no interface has
changed in the provided API of the library. That may be the case for
documentation changes, or internal performance improvements for example.
Increasing the minor number, for example from 2.4.1
to 2.5.0
, means that
things have been added to the API, but nothing was changed in the pre-existing
API provided by the library. Finally, increasing the major number, such as from
2.4.1
to 3.0.0
, means that some parts of the API have changed and thus may
be incompatible with how we are currently using the previous version.
In Rust, packages are called crates and use semantic versioning. In fact, if you
specify a dependency of the form package = "2.4.1"
, cargo will interpret that
as the version constraint 2.4.1 <= v < 3.0.0
for that package. It does so
based on the fact that any version in that range should not break our code
according to the rules of semantic versioning. For more information on
dependencies specifications in Cargo.toml
you can read the Cargo reference
book.
Side note on semantic versioning
Some people think that the granularity of semantic versioning is too broad in the case of major version changes. Instead, versions should never be breaking, but use new namespaces for things that change. It brings the same benefits in the large, that what choosing immutability as default brings in the small. For more information on this point of view, I highly recommend "Spec-ulation" by Rich Hickey, creator of the Clojure programming language.