Contributing to Rust std

A collection of tips on contributing to Rust

Adding abstract namespace support for UDS

Recently, I sent a pull request to Rust adding abstract namespace support for Unix domain sockets and I wanted to aggregate notes on the experience for future reference. You can see the documentation (and use the feature in nightly) here: SockerAddr::from_abstract_namespace

Easy setup

Competitive with other projects I've contributed to, I built my local environment on an x86_64 Linux machine pretty quickly. Given the repo includes several major components (e.g. the compiler, stdlib and docs), I was expecting to spend a few hours on just setting up a productive feedback loop. Yet, from git clone to writing meaningful code, the setup took ~20 minutes and most of that time was spent pulling the repo and related crates.

When you're rebasing off master, a useful reminder to constantly run:

$ git submodule update --recursive

The x.py cli

The Rust repo provides a cli for common contributor tasks. I actually didn't realize how versatile the tool is until much later. As an example, the cli can generate the Rust std docs for you so you can verify your doc comments:

$ python3 ./x.py doc

It can format your changes as well:

$ python3 ./x.py fmt

Building and testing loop

You'll also use x.py to build and test your changes. To build my changes quickly, I used this command:

$ python3 ./x.py build --stage 0 library/std

And this command to test:

$ python3 ./x.py test --stage 0 library/std --test-args unix

When you're wanting to run just your tests rather than all of the std tests, --test-args can help filter the test suites.

I ran these 2 commands quite commonly as I cycled through changes.

Using your new std crate

If you actually want to use your new std crate in another project you can set up a custom toolchain using rustup. After you do a complete build, you can set it as a toolchain option by linking it:

$ python3 ./x.py build --stage 1 # complete build
$ rustup toolchain link mylocalrust ./build/x6_64-unknown-linux-gnu/stage1

You can also specify other stages to build against, but I mostly built against stage 1.

Now you can compile your Rust programs with your local toolchain with the + arg:

$ cargo +mylocalrust build

Rollup procedure and CI

I would've saved myself some time knowing this in the beginning.

When you send a PR to Rust, the branch is built & tested against one combination of OS and architecture. If your branch passes, it doesn't mean it's necessarily ready to be merged. When the PR gets approved and a rollup occurs, a new branch including your PR among others will then be built & tested against multiple platforms.

To save time going through cycles with the CI & reviewers, you would be wise to test your branch across different machines. After a bit of going through trial and error myself, I eventually was able to run my Linux build safely on my old Macbook Pro machine.

Cross-platform issues with documentation

Here is a specific cross-platform issue I learned about that seems to be particularly relevant to stdlib contributing:

If you're working on a platform-specific issue then you'll want to tell the compiler about it through #[cfg(...)]. As an example,

#[cfg(target_os = "linux")]
fn my_new_cool_feature() {}

But since you know the value of documentation, you'll also want this feature shown in the docs so you add any(doc):

/// Super dope docs
///
/// ```
/// let super_dope_example = my_new_cool_feature();
/// assert!(super_dope_example, is_cool);
/// ```
#[cfg(any(doc, target_os = "linux"))]
fn my_new_cool_feature() {}

From your Linux machine perspective, the feature works and the docs look great, right?

Unfortunately, even though other platforms may be safe from your platform-specific feature code, they aren't safe from your platform-specific doctests example. If your doctests are built & ran on another platform, they'll fail because they are using your new cool feature.

The current work around is adding #[doc()]:

/// Super dope docs
///
/// ```
/// let super_dope_example = my_new_cool_feature();
/// assert!(super_dope_example, is_cool);
/// ```
#[doc(cfg(target_os = "linux"))]
#[cfg(any(doc, target_os = "linux"))]
fn my_new_cool_feature() {}

This will prevent those doctests from being compiled & ran on another platform as well as add a banner to the documentation stating that this feature is platform-specific.

Conclusion

I hope this was useful to you if you're interested in contributing to Rust. I encourage others to not feel overwhelmed if they see an area they can help out in. While my main interest has moved on to the kernel's eBPF subsystem, I plan on using Rust as the main language to build tooling there with.

Written by