Rust Tooling Tips

Pascal Hertleif – @killercup

2015-10-28

Table of contents

Pascal Hertleif

Overview

I’m not talking about editor/IDE plugins, but the tools those can built upon

What I’m talking about:

  1. Tools built-in to Rust
  2. A lot of Cargo
  3. rustfmt
  4. racer
  5. Lints, lints everywhere

Tools built-in to Rust

rustc

Compiling Rust code:

$ rustc -O src/main.rs

(Don’t forget -O if you want to enable compiler optimizations!)

Explain errors:

$ rustc --explain E0106

Can also be found on https://doc.rust-lang.org/error-index.html

(You can help extend those messages! See Github Issue #24407)

List built-in lints:

$ rustc -W help

rustdoc

Render documentation like http://doc.rust-lang.org/std/

$ rustdoc src/lib.rs

rust-lldb, rust-gdb

Debugger scripts based on lldb and gdb with Rust pretty printers

Read more here: http://j.mp/rustlldb

Cargo

With Cargo, you can easily

  • compile Rust projects
  • manage dependecies
  • render documentation
  • run tests, benchmarks, examples

Compiling Rust Code

Without Cargo

$ rustc -O src/main.rs

Let’s add some external libraries!

$ rustc src/bin/add/main.rs --crate-name cargo_add --crate-type bin -C opt-level=3 --cfg feature=\"default\" --out-dir /Users/pascal/Projekte/cargo-edit/target/release --emit=dep-info,link -L dependency=/Users/pascal/Projekte/cargo-edit/target/release -L dependency=/Users/pascal/Projekte/cargo-edit/target/release/deps --extern rustc_serialize=/Users/pascal/Projekte/cargo-edit/target/release/deps/librustc_serialize-7ff5bfc027146194.rlib --extern toml=/Users/pascal/Projekte/cargo-edit/target/release/deps/libtoml-7d16d978f944b9c6.rlib --extern curl=/Users/pascal/Projekte/cargo-edit/target/release/deps/libcurl-89d04227df05c87c.rlib --extern pad=/Users/pascal/Projekte/cargo-edit/target/release/deps/libpad-8b41ff1b2f475326.rlib --extern quick_error=/Users/pascal/Projekte/cargo-edit/target/release/deps/libquick_error-f3aa3728a185a974.rlib --extern docopt=/Users/pascal/Projekte/cargo-edit/target/release/deps/libdocopt-398ed9badedc4dd3.rlib --extern semver=/Users/pascal/Projekte/cargo-edit/target/release/deps/libsemver-41b5af09b2b837dc.rlib --extern cargo_edit=/Users/pascal/Projekte/cargo-edit/target/release/libcargo_edit.rlib -L native=/usr/lib -L native=/usr/local/Cellar/openssl/1.0.2d_1/lib -L native=/Users/pascal/Projekte/cargo-edit/target/release/build/openssl-sys-f0bee5fb97afc90d/out

With Cargo:

$ cargo build --release

Cargo Project Layout

▾ src/          # source files
  lib.rs        # main entry point for libraries
  main.rs       # main entry point for executables
  ▾ bin/        # (optional) additional executables
    *.rs
▾ examples/     # (optional) examples
  *.rs
▾ tests/        # (optional) integration tests
  *.rs
▾ benches/      # (optional) benchmarks
  *.rs
▾ src/          # cargo (build|test|bench|doc)
  lib.rs        # cargo build
  main.rs       # cargo run
  ▾ bin/
    foo.rs      # cargo run --bin=foo
▾ examples/
  bar.rs        # cargo run --example=bar
▾ tests/        # cargo test
  *.rs
▾ benches/      # cargo bench (unstable)
  *.rs

Other Cargo Subcommands

$ cargo search proto
    Updating registry `https://github.com/rust-lang/crates.io-index`
capnp (0.5.0)        Runtime library for Cap'n Proto serialization
capnpc (0.5.0)       Cap'n Proto schema compiler plugin
capnp-rpc (0.5.0)    Experimental Cap'n Proto RPC layer

Update

$ cargo update
    Updating libc v0.1.2 -> v0.1.10

Install

Really fresh: Landed in nightly last week!

$ cargo install rustfmt #soon
$ cargo install --git https://github.com/nrc/rustfmt.git # right now

Add More Cargo Subcommands!

Count line numbers

github.com/kbknapp/cargo-count

$ cargo count -e target -s ,
Gathering information...
         Language  Files  Lines  Blanks  Comments  Code
         --------  -----  -----  ------  --------  ----
         TOML      5      104    19      0         85
         Rust      17     1,832  279     144       1,409
         --------  -----  -----  ------  --------  ----
Totals:            22     1,936  298     144       1,494

Outdated dependencies

Before you cargo update: github.com/kbknapp/cargo-outdated

$ cargo outdated
Checking for SemVer compatible updates...Done
Checking for the latest updates...Done
All dependencies are up to date, yay!

List dependencies

$ cargo list
libc  0.1.2
regex 0.1.41

(Part of cargo-edit.)

$ cargo list --tree
├── libc (0.1.10)
└── regex (0.1.41)
    ├── aho-corasick (0.3.4)
    │   └── memchr (0.1.6)
    │       └── libc (0.1.10)
    ├── memchr (0.1.6)
    │   └── libc (0.1.10)
    └── regex-syntax (0.2.2)

Add, remove dependencies

$ cargo add regex

Automatically adds the latest available version of regex.

Part github.com/killercup/cargo-edit by yours truly.

Also contains cargo rm.

rustfmt

Auto­mat­i­cally refor­mat your Rust code to make it eas­ily parseable by humans

Get it from github.com/nrc/rustfmt

The One True Rust Style?

Current state

Good results, can be tweaked with some options.

Before

fn main() { return doughnutFryer.start() .then(|_| _frostingGlazer.start()) .then(|_| Future.wait([ _conveyorBelts.start(), sprinkleSprinkler.start(), sauceDripper.start() ])) .catchError(cannotGetConveyorBeltRunning) .then(|_| tellEveryoneDonutsAreJustAboutDone()) .then(|_| Future.wait([ croissantFactory.start(), _giantBakingOvens.start(), butterbutterer.start() ]) .catchError(_handleBakingFailures) .timeout(scriptLoadingTimeout, _handleBakingFailures) .catchError(cannotGetConveyorBeltRunning)) .catchError(cannotGetConveyorBeltRunning) .then(|_| { _logger.info("Let's eat!"); }); }

(From nrc/rustfmt#296)

After

fn main() {
    doughnutFryer.start()
                 .then(|_| _frostingGlazer.start())
                 .then(|_| {
                     Future.wait(_conveyorBelts.start(),
                                 sprinkleSprinkler.start(),
                                 sauceDripper.start())
                 })
                 .catchError(cannotGetConveyorBeltRunning)
                 .then(|_| tellEveryoneDonutsAreJustAboutDone())
                 .then(|_| {
                     Future.wait(croissantFactory.start(),
                                 _giantBakingOvens.start(),
                                 butterbutterer.start())
                           .catchError(_handleBakingFailures)
                           .timeout(scriptLoadingTimeout, _handleBakingFailures)
                           .catchError(cannotGetConveyorBeltRunning)
                 })
                 .catchError(cannotGetConveyorBeltRunning)
                 .then(|_| {
                     _logger.info("Let's eat!");
                 });
}

Autocompletion

That one IDE feature that we all want outside of IDEs

Racer

Currently the only working option for Rust autocomplete

github.com/phildawes/racer

Core team (@nrc) wants to change compiler, add tools to offer autocomplete-as-a-service

See rust-lang.org/ides.html

Lints, Lints Everywhere

Lints are basically compiler warning plugins

rustc already has a few, some disabled by default

rustc -W help shows a list

My favorite lint

missing docs: detects missing documentation for public members

#![deny(missing_docs)] makes every crate better

Clippy

Crate that contains additional lints, e.g. approx_constant or needless_return

Get it from github.com/Manishearth/rust-clippy

I wrote an article about this last weekend. Then this happend:

Thank you!

Questions?

You can find these slides here:

killercup.github.io/presentation-rust-tooling-tips