I've been using Rust for a little over six months now. I'm far from an expert, but I have stumbled across many, many gotchas and learned many, many things along the way; things that I hope will be of use to those who are learning what is easily my favourite programming language.
This is the third article in my miniseries for Rust newbs like me. You can find my other excursions into Rust in:
I plan to write more, and this article is about Rust's package manager, Cargo. I'm ashamed to admit that I don't use Cargo's power as widely as I should, but researching this article gave me a better view of its commands' capabilities. In fact, I wasn't even aware of some of the options available until I started looking in more detail.
For this list of my top seven Cargo commands, I'll assume you have basic familiarity with Cargo—that you have it installed, and you can create a package using
cargo new <package>, for instance. I could have provided more commands (there are many options!), but here are my "lucky 7."
- cargo help <command>: You can always find out more about a command with the
--helpoption. The same goes for Cargo itself:
cargo --helpwill give you a quick intro to what's out there. To get more information on a command (more like a man page), you can try using the command
new. For instance,
cargo help newwill give extended information about
cargo new. This behaviour is pretty typical for command-line tools, particularly in the Linux/Unix world, but it's very expressively implemented for Cargo, and you can gain lots of quick information with it.
- cargo build --bin <target>: What happens when you have multiple .rs files in your package, but you want to build just one of them? I have a package called
test-and-trythat I use for, well, testing and trying functionality, features, commands, and crates. It has around a dozen different files in it. By default,
cargo buildwill try to build all of them, and as they're often in various states of repair (some of them generating lots of warnings, some of them not even fully compiling), this can be a real pain. Instead, I place a section in my
Cargo.tomlfile for each one like this:
[[bin]] name = "warp-body" path = "src/warp-body.rs"
I can then use
cargo build --bin warp-bodyto build just this file (and any dependencies). I can then run it with a similar command:
cargo run --bin warp-body.
- cargo test: I have an admission; I am not as assiduous about creating automatic tests in my Rust code as I ought to be. This is because I'm currently mainly writing proof of concept rather than production code, and also because I'm lazy. Maybe changing this behaviour should be a New Year's resolution, but when I do get round to writing tests, Cargo is there to help me (as it is for you). All you need to do is add a line before the test code in your .rs file:
When you run
cargo test, Cargo will "automagically" find these tests, run them, and tell you if you have problems. As with many of the commands here, you'll find much more information online, but it's particularly worth familiarising yourself with the basics of this capability in the relevant Rust By Example section.
- cargo search <query>: This is one of the commands that I didn't even know existed until I started researching this article—and which would have saved me so much time over the past few months if I'd known about it. It searches Crates.io, Rust's repository of public (and sometimes maintained) packages and tells you which ones may be relevant. (You can specify a different repository if you want, with the intuitively named
--registryoption.) I've recently been doing some work on network protocols for non-String data, so I've been working with Concise Binary Object Representation (CBOR). Here's what happens if I use
This is great! I can, of course, also combine this command with tools like grep to narrow down the search yet further, like so:
cargo search cbor --limit 70 | grep serde.
- cargo tree: Spoiler alert: this one may scare you. You've probably noticed that when you first build a new package, or when you add a new dependency, or just do a
cargo cleanand then
cargo build, you see a long list of crates printed out as Cargo pulls them down from the relevant repositories and compiles them. How can you tell ahead of time, however, what will be pulled down and what version it will be? More importantly, how can you know what other dependencies a new crate has pulled into your build? The answer is
cargo tree. Just to warn you: For any marginally complex project, you can expect to have a lot of dependencies. I tried
cargo tree | wc -lto count the number of dependent crates for a smallish project I'm working on and got an answer of 350! I tried providing an example, but it didn't display well, so I recommend that you try it yourself—be prepared for lots of output!
- cargo clippy: If you try running this and it doesn't work, that's because I cheated a little with these last two commands: you may have to install them explicitly (depending on your setup). For this one, run
cargo install clippy—you'll be glad you did. Clippy is Rust's linter; it goes through your code, looking at ways to reduce and declutter it by removing or changing commands. I try to run
cargo clippybefore every
git commit—partly because the Git repositories I tend to commit to have automatic actions to reject files that need linting, and partly to keep my code generally more tidy. Here's an example:
Let's face it; this isn't a major issue (though clippy will find errors, too, if you run it on non-compiling code), but it's an easy fix, so you might as well deal with it—either by removing the code or prefixing the variable with an underscore. As I plan to use this variable later but haven't yet implemented the function to consume it, I will perform the latter fix.
- cargo readme: While it's not the most earth-shattering of commands, this is another that is very useful (and that, as with
cargo clippy, you may need to install explicitly). If you add the relevant lines to your .rs files, you can output README files from Cargo. For instance, I have the following lines at the beginning of my main.rs file:
I'll leave the
cargo readmecommand's output as an exercise for the reader, but it's interesting to me that the Licence (or "License," if you must) declaration is added. Use this to create simple documentation for your users and make them happy with minimal effort (always a good approach!).
I've just scratched the surface of Cargo's capabilities in this article; all the commands above are actually way more powerful than I described. I heartily recommend that you spend some time investigating Cargo and finding out how it can make your life better.
This article was originally published on Alice, Eve, and Bob and is reprinted with the author's permission.