This is the third article in my mini-series for Rust newbs like me. I’ve been using Rust for a little over six months now, and I’m far from an expert, but I have stumbled across many, many gotchas and learned many, many things along the way: things which I hope will be of use to record for those who are learning what is easily my favourite language. You can find my other excursions into Rust here:
I plan to write more over time, but this one is about Cargo. I’m ashamed to admit that I don’t use Cargo’s power as widely as a should, but researching this article has given me a better view into the command’s capabilities. In fact, I wasn’t even aware of some of the options available until I started looking in more detail. I’m going to assume a basic familiarity with Cargo – you have it installed, and you can create a package using
cargo new <package>, for instance – so let’s work from there. I could have provided more (there are many options!), but here’s your “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. For more information on a particular command (more like a man page), you can try using the command “new”:
cargo help newwill give you extended information about cargo new, for instance. 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.
cargo build --bin <target>What happens when you have multiple .rs files in your package, but you only want to build one of them? I have a package called test-and-try which I use for, well, testing and trying functionality, features, commands and crates, and which 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 thus:
name = "warp-body"
path = "src/warp-body.rs"
I can then use
cargo build --bin warp-body to build just this file (and any dependencies). I can then run it with a similar command:
cargo run --bin warp-body
cargo testI 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 PoC (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 thus:
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. What is does is search 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 CBOR. Let’s see what happens if I use cargo search:
This is great! I can, of course, also combine with tools like grep to narrow down the search yet further like so:
cargo search cbor --limit 70 | grep serde
cargo treeSpoiler alert: this one may scare you. You’ve probably noticed, when you first build a new package, or when you add a new dependency, or just do a
cargo cleanand then
cargo build, that you’ll see long list of crates being printed out as Cargo pulls them down from the relevant repository and then 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 -l to 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 clippyIf you tried running this and it didn’t work, that’s because I’ve cheated a little with these last two commands; you may have to install them explicitly (depending on your initial set-up). 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 in which you can reduce and declutter it by removing or changing commands. I try to run
cargo clippybefore every
git commit– partly because the git repositories to which I tend to be committing have automatic actions to reject files which need linting, and partly to keep my code generally more tidy. Let’s see an example:
Let’s face it: this isn’t a major issue (though clippy will also find errors, too, if you run it on non-compiling code), but it’s an easy fix, and so you might as well deal with it – either by removing the code, or prefixing the variable an underscore. As I plan to use this variable later on, but haven’t yet implemented the function to consume it, I plan to perform the latter fix.
cargo readmeNot the most earth-shattering of commands, this is another which is very useful (and which you may need to install explicitly, as with cargo clippy, above). 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 output of the command cargo readme as an exercise to 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 of the commands I’ve listed above are actually way more powerful than I’ve described. I heartily recommend that you spend some time investigating Cargo and finding out how it can make your life better.