diff --git a/tamer/bootstrap b/tamer/bootstrap index fef170cb..5cbd4afb 100755 --- a/tamer/bootstrap +++ b/tamer/bootstrap @@ -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 diff --git a/tamer/configure.ac b/tamer/configure.ac index 42009e13..6ce2c2bf 100644 --- a/tamer/configure.ac +++ b/tamer/configure.ac @@ -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]) diff --git a/tamer/rust-toolchain.toml b/tamer/rust-toolchain.toml new file mode 100644 index 00000000..7adc91bc --- /dev/null +++ b/tamer/rust-toolchain.toml @@ -0,0 +1,52 @@ +# See +# +# 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. +