Updating Rust


Updating Rust

Compiling Rust

By default, OpenBSD has an old version of rustc available in the packages. It is because OpenBSD receives a tier 3 support from the Rust team, and they don't provide binaries nor installation via Rustup.

However, it's possible to use an up to date version of rustc, by compiling it.

Tested on OpenBSD 7.4.

Downloading build-rust

A member of the OpenBSD community maintains a script to compile Rust on OpenBSD. To download & use it, install git:

# pkg_add git

Then, the build-rust repository can be cloned:

  $ git clone https://github.com/semarie/build-rust
  $ cd build-rust

Configuring build-rust

The configuration file is stored at ~/.build_rust.conf. Example below:

# The command you use to become admin. doas, sudo, or nothing if you're
# already root
SUDO=doas
# The URL where to download the rustc source code packaged for building
# Note: there is no slash at the end
distfiles_rustc_base="https://static.rust-lang.org/dist/2023-10-21"

# The Rust compiler used to compile the other Rust version will be used
# from there. /usr/local is the path to use when using the default Rust
# installed using pkg_add(1).
# Once you built a Rust version (e.g. at /path/to/build-rust/install_dir/current),
# use the new path in rust_base_dir to use the new Rust version to compile another
# one.
rust_base_dir=/usr/local

Note: rustc can usually compile only its next version. So, it's required to compile the rustc versions one by one. To do so, the right URL, and especially the right date, has to be used in distfiles_rustc_base.

Identifying the date of the current version

It's required to have the version available in the packages to build the next version. It can be installed using pkg_add(1):

# pkg_add rust

To know the date of your current version, you can use the following command.

$ rustc --version
rustc 1.72.1 (d5c2e9c34 2023-09-13) (built from a source tarball)

The next date to use in distfiles_rustc_base will be later than this one.

Finding the right date

The following Fish script finds all dates in a month when there has been a package. Optionally, it downloads the packages and prints the Rust versions associated with them.

Examples:

  • `fish find-archives.fish 03 2024` to list all URLs from March 2024 with an archive, without knowing their version.
  • `fish find-archives.fish 03 2024 true` to download all the archives from March 2024, and print their version, URL and path.
  • `fish find-archives.fish 03 2024 true nightly` to download all the nightly archives (instead of the beta ones) from March 2024, and print their version, URL and path.

Note: the second example could be useful to be sure to use the latest package of the targeted version. Using 1.76.beta.9 is beter than using 1.76.beta.1.

find-archives.sh

#!/bin/ksh -eu
#
#  Copyright (c) 2024 Anthony Bocci <anthony.bocci+buildrust@protonmail.com>
#
#  Permission to use, copy, modify, and distribute this software for any
#  purpose with or without fee is hereby granted, provided that the above
#  copyright notice and this permission notice appear in all copies.
#
#  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
#  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
#  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
#  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
#  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
#  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin
current_script=$(basename $0)

# Display usage information
usage() {
    echo "Find beta or nightly rustc packages"
    echo ""
    echo "Usage: $current_script <month> [<year>] [<first-day>] [<target>]"
    echo "<month> is the month to check. Example: 03 for March."
    echo "<year> is the year to check. Example 2024. Default to the current year."
    echo "<first-day> is the first day of the month to try. Default to 1."
    echo "<target> is either beta or nightly. Default to beta."
}

if [ "$#" -lt 1 ]; then
    usage
    exit 0
fi

month="$(($1+0))"
year=$(date '+%Y')
first_day=1
target=beta
last_day=31

if [ "$#" -gt 1 ]; then
    year="$(($2+0))"
fi

if [ "$#" -gt 2 ]; then
    first_day="$(($3+0))"
fi

if [ "$#" -gt 3 ]; then
    target="$4"
fi

# Ensure arguments are numbers
if [[ $month -eq 0 ]] || [[ $year -eq 0 ]] || [[ $first_day -eq 0 ]]; then
    usage
    exit 1
fi

tmp_dir="/tmp/build-rust-archives"
archive_name="rustc-$target-src.tar.gz"
extracted_dir="rustc-$target-src"
mkdir -p $tmp_dir

