Should "*" be used for cargo dependencies?


#1

Say I want to depend on 3 crates: regex, regex_macros and log.

Here are the 4 possibilities I can see myself using in Cargo.toml:

  • Scheme 1: purely using [dependencies.*] sections.
[dependencies.regex]
[dependencies.regex_macros]
[dependencies.log]
  • Scheme 2: using * versions
[dependencies]
regex = "*"
regex_macros = "*"
log = "*"
  • Scheme 3: using the versions that they were when I first used them
[dependencies]
regex = "0.1.1"
regex_macros = "0.1.2"
log = "0.2.1"
  • Scheme 4: continuously updating Cargo.toml with new versions when I see they have a new version.
[dependencies]
regex = "0.1.14"
regex_macros = "0.1.8"
log = "0.2.3"

I’ve been personally using scheme 3 since I begin using rust, but I’ve also had to manually update the versions when a new major version update of a package is released (0.1.x to 0.2.x). I’m not sure if that’s an advantage or a disadvantage.

I don’t think there’s that much of an advantage to scheme 4 over scheme 3, as cargo update will get the latest versions for you anyways. I think the only case you’d want to do this manually in Cargo.toml is when you want to force other people compiling your library/program to download the latest versions if they don’t use cargo update.

I’ve seen libraries recommend [dependencies.x], x = "*", x = <latest version> and also x = <version the readme was last updated at>.

So, users of rust, which scheme do you use, and which one do you recommend new users using? Also, do you think the preferred version will change after libraries start stabilizing into 1.x versions?


#2

Here is my $0.02

  1. You should be checking in your Cargo.lock - ensuring that the dependencies you just built with are what someone else builds with.
  2. You should be staying on ‘*’ in the Cargo.toml.
  3. When a library you depend on releases breaking API changes, the time to take them is as close to the introduction of the breakage as possible. When you do not do this, you wind up essentially earning interest debt in your project: you don’t have to upgrade, but as soon as you need a new feature, or another library needs it, you will. Do the right hard thing and do the work to get working, stable, and current close to the moment of breakage.
  4. You should run ‘cargo update’ frequently, and checking that your code works with the latest versions of your dependencies.

As for how to specify your versions, I prefer the ‘=*’ style, myself.


#3

You should choose Scheme 3, but since Rust is changing so much, many peoplar are doing scheme 2. Note that “x” means “^x.y.z”, not “=x.y.z”.


#4

Just curious - what’s your reasoning behind preferring Scheme 3?


#5

They end up being basically the same due to the Lockfile. No need to churn your Cargo.toml for no reason.


#6

Right - that’s why it felt like, even after Rust settles, scheme 2 might actually be “better”, although it’s not going to give you any semantic version style upgrade control. (You just check in the lockfile).