which is used to build any nontrivial Rust program,
will automatically download and build all the dependencies
and (together with
rustc) manage reuse of previous builds etc.
cargo is super-convenient for the common use cases, but also has serious problems.
A (git) tree can be a workspace containing
Each package can contain multiple
(eg, a library and several binaries),
but informally people often say "crate" to mean "package".
When publishing to
crates.io, each package becomes separate.
cargo needs some metadata,
from a file
Cargo.toml in the toplevel.
cargo can often infer the intended libraries and executables
in a conventionally-laid-out package.
There are knobs to override these conventions.
In particular it is fairly easy (and a good idea)
to avoid the proliferation
src directories in each subdirectory of a workspace.
It is a good idea to start a new project with
Unlike some similar tools in other languages,
the resulting tree does not contain much boilerplate.
If you make a project from scratch do not forget to include
edition = "2018" (or similar). See Editions.
cargo maintains a calculated dependency resolution
(versions and hashes of all dependencies)
It is conventional to commit that file
for packages generating binaries,
and omit it for libraries
(where my personal practice is to commit
By default cargo only operates on the crate in the cwd.
If you want it to build/test/whatever the whole workspace,
you must say
cargo and the
have some troublesome security properties.
Since I have not seen this discussed in depth elsewhere,
I will do so here.
cargo's model is heavily influenced by
whose ecosystem and usual methods of use
have an appalling security record.
The Rust libraries are much less atomised than npm's. In a typical project one may end up using a handful, dozens or maybe hundreds of dependencies, but not the thousands upon thousands one sees with npm.
Both cargo and
will run, at build-time,
code supplied by the packages they are building.
There are no restrictions on what that code might do.
crates.io package repository contains tarballs,
and there is no mechanical linkage or machine-readable traceability
of those crate tarballs
back to the git repositories they were hopefully originally created from.
crates.io index is maintained in git but
cargo does not look at
the git history of the index
and does not mind if the index history rewinds,
which it has done occasionally.)
Some of the more important libraries are part of library collections managed by multiple-person umbrella institutions. But many necessary libraries are standalone and owned and maintained by a single Rust developer.
There are tools to help with the
software supply chain management problem,
even records advisories for
APIs which are capable of misuse,
even if there is no known real-world bug,
Some OS distros (e.g. Debian) are starting to maintain
reasonable collections of Rust packages
within the distro package repository.
This puts your OS distro between you
and the raw data from
which is likely to reduce your risk.
To do this,
you will probably want to configure cargo's
crates.io but to
look at your distro packages instead (sorry, link needs JS).
You may also consider some kind of privsep, where packages are built in a container or VM of some kind.
One approach is to keep all of the Rust code, and run all of the tools and the generated code, in the privsep environment. But this is not always very convenient for day-to-day development.
I have a tool
(sorry, link needs JS)
help maintain a convenient workflow
even when one doesn't want to run the Rust system
in one's main environment.
cargo is very easy for simple cases.
But it has limitations, bugs, and inflexibilities. Unlike most of the rest of Rust, important problems can remain outstanding for years. Some awkward limitations are even deliberate policy on the part of cargo upstream.
The situation is too complex to document here, but here are some of the key issues you may run into:
Out-of-tree builds are supported in theory,
but in practice the information needed to
successfully run a nontrivial test suite
(or complex code generator)
in an out-of-tree build
is not provided to the crates being compiled.
The ecosystem infrastructure does not use out-of-tree builds.
So many crates' tests do not work out-of-tree,
and some crates do not build.
(You can arrange for the
to be somewhere else,
if you don't mind the build still needing write access to the source tree.)
Although a stated goal of cargo is to be
embeddable into other build systems,
cargo does not expose the interfaces necessary to do this well.
It's hard to know when to rerun cargo and when cargo's outputs changed.
It's hard to get cargo to build precisely what's needed.
If you want to run cargo inside
you will need to resort to stamp files,
and live with it sometimes doing unnecessary work.
It is not possible to have a completely local (unpublished) dependency without baking the path on the local filesystem into the depending packages' source tree.
nailing-cargo and other tools may help with some of these issues.