Cargo.toml vs Cargo.lock
Cargo.toml
and Cargo.lock
serve two different purposes. Before we talkabout them, here’s a summary:
Cargo.toml
is about describing your dependencies in a broad sense, and iswritten by you.Cargo.lock
contains exact information about your dependencies. It ismaintained by Cargo and should not be manually edited.If you’re building a non-end product, such as a rust library that other rust packages will depend on, putCargo.lock
in your.gitignore
. If you’re building an end product, which are executablelike command-line tool or an application, or a system library with crate-type ofstaticlib
orcdylib
,checkCargo.lock
intogit
. If you're curious about why that is, see"Why do binaries haveCargo.lock
in version control, but not libraries?" in theFAQ.
Let’s dig in a little bit more.
Cargo.toml
is a manifest file in which we can specify a bunch ofdifferent metadata about our package. For example, we can say that we dependon another package:
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand.git" }
This package has a single dependency, on the rand
library. We’ve stated inthis case that we’re relying on a particular Git repository that lives onGitHub. Since we haven’t specified any other information, Cargo assumes thatwe intend to use the latest commit on the master
branch to build our package.
Sound good? Well, there’s one problem: If you build this package today, andthen you send a copy to me, and I build this package tomorrow, something badcould happen. There could be more commits to rand
in the meantime, and mybuild would include new commits while yours would not. Therefore, we wouldget different builds. This would be bad because we want reproducible builds.
We could fix this problem by putting a rev
line in our Cargo.toml
:
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand.git", rev = "9f35b8e" }
Now our builds will be the same. But there’s a big drawback: now we have tomanually think about SHA-1s every time we want to update our library. This isboth tedious and error prone.
Enter the Cargo.lock
. Because of its existence, we don’t need to manuallykeep track of the exact revisions: Cargo will do it for us. When we have amanifest like this:
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand.git" }
Cargo will take the latest commit and write that information out into ourCargo.lock
when we build for the first time. That file will look like this:
[[package]]
name = "hello_world"
version = "0.1.0"
dependencies = [
"rand 0.1.0 (git+https://github.com/rust-lang-nursery/rand.git#9f35b8e439eeedd60b9414c58f389bdc6a3284f9)",
]
[[package]]
name = "rand"
version = "0.1.0"
source = "git+https://github.com/rust-lang-nursery/rand.git#9f35b8e439eeedd60b9414c58f389bdc6a3284f9"
You can see that there’s a lot more information here, including the exactrevision we used to build. Now when you give your package to someone else,they’ll use the exact same SHA, even though we didn’t specify it in ourCargo.toml
.
When we’re ready to opt in to a new version of the library, Cargo canre-calculate the dependencies and update things for us:
$ cargo update # updates all dependencies
$ cargo update -p rand # updates just “rand”
This will write out a new Cargo.lock
with the new version information. Notethat the argument to cargo update
is actually aPackage ID Specification and rand
is just a shortspecification.