Offline Rust install


#1

Hey!

I’ve been experimenting with ways to install and use Rust while disconnected from the internet. Rust and its tooling seems to work quite well offline and I wanted to share what I’ve learned.

Why install offline?

Not all meetup/workshop venues provide great wifi and sometimes there is no internet connection available to attendees at all. It’s nice to have plan B so that newcomers can get started with Rust in any case. Additionally, offline access to crates.io also comes in handy sometimes.

Essential components of a Rust install

At minimum, I think a useful Rust installation would provide the compiler, Cargo, documentation and some crates.

rustup is a very nice tool that can install the compiler, Cargo and docs. Many people here are probably familiar with it! rustup checks for and downloads new versions of Rust via the internet, so the normal install method won’t work.

Fortunately, once rustup has finished installing Rust, the necessary files are deposited neatly inside the .cargo and .multirust folders in the home directory. Copying those onto a new computer and adding .cargo/bin to the PATH seems to just work. (Of course, the target computer must be running the same OS and architecture!)

I find this pretty incredible, and it feels too easy to be true so I’m a little skeptical that I’ve not missed something here! Kudos to the rustup team for making the design so simple!

For crates, Cargo provides a way to replace crates.io with a local mirror. Usually this mechanism would be used within a single project to vendor its dependencies, but you can also set the config option globally. This makes Cargo refer to the filesystem for any crate it needs rather than trying to fetch it online.

Currently the total size of all crates on crates.io is around 5.5 GB, which is kind of large but not unmanageable. It would be possible to reduce the size by only downloading a subset, say, the most recent versions of each crate with its dependencies. But for a first attempt the download-'em-all strategy seems to work.

Installation method

The easiest installation method I could think of was to put .cargo, .multirust and a folder full of crates onto a USB stick, then copy those files from the USB stick onto a computer to install them. The idea is that a bunch of USB sticks could be prepared beforehand and brought along to an event.

Here’s a screencap showing what it might look like to install and use Rust this way (I fast-forwarded the slow bits):

Because it’s a full rustup install the user can later reconnect to the internet and update their version of Rust like normal, as shown at the end of the video. They could also reconfigure Cargo to fetch crates from crates.io again, rather than using the offline copy.

Contents of the USB stick

Here’s an overview of what was on the USB stick:

./
├── .cargo/
│   ├── bin/
│   │   ├── cargo       // These binaries are all shims for rustup, which finds
│   │   ├── rustc       // the actual binaries inside .multirust/toolchains
│   │   ├── rustdoc
│   │   ├── rust-gdb
│   │   ├── rust-lldb
│   │   └── rustup
│   ├── .crates.toml
│   ├── config          // Contains config so that Cargo looks for crates offline
│   └── env
├── .crates.io-mirror/
│   ├── index/          // Crate metadata; same format as .cargo/registry/index
│   ├── a-0.0.1.crate   // The crates themselves, 36,858 of them
│   ├── abc-0.1.0.crate
│   └── abc-0.1.1.crate
│       ...
└── .multirust/
    ├── toolchains/
    │   └── nightly-x86_64-unknown-linux-gnu/
    │       ├── bin/
    │       │   ├── cargo
    │       │   ├── rustc   // Actual compiler
    │       │   ├── rustdoc
    │       │   └── rust-gdb
    │       ├── etc/
    │       ├── lib/        // .so libraries used by compiler
    │       └── share/
    │           ├── doc/    // HTML docs!
    │           ├── man/
    │           └── zsh/
    ├── update-hashes/
    └── settings.toml

And here’s the contents of .cargo/config which makes Cargo look for crates offline:

[source.offline]
local-registry = ".crates.io-mirror"

[source.crates-io]
replace-with = "offline"

Rough edges

  • Setting PATH: Usually rustup handles setting the PATH environment variable to include .cargo/bin. This doesn’t happen when you just copy the files onto your system, and the correct way to set the PATH is system-dependent.

  • Crate discovery: When online, crates can be found using search engines, looking at rendered documentation, reading readmes and with cargo search. None of that works offline so it’s hard to find a crate without knowing it by name.

Wrap up

So that’s it! A cheap and cheerful way to keep Rusting on when the wifi drops out. There are probably much more clever ways to do this and it would be interesting find out what they are!


#2

I’ve built something to handle the cargo index nicely, including providing the index at an http endpoint: cargo-cacher


#3

You might be interested in this cargo issue I filed. We’re using source replacement for vendoring the crates from crates.io we use for Firefox, but currently source replacement is all-or-nothing, which makes it awkward to switch between “use the stuff in this local directory” and “get crates from crates.io”. For your use case it sounds like this would be desirable–you’d have a local cache of most of crates.io, but you could allow cargo to fetch new crates as needed if you have an internet connection.