Home Wiki > Rust
Sign up | Login


tagline: From openSUSE

How to package the Rust compiler in the openSUSE Build Service.

Packaging the Rust compiler

The Rust compiler comes in two SRPMS, one for rust and one for cargo. However, both Rust and Cargo need each other to compile themselves! The following section describes how bootstrapping is done.

The bootstrapping process

Rust's bootstrapping process needs three things:

  • rustc - the Rust compiler itself
  • rust-std - the Rust language's standard library
  • cargo - the build tool for Rust

The bootstrapping packages

First we need the binaries for rust, rust-std, and cargo that have been built in the primordial soup upstream. We will use those to build openSUSE's own version, from fresh sources. We create rustc-bootstrap, rust-std-bootstrap, and cargo-bootstrap packages out of these binaries from upstream. These -bootstrap packages live in the devel:languages:rust:previous-versions project. Each package contains precompiled binaries for a bunch of architectures, and a specfile that just puts the precompiled binary in the correct place in the filesystem.

Creating a project for the first compilation

For the purposes of this discussion, we will create a new project called initial and copy the rustc-bootstrap, rust-std-bootstrap, and cargo-bootstrap packages to it.

At this point, the build service will create RPMS out of rustc-bootstrap, rust-std-bootstrap, and cargo-bootstrap.

Next, set up the following prjconf for your initial project. You can use the "Advanced / Project config" tab at the top of your initial project's page in the build service.

Prefer: rust
Keep: rust

# Uncomment to enable bootstrapping both rust and cargo.
# Rust will then compile with rust-bootstrap and cargo-bootstrap.
# Cargo will compile with the built rust, and cargo-bootstrap.
%_with_rust_bootstrap --with-rust_bootstrap
%_with_cargo_bootstrap --with-cargo_bootstrap

This prjconf does a few things:

  • "Prefer: rust" indicates that the build service should prefer the "rust" package when it has a choice among several packages that provide the same capability.
  • "Keep: rust" is used for packages that require themselves to build.
  • Defines %_with_rust_bootstrap and %_with_cargo_bootstrap macros. We will activate these the very first time we compile the packages, and comment them out afterwards.

You can see the final prjconf from devel:languages:rust. Keep in mind that that one has the macros commented out! You need them to be defined (without comments) for the very first build.

Building the first packages

Copy the the rust and cargo packages from devel:languages:rust into your initial project.

At this point, the build service will churn for some time and compile rust first, and cargo second. The rust package will provide rust-std as well as a result of its compilation. This takes time, around two or three hours. You may go watch a movie or something.

What just happened?

The build service took the prebuilt bootstrapping packages, and made RPMS from them. Then, it used the prebuilt compiler, standard library, and cargo from those RPMS to build the Rust compiler and Cargo from real sources. We now have usable RPMS for those, but we would like to build the next versions of Rust/Cargo from the binaries we built ourselves, not with bootstrapping packages.

Building non-bootstrapped (normal) packages

Create a project called second, and copy your rust and cargo packages to it.

At this point, those packages cannot be built because they require previously-built versions of themselves. We will use the aggregatepac trick to do this.

Do this:

osc aggregatepac initial rust second
osc aggregatepac initial cargo second

This tells the build service to make the binaries from the rust and cargo packages from the initial project, to be copied respectively into the rust and cargo packages in the second project. The immediate effect of these commands is that a file called _aggregate is placed in each of your destination projects.

At this point you must wait a few minutes for the build service to copy the binaries. Watch the build status of the second project. When it succeeds, you must then delete the _aggregate files from both rust and cargo in the second project.

At this point, the build service will start churning again:

  • First, it will build the rust package in the second project, using the binaries from the initial project.
  • Then, it will build the cargo package in the second project, using the rust binary from second and the cargo binary from initial.

This takes a long time, around two or three hours. You may go bake a cake or something.

Updating to the next version of Rust/Cargo

Make sure your destination project has the "Keep" line in its prjconf as described above.

You can put new versions of the tarballs for rust/cargo in their respective packages. They should get rebuilt using the binaries from the previous versions, as per the "Keep" line in the project configuration.

Note that you need Rust version N to build Rust N+1. This means that you need to update Rust and Cargo sequentially; if you miss a few versions between updates, you must build the chain of versions one by one.

Summary of the bootstrapping steps

  1. Create a new project
  2. Copy the prjconf described above to have the Prefer/Keep lines, and uncomment the bootstrapping macros.
  3. Copy the rustc-bootstrap, rust-std-bootstrap, cargo-bootstrap packages into the project; wait for them to build (more or less fast).
  4. Copy the rust and cargo packages. Wait for them to build (slow).
  5. Create a second project
  6. Copy the prjconf; disable the bootstrapping macros
  7. Copy the rust and cargo packages into the second project.
  8. Aggregatepac.
  9. Wait for the aggregated binaries to be copied.
  10. Delete _aggregate from the rust and cargo packages.
  11. Wait for rust and cargo to build (slow).
  12. Your packages are done. You can update to new tarball versions as they come out.