tamer: Support nightly Rust toolchain pinning

I had never intended to avoid pinning nightly.  This is an unfortunate thing
to have to do---require a _specific_ version of a compiler to build your
software; it's madness.  But the unstable features utilized by TAMER (as
rationalized in `src/lib.rs`) are still worth the effort.

It's not _actually_ that case that we need a specific version of the
compiler, granted; this is outlined in `rust-toolchain.toml`'s
rationale.  You should look there for more information; my approach still
utilizes explicit channels via cargo.  Unfortunately, I had hard-coded it
previously, putting me in a bit of a bind an unable to override the behavior
without modifying the software.

The reason for this change is that `adt_const_params` has a BC break
involving the introduction of `ConstParamTy`.  This is only the second time
I've been bitten by a nightly BC break; the other was the renaming of
`int_log`'s API, as mentioned in
709291b107.  This pinning will in fact
mitigate those future issues---TAMER will be able to resolve the issue at
its leisure, and will further be able to continue to build earlier commits
in the future by simply re-bootstrapping with the committed nightly
version.

If you're curious of my rationale for wanting to inhibit toolchain
downloading during build, or use system libraries, have a look at GNU Guix's
approach to building software safely and reproducibly.  In particular,
dependencies are also built from source (rather than downloading binaries
from external sources), and builds take place in network-isolated
containers.  The `TAMER_RUST_TOOLCHAIN` configure parameter is meant to
facilitate these situations by giving more flexibility to packagers.

DEV-14476
main
Mike Gerwitz 2023-06-05 15:58:26 -04:00
parent 1706c55645
commit 6769f0c280
3 changed files with 87 additions and 7 deletions

View File

@ -24,6 +24,12 @@
set -euo pipefail
# Invoke cargo both to output version information to the log and to trigger
# rustup based on `rust-toolchain.toml`, if the user happens to use rustup.
# This will allow `cargo` commands to work in the usual way, though `make`
# should still be preferred.
which cargo &>/dev/null && cargo --version
# This will apply a default configuration, which will be used to perform a
# fetch of the dependencies. You are of course free to reconfigure after.
./autogen.sh && ./configure && make fetch

View File

@ -43,28 +43,50 @@ AC_SUBST(SUFFIX, m4_argn(4, ver_split))
AC_ARG_VAR([CARGO], [Rust Cargo executable])
AC_CHECK_PROGS(CARGO, [cargo])
# Rust toolchain (stable/nightly) is hard-coded for now, since decisions
# regarding whether to use it are nuanced.
AC_SUBST([RUST_TC], nightly)
test -n "$CARGO" || AC_MSG_ERROR([cargo not found])
# Derive the expected nightly version from `rust-toolchain.toml` and
# configure the build system to use that version explicitly for each cargo
# invoation in the Makefile.
#
# See rust-toolchain.toml for information about this process. Note that
# this file will only trigger an auto-update if it is actually used to
# derive the version (if TAMER_RUST_TOOLCHAIN is _not_ used).
AC_ARG_VAR([TAMER_RUST_TOOLCHAIN],
[Rust toolchain channel to use in place of rust-toolchain.toml contents])
AC_MSG_CHECKING([toolchain channel])
AS_IF([test -n "$TAMER_RUST_TOOLCHAIN"],
[AC_MSG_RESULT([$TAMER_RUST_TOOLCHAIN (from TAMER_RUST_TOOLCHAIN)])
AC_SUBST(RUST_TC, [$TAMER_RUST_TOOLCHAIN])],
[rust_channel=$($AWK -F '[[ "]]' '$1=="channel" { print $4 }' rust-toolchain.toml)
AS_IF([test -n "$rust_channel"],
[AC_MSG_RESULT([$rust_channel (from rust-toolchain.toml)])
AC_SUBST([RUST_TC], [$rust_channel])],
[AC_MSG_RESULT([missing (from both rust-toolchain.toml and TAMER_RUST_TOOLCHAIN)])
AC_MSG_ERROR([rust-toolchain.toml is missing or does not contain channel])])
AC_SUBST([CONFIG_STATUS_DEPENDENCIES], rust-toolchain.toml)])
# There is no reason the build should _ever_ access the network.
# This both helps with reproducibility and helps to mitigate supply chain
# attacks by requiring developers to explicitly indicate their intent to
# fetch a network resource (by invoking cargo manually).
AC_SUBST([CARGO_FLAGS], "--frozen --offline")
# This is a nightly version at the time of writing
# This is the version of Rust that would be required if we were not
# utilizing nightly features. This serves as a lower version bound, whereas
# the nightly check above serves as an upper bound.
rustc_ver_req=1.70
AC_CHECK_PROGS(RUSTC, [rustc])
AC_MSG_CHECKING([rustc $RUST_TC version >= $rustc_ver_req])
rustc_version=$("$RUSTC" "+$RUST_TC" --version | cut -d' ' -f2)
AS_IF([test -z "$rustc_version"],
[AC_MSG_ERROR([
failed to execute rustc with toolchain $RUST_TC (see above for error message)
- if the above toolchain is not found, try running `bootstrap`])])
AX_COMPARE_VERSION([$rustc_version], [ge], [$rustc_ver_req],
[AC_MSG_RESULT([yes ($rustc_version)])],
[AC_MSG_RESULT([no ($rustc_version)])
AC_MSG_ERROR([If using rustup, run `rustup update'])])
[AC_MSG_RESULT([no ($rustc_version)])])
AC_ARG_VAR([CARGO_BUILD_FLAGS],
[Flags to be passed to `cargo build' when invoked via Make])

View File

@ -0,0 +1,52 @@
# See <https://rust-lang.github.io/rustup/overrides.html?highlight=rust-toolchain#the-toolchain-file>
#
# This file is used to pin the version of Rust used to build TAMER. This is
# not at all an ideal situation, but is necessary because TAMER uses nightly
# features, and those features will occaisonally make
# backwards-incompatabile changes.
#
# The default behavior caused by this file is not ideal: If the user uses
# rustup, it'll cause the toolchain to be downloaded during build,
# _ignoring_ any `--offline` flag provided to Cargo. Projects ought to be
# able to build without network access; the `bootstrap` script is intended
# to install necessary dependencies on a system prior to building.
#
# By explicitly specifying the toolchain via `cargo +toolchain`, we bypass
# the system utilizing this file. It becomes clear that TAMER is being
# compiled with a particular toolchain version---the invoked command (by
# `make`) explicitly says so. This also avoids automatically downloading
# the toolchain if it's missing, relying instead on any prior bootstrapping
# or system-installed toolchain.
#
# Why have `rust-toolchain.toml` at all, then? Because then `cargo` will
# work when invoked independently, if someone chooses not to use `make` for
# any reason. It is still recommended that `make` be utilized so that all
# the other build configuration takes effect.
#
# `configure.ac` will extract the channel from this file and utilize it to
# configure the build to explicitly pass the channel via each cargo
# invocation via the `Makefile`. Changing this file will will cause
# reconfiguration automatically.
#
# Alternatively, `TAMER_RUST_TOOLCHAIN` may be used to explicitly specify
# the channel for the toolchain. If you do this, then modifying
# `rust-toolchain.toml` will _not_ trigger a reconfiguration automatically.
#
# If you are building an earlier commit that does not have this file, then
# you will need to modify `configure.ac` / `Makefile.am` to do your bidding.
[toolchain]
channel = "nightly-2023-04-15"
# The components should be checked in `configure.ac`
# - Note that `cargo-fmt` is `rustfmt`.
components = ["rustfmt", "clippy"]
# A note on the above version: it's not likely to be the case that _this
# specific version_ is necessary to build TAMER. Instead, this is an upper
# bound, whereas the Rust version in `configure.ac` is a lower bound. Some,
# or all, of the versions within that bound are likely to work. If you know
# another version that works (e.g. you are packaging TAMER and want to use
# another version of Rust already available elsewhere), you may use the
# `TAMER_RUST_TOOLCHAIN` `configure` parameter.