Defining Dependency Versions Remotely

This, and if it works, I copy the string over to the other Cargo.tomls when I get around to it. The present world with multi-repo is nothing to marvel at.

If the goal is to keep versions of common dependencies in sync, then I'd rather let dependencies refer to each other:

[dependencies]
foo = "^3.14"
bar = "^2.71"
baz = { same_as = ["foo", "bar"] }
  • This will make the crate use the same version of baz that foo and bar use.
  • If foo and baz use different-but-compatible version requirements - e.g. foo needs >=0.2.3 while bar needs >=0.2.4 - it'll just have them both use a version they both accept.
  • If foo and bar require incompatible versions of baz - cargo should fail with an appropriate error message.

That is discussed earlier. For more information on the idea, see 3516-public-private-dependencies - The Rust RFC Book.

That only helps make sure that baz uses the same version requirement/range as foo and bar but does not ensure that foo, bar, and baz use the same precise versions some external source which is the request in this issue.

2 Likes

Where one has such stringent compatibility requirements, I've just exported the inner dependency crate from the foo or bar crates to use directly. For example, ghostflow_gitlab offers APIs around the gitlab crate and, because the version is hard to specify properly as a ghostflow_gitlab consumer, instead ghostflow_gitlab::gitlab is used.

just exported the inner dependency crate

As an interim, I've considered re-exporting our dependencies to a "pinning" crate. This might actually help the developer experience since all of our main dependencies would just complete off of same pinning::foo pattern.

When using a polyrepo pattern for services, each new service requires us to add multiple dependencies to the Cargo.toml. Even if the version resolution was delegated out, the dependency names don't complete off of a common list. Using a type name the first time frequently requires adding the type in three places if not using the fully qualified name. Even after we switch to a private registry for other reasons, having the list of our frequent direct dependencies in a consolidated form would still add value in the form of completion for frequent direct dependencies.

Our common crate, which is rather monorepo style, embodies this kind of solution already. If a crate only uses the re-exported common interfaces, we can often alleviate the need to list the dependency or maintain version parity at all.

To combat fat binaries, I bet I would have to add some features. Our common crate does this. With a shared target (configured by .cargo/config.toml), all projects can share targets fairly easily, so re-using builds has been achieve a while ago. I haven't thought though the lockfile implications of re-export as a workaround.

If you aren't actually using the code, it is extremely unlikely to be present in the final binary. Otherwise everyone would get a full copy of the stdlib for every binary.