# Loop over each day of the given month / year and check if an archive exists
for day in $(seq $first_day 1 $last_day); do
    day_str=$(printf "%02d" $day)
    month_str=$(printf "%02d" $month)
    url="https://static.rust-lang.org/dist/$year-$month_str-$day_str"

    http_response=$(curl -s -I "$url/$archive_name")
    status_code=$(echo $http_response | head -n 1 | cut -d' ' -f2)
    # Get the remote file length. Grep behaves strangely with \r\n, so they
    # are replaced with \n. One is added at the end of the input, otherwise
    # grep doesn't capture the last line.
    remote_file_length=$(echo "$http_response\n" | tr '\r\n' '\n' | grep -i 'content-length' | cut -d' ' -f2)
    remote_file_length=$(($remote_file_length + 0))
    # There is no archive at this URL, skip this day
    if [ $status_code != '200' ]; then
	continue
    fi
    out_dir="$tmp_dir/$year-$month_str-$day_str"
    mkdir -p $out_dir
    cd "$out_dir"

    # If the archive file is there but incomplete, remove it
    # It happens when the download is interrupted
    if [ -f $archive_name ]; then
	local_file_length=$(stat -f '%z' $archive_name)
	local_file_length=$(($local_file_length + 0))
	if [ $local_file_length -lt $remote_file_length ]; then
	    rm "$archive_name"
	fi
    fi

    # Download the archive only if it's not already there
    if [ ! -f $archive_name ]; then
	echo "Downloading $url/$archive_name at $out_dir/$archive_name..."
	curl -s -o "$archive_name" "$url/$archive_name"
    fi

    if [ ! -d $extracted_dir ]; then
	echo "Extracting version file from $archive_name..."
	tar -xzf "$archive_name" "$extracted_dir/version"
    fi

    if [ -f "$extracted_dir/version" ]; then
	rustc_version=$(cat "$extracted_dir/version")
	echo -e "$rustc_version, $url\n"
    fi
done

As a reference:

  • 2023-09-29 is version 1.73
  • 2023-10-21 is version 1.74
  • 2023-11-13 is version 1.75
  • 2023-01-27 is version 1.76
  • 2024-03-17 is version 1.77
  • 2024-03-18 is version 1.78
  • 2024-04-28 is version 1.79
  • 2024-07-12 is version 1.80

The packages with the same versions, uploaded between these dates, can be ignored. Only the rustc version matters.

When you know the URL of the Rust version you're looking for, set the distfiles_rustc_base variable in configuration and you're ready to go.

Usage

To initialize the directory and install required packages to compile rustc, type the following command:

$ ./build.sh beta init

Once done, you can run the following commands to build rustc.

Note: the second one will probably take a long time, and the third one is optional, it's just convenient to use the new version to compile another Rust version.

$ cd /path/to/build-rust/
$ ./build.sh beta
$ mv ./install_dir/beta ./install_dir/current

If you get the following error when running ./build.sh beta, it means that your current version of Rust is lower or greater than the one needed to compile the new version.

Sun Mar 24 09:15:32 2024: error: build requires rustc 1.75.
Sun Mar 24 09:15:32 2024: task not finished: see build.log for detail

Usually, it's either because you're not compiling the right Rust version (wrong URL in distfiles_rustc_base) or because you don't use the right version of the compiler (wrong path in rust_base_dir).

You might get other errors, an example is about a Rust feature stable but still allowed with an attribute as if it was unstable. Using a package of a different (usually newer) date should fix it.

If it worked properly, you can test the result with the following command:

$ /path/to/build-rust/install_dir/current/bin/rustc --version

Installing a pre-built Rust

It's recommended to build Rust yourself or to use the one installed using pkg_add(1).

However, if you don't want to build it manually, feel free to download one of the versions listed in the table. Do it at your own risks.

OpenBSD version Rust version File File hash (SHA256)
7.4 1.73 v1.73.tar.gz f68992f93c512a64df535e8b4f4c678225cc2a7f5a9799da23924a5b400ee43d
7.4 1.74 v1.74.tar.gz 507d1f565eebe6118eeb4d1f5811ab614af73481ceea2218991fa4967e498070
7.4 1.75 v1.75.tar.gz bef7701c7fec9d66dabdbe1474140818ff69bedc91681d013dbbd19108b8cb4e
7.4 1.76 v1.76.tar.gz a2404201b58e83d25e918f821dca18fe1f8e7cbfb2dfee9fa444d6d5d33fcef2
7.4 1.77 v1.77.tar.gz 66c4952e1e5ed91f0cb5e0714b4e379c61d3583f88968eeda32838df9d17a58b
7.5 1.78 v1.78.tar.gz e6d1672bec6cff3f6a5612d7ed0ad70b0a97e75a20ca3cb1614ad1ca2f2d0796
7.5 1.79 v1.79.tar.gz a5de87b8fb402ab17726f0b6329fee5cefe345b1b67cec345c3a763811f5b41f
7.5 1.80 v1.80.tar.gz 08d5510a5f470c50109762139fc170a324a71493cda9227e9e94e0882e6f5882

Using the new version as the default one

To use the new version as the default one, add the following lines in ~/.kshrc, to add the new version in the PATH.

export PATH="/path/to/build-rust/install_dir/current/bin:$PATH"
export LD_LIBRARY_PATH="/path/to/build-rust/install_dir/current/lib:$LD_LIBRARY_PATH"

OR

If you're using Fish, type the following commands (only once, the changes will persist):

set -Ux LD_LIBRARY_PATH /path/to/build-rust/install_dir/current/lib $LD_LIBRARY_PATH
set -U fish_user_paths /path/to/build-rust/install_dir/current/bin $fish_user_paths