Getting started with rust-toolset

One of the new software collections we’ve introduced this fall is for Rust, the programming language that aims for memory and thread safety without compromising performance. Dangling pointers and data races are caught at compile time, while still optimizing to fast native code without a language runtime!

In rust-toolset-7, we’re including everything you need to start programming in Rust on Red Hat Enterprise Linux 7, in the familiar format of software collections. In this release, we’re shipping Rust 1.20 and its matching Cargo 0.21 – both as Tech Preview. (NOTE: The “-7” in our toolset name is to sync with the other collections now being released, devtoolset-7, go-toolset-7, and llvm-toolset-7.)

Install rust-toolset-7

The toolset is available in the rhel-7-server-devtools-rpms repo for RHEL 7 Server, or rhel-7-workstation-devtools-rpms for RHEL 7 Workstation. (If you don’t already have RHEL 7, Red Hat offers no-cost RHEL subscriptions for development use here.) You can use subscription manager to enable the repo, then yum to install it as usual.

# subscription-manager repos --enable rhel-7-server-devtools-rpms
# yum install rust-toolset-7

This will install the rustc compiler, the standard library, and the cargo build tool. Once installed, you can verify the versions and the installed path:

$ scl enable rust-toolset-7 'rustc -V'
rustc 1.20.0
$ scl enable rust-toolset-7 'cargo -V'
cargo 0.21.1
$ scl enable rust-toolset-7 'rustc --print sysroot'
/opt/rh/rust-toolset-7/root/usr

Running through scl for every command can be a nuisance, but it’s easy to start a shell with the appropriate paths enabled:

$ scl enable rust-toolset-7 bash

The rest of this post assumes such an enabled shell.

Start with Hello World

What would a programming language be without this universal greeting? This is so ingrained that the example is directly available to us here. Rust projects are managed with the cargo tool, so let’s create a new program:

$ cargo new --bin hello      
     Created binary (application) `hello` project

This will automatically create a new project manifest, hello/Cargo.toml:

[package]
name = "hello"
version = "0.1.0"
authors = ["Josh Stone <jistone@redhat.com>"]

[dependencies]

And a new source file, hello/src/main.rs:

fn main() {
    println!("Hello, world!");
}

Feel free to edit this, and then build and run it with cargo:

$ cd hello/
$ cargo run
   Compiling hello v0.1.0 (file:///home/jistone/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.18 secs
     Running `target/debug/hello`
Hello, world!

Try some external dependencies

Rust libraries are called crates, hosted online at crates.io, and cargo will take care of downloading and building all of your dependencies automatically. Let’s create a quick project to generate a vector of random numbers, and then sort them. First, run “cargo new --bin sorter”, and then add a dependency on the rand crate in Cargo.toml:

[dependencies]
rand = "0.3"

Then edit src/main.rs to look like this:

extern crate rand;

use rand::Rng;

fn main() {
    let mut rng = rand::thread_rng();
    let mut numbers: Vec<i8> = rng.gen_iter().take(10).collect();
    println!("random numbers: {:?}", numbers);

    numbers.sort();
    println!("sorted numbers: {:?}", numbers);
}

Then build and run it:

$ cargo run
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading rand v0.3.17
 Downloading libc v0.2.32
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/sorter`
random numbers: [-83, -69, -75, -72, -48, 12, 82, -30, -101, 106]
sorted numbers: [-101, -83, -75, -72, -69, -48, -30, 12, 82, 106]

That’s simple enough — how about adding some parallelism? Rust has strong compile-time protections from data races, and there are many crates, which build parallel abstractions from this, so let’s try the sorting functions in rayon. First, add another dependency to Cargo.toml:

[dependencies]
rand = "0.3"
rayon = "0.8"

Then use it in src/main.rs:

extern crate rand;
extern crate rayon;

use rand::Rng;
use rayon::prelude::*;

fn main() {
    let mut rng = rand::thread_rng();
    let mut numbers: Vec<i8> = rng.gen_iter().take(10).collect();
    println!("random numbers: {:?}", numbers);

    numbers.par_sort(); // now sorting in parallel threads!
    println!("sorted numbers: {:?}", numbers);
}

Then build and run it again:

$ cargo run
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading rayon v0.8.2
 Downloading rayon-core v1.2.1
 Downloading num_cpus v1.7.0
 Downloading lazy_static v0.2.9
 Downloading coco v0.1.1
 Downloading futures v0.1.16
 Downloading either v1.3.0
 Downloading scopeguard v0.3.3
   Compiling either v1.3.0
   Compiling scopeguard v0.3.3
   Compiling rayon-core v1.2.1
   Compiling lazy_static v0.2.9
   Compiling futures v0.1.16
   Compiling num_cpus v1.7.0
   Compiling coco v0.1.1
   Compiling rayon v0.8.2
   Compiling sorter v0.1.0 (file:///home/jistone/sorter)
    Finished dev [unoptimized + debuginfo] target(s) in 6.90 secs
     Running `target/debug/sorter`
random numbers: [120, -103, 88, -1, 102, -122, -125, -20, -70, -114]
sorted numbers: [-125, -122, -114, -103, -70, -20, -1, 88, 102, 120]

There are more transitive dependencies now, but we didn’t have to rebuild the two we already had. The result should not be surprising — different random numbers, of course, but still sorted.

We’ve just been running the default [unoptimized + debuginfo] build. If you want to start measuring performance, you should use “cargo run --release”, enabling optimizations. Of course, a tiny 10-item vector is not very interesting here. If I increase this program to generate 100 million items — gen_iter().take(100_000_000) — and remove the prints, then my 2-core/4-thread laptop runs the serial sort in 8.2 seconds, and the parallel sort in 3.8 seconds. Although this is a very casual benchmark, it’s still a nice speedup for almost no effort!

Install a useful Rust program

Now that you have a working Rust toolchain, perhaps you’d like a complete program written in Rust. You could look to rustc and cargo themselves, but I also recommend installing ripgrep. This is a recursive grep tool, similar to Ack or The Silver Searcher, but even faster!

$ cargo install ripgrep
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading ripgrep v0.7.1
  Installing ripgrep v0.7.1
 Downloading grep v0.1.7
[... and all other dependencies]
   Compiling termcolor v0.3.3
[... and all other dependencies]
   Compiling ripgrep v0.7.1
    Finished release [optimized + debuginfo] target(s) in 114.67 secs
  Installing /home/jistone/.cargo/bin/rg

Just add ~/.cargo/bin to your PATH and start searching!

$ PATH="~/.cargo/bin:$PATH"
$ rg 'extern crate'
sorter/src/main.rs
1:extern crate rand;
2:extern crate rayon;

Note: programs built with rust-toolset-7 do not have any runtime dependency, so you can freely run them without worrying about any scl enable.

Further Reading

For more information, especially if you want to learn more about programming in Rust to begin with, please visit these resources:


Take advantage of your Red Hat Developers membership and download RHEL today at no cost.

Share