rust
Source
FROM scratch AS build
ARG VERSION
ARG TARGETARCH
ARG MRUSTC_VERSION
ARG BSTR_VERSION
ENV BOOTSTRAP_RUST_VERSION="1.90"
COPY --from=stagex/core-filesystem . /
COPY --from=stagex/core-busybox . /
# As `/bin/bash` is required by `mrustc`, wrap BusyBox's Bourne-inspired shell (`hush`) as `bash`
RUN --network=none printf "%s\n%s\n" '#!/bin/sh' 'hush "$@"' > /usr/bin/bash && chmod +x /usr/bin/bash
COPY --from=stagex/core-llvm / /
COPY --from=stagex/core-llvm-libgcc / /
COPY --from=stagex/core-make . /
COPY --from=stagex/core-pkgconf . /
COPY --from=stagex/core-python . /
COPY --from=stagex/core-onetbb . /
COPY --from=stagex/core-mold . /
COPY --from=stagex/core-zlib . /
COPY --from=stagex/core-libzstd . /
COPY --from=stagex/core-musl . /
COPY --from=stagex/core-ca-certificates . /
COPY --from=stagex/core-curl . /
COPY <<-'EOF' /etc/profile
set -eux
if [ "$TARGETARCH" = "amd64" ]; then
export ARCH="x86_64"
fi
if [ "$TARGETARCH" = "arm64" ]; then
export ARCH="aarch64"
fi
export TARGET=${ARCH}-unknown-linux-musl
export MAKEFLAGS="-j$(nproc)"
export LLVM_ROOT="/usr/lib/llvm${LLVM_VERSION}"
if [ "$LLVM_VERSION" = "system" ]; then
export LLVM_ROOT="/usr"
fi
export LLVM_BINDIR=${LLVM_ROOT}/bin
export LLVM_CONFIG=${LLVM_BINDIR}/llvm-config
export AS=${LLVM_BINDIR}/llvm-as
export AR=${LLVM_BINDIR}/llvm-ar
export NM=${LLVM_BINDIR}/llvm-nm
export DWP=${LLVM_BINDIR}/llvm-dwp
export RANLIB=${LLVM_BINDIR}/llvm-ranlib
export READELF=${LLVM_BINDIR}/llvm-readelf
export STRIP=${LLVM_BINDIR}/llvm-strip
export OBJCOPY=${LLVM_BINDIR}/llvm-objcopy
export OBJDUMP=${LLVM_BINDIR}/llvm-objdump
export SIZE=${LLVM_BINDIR}/llvm-size
export LD=mold
export CC=clang
export CXX=clang++
export CCC_OVERRIDE_OPTIONS="${CCC_OVERRIDE_OPTIONS:-} +-fuse-ld=mold"
export LLVM_LIB=${LLVM_ROOT}/lib/${TARGET}
export LIBCC="$LLVM_LIB/libclang_rt.builtins.a"
EOF
SHELL ["/bin/sh","-l","-c"]
# Rust defaults to static linking for `musl` targets when we want dynamic linking.
ENV RUSTFLAGS="-Ctarget-feature=-crt-static"
# Don't use the `openssl` vendored within the Rust source tarball
COPY --from=stagex/core-openssl . /
ENV OPENSSL_NO_VENDOR=1
# We begin ratcheting Rust from a version which requires LLVM 21
COPY --from=stagex/core-llvm21 . /
ENV LLVM_VERSION="21"
# mrustc expects libatomic.
COPY --from=stagex/core-libatomic-stub . /
ADD fetch/bstr-${BSTR_VERSION}.tar.gz .
RUN --network=none <<-'EOF'
mkdir /bstr
cd /bstr-${BSTR_VERSION}/scripts/regex/
# Extract the scripts used to generate the regex patterns `bstr` needs
mv grapheme.sh sentence.sh word.sh /bstr/
cd /
rm -rf /bstr-${BSTR_VERSION}
EOF
ADD fetch/mrustc-${MRUSTC_VERSION}.tar.gz .
ADD fetch/*.patch .
ADD patches/*.patch .
WORKDIR /mrustc-${MRUSTC_VERSION}
COPY fetch/rustc-${BOOTSTRAP_RUST_VERSION}.0-src.tar.gz .
COPY --chmod=0755 <<-'EOF' /sanitize_rust-src
set -eux
cd "$1"
# Remove non-source files shipped within the source tarball
# `.inc` is used within LLVM for some C source files which are included
# `.in` corresponds to input for template files, though greater specificity is used than `*.in`
# The Rust build system is orchestrated with Python, contains a hand-written `configure`, and a pair of scripts named `x`
# The `stage0` file contains metadata on the stage-0 (bootstrap) toolchain used to build Rust
# The `version`, `channel` files contains version information for the Rust present within the tree
# The `.gitmodules` file contains a list of what would be Git submodules
# The `.ftl` file is a resource for Fluent: https://projectfluent.org
# `xdg-open` corresponds to a shell script contained with the Rust crate `opener`
# `.el` is the extension for configuration files for Eglot, as used with Emacs
# `rustdoc` and `cargo` contain web files and image assets
# Rust ships some wrappers for `gdb`/`lldb` which are shell scripts
# The `gix` assets are text files used to instantiate Git repositories and so on
# TODO: `_cargo` is unidentified and seemingly not present within the Git repository
# TODO: '*.rs.data' are auditable Rust source files in `icu-list-data`, generated by
# `icu-provider-baked`, which should be handled ourselves
find . -type f \
! -name "*.toml" ! -name "*.lock" ! -name "*.json" \
! -name "*.ld" ! -iname "*.s" ! -name "*.asm" ! -name "*.h" ! -name "*.c" ! -name "*.hpp" ! -name "*.cpp" ! -name "*.inc" \
! -name "*.h.in" ! -name "*.pc.in" ! -name "Makefile.in" ! -name "*.rc.in" \
! -name "*.rs" ! -name "*.py" ! -name "*.sh" ! -name "configure" ! -name "x" ! -name "x.ps1" \
! -name "stage0" ! -name "version" ! -name "channel" ! -name ".gitmodules" \
! -name "*.ftl" ! -name "xdg-open" ! -name "*.el" \
! -name "*.html" ! -name "*.html.template" ! -name "*.css" ! -name "*.js" ! -name "*.png" ! -name "*.svg" \
! -name "rust-gdb" ! -name "rust-gdbgui" ! -name "rust-lldb" ! -name "lldb_commands" ! -name "_cargo" \
! -iname "*.txt" ! -name "*.md" ! -name "COPY*" ! -name "LICENSE*" \
! -path "*vendor/gix-*/src/assets/*" \
! -name "*.rs.data" \
-delete
# While we allowed `configure` as Rust itself has a handwritten, small `configure` in its root,
# we want to erase all others as they're frequently generated via `autoconf`
find . -mindepth 2 -type f -name "configure" -delete
# We also erase such `x` files
find . -mindepth 2 -type f -name "x" -delete
# Sanity check these files are ASCII by checking no bytes are greater than 128
check_ascii() {
if [ $(cat "$0" | od -An -tx1 | grep " [8-9a-f]" | wc -c) -ne 0 ]; then
echo "\`$0\` was not ASCII"
exit 1
fi
}
# This does not include all exceptional files, solely the ones more likely to raise concerns which should be ASCII
for exceptional in "*.inc" "*.in" "configure" "x" "x.ps1" "stage0" "version" "channel" ".gitmodules" "*.ftl" "xdg-open" "*.el" "*.rs.data" "rust-gdb" "rust-gdbgui" "rust-lldb" "lldb_commands" "_cargo"; do
find . -type f -name "$exceptional" | while IFS="\n" read -r file; do
check_ascii "$file"
done
done
find . -type f -path "*vendor/gix-*/src/assets/*" | while IFS="\n" read -r file; do
check_ascii "$file"
done
# Satisfy how `bstr` wants pre-compiled state machines for its regexes
# The `fsm` directory we're patching has been effectively unchanged for years, but we explicitly
# remove historical versions (pre-mid-2023) for which this patch wouldn't apply. We then replace
# them with the latest version which will still be compatible as they still have the same major
# version and follow SemVer.
rm -rf ./vendor/bstr-0.*
# Update the `1.y.z` series to `1.12.0`, which we assume is the latest vendored `bstr`
# TODO: Automatically detect the latest `bstr`
ls ./vendor/ | grep "^bstr-1\.[0-5]\.[0-9]*$" | while IFS="\n" read -r old_bstr; do
rm -rf "./vendor/${old_bstr}"
cp -r "./vendor/bstr-1.12.0" "./vendor/${old_bstr}"
sed -i s/1.12.0/$(printf "%s" "${old_bstr}" | cut -d'-' -f2)/ "./vendor/${old_bstr}/Cargo.toml"
done
ls ./vendor | grep "^bstr-" | while IFS="\n" read -r bstr; do
cd ./vendor/"${bstr}"
# We first provide the raw regex patterns in an uncompiled state
sh /bstr/grapheme.sh > src/unicode/fsm/grapheme_break.txt
sh /bstr/sentence.sh > src/unicode/fsm/sentence_break.txt
sh /bstr/word.sh > src/unicode/fsm/word_break.txt
# We then patch `bstr` to not expect precompiled regex patterns but to instead perform the
# compilation itself. While these are lazy and cached, this will cause the latency of the first
# use to potentially be minutes. Unfortunately, to produce the state machines ourselves would
# require compiling `regex-cli`, a non-trivial Rust binary, or possibly `ucd-generate` (another
# Rust binary though one which should be quite feasible to package), or another tool which
# supports this input and outputs into an amenable format.
# TODO: Add a build script to `bstr` to compile the expected state machines
sed -i s/'features = \["dfa-search"\]'/'features = \["dfa-search", "syntax", "dfa-build"\]'/ ./Cargo.toml
patch -p1 -i /bstr.patch
cd ../..
done
EOF
# We start by applying our set of patches to `mrustc` and the bootstrapped Rust source
RUN --network=none <<-EOF
set -eux
export RUSTC_VERSION="${BOOTSTRAP_RUST_VERSION}.0"
# Whitelist the allowed files within `mrustc` to remove any potential non-source files
find . -type f \
! -name "Makefile" ! -name "*.mk" ! -name "*.sh" \
! -name "*.h" ! -name "*.hpp" ! -name "*.cpp" \
! -name "*.toml" ! -name "*.rs" ! -name "*.patch" ! -name "*.txt" \
! -name "rustc-${BOOTSTRAP_RUST_VERSION}.0-src.tar.gz" \
-delete
tar -xf rustc-${BOOTSTRAP_RUST_VERSION}.0-src.tar.gz
# Replace the `.tar` so it isn't extracted again, restoring/overwriting any files
rm rustc-${BOOTSTRAP_RUST_VERSION}.0-src.tar.gz
touch rustc-${BOOTSTRAP_RUST_VERSION}.0-src.tar.gz
RUSTC_SRC=rustc-${BOOTSTRAP_RUST_VERSION}.0-src
/sanitize_rust-src "$RUSTC_SRC"
# Generate `mrustc`'s marker that this is an extracted tarball
touch $RUSTC_SRC/extracted
# Even with the `mrustc`, `rustc` imports, all files should be restricted to the above extensions
# at this time and it shouldn't be possible to recreate any other files (such as by re-extraction
# from the tarball or restoring a cached version), ensuring the following is from source so long
# as no non-source files masqueraded under a source file extension
# Patch the patch file `mrustc` will apply itself, as it isn't accepted by `busybox` as-is due to misc oddities
patch -p1 -i ../patch.patch
# Apply `mrustc`'s patches to the `rustc` source so it'll build with `mrustc`
make RUSTCSRC
# `mrustc` wants to build the LLVM toolchain vendored within Rust. We don't
# Shim the build directory to our existing LLVM toolchain
ln -s $LLVM_ROOT $RUSTC_SRC/build
# Stub a `Makefile` so `mrustc`'s `Makefile` thinks the target was created and it can itself build LLVM
touch $RUSTC_SRC/src/llvm-project/llvm/CMakeLists.txt
echo "all:" > $RUSTC_SRC/build/Makefile
# Patch a segfault in `mrustc`'s type inference, fixed after the release was tagged
patch -p1 -i ../aea331a4f60535eb6c146b82c50255334e4abf3a.patch
# Patch undefined behavior `mrustc` relies on, which `g++` graces, but `clang++` doesn't
patch -p1 -i ../mrustc-undefined-behavior.patch
# `inline` a `const static` so its value may be used from distinct objects which don't inherently
# have visibility. Weirdly, `clang++` only requires this with `-O0` and not `-O1`. Presumably,
# with even a minimal amount of optimizations, this will already be inlined as necessary.
sed -i s/"static const unsigned PTR_BASE"/"inline static const unsigned PTR_BASE"/ src/hir/encoded_literal.hpp
# `rustix`'s ASM (as transpiled by `mrustc`) is rejected by `clang`, so use the `libc` backend
for rustix in $(ls $RUSTC_SRC/vendor | grep rustix); do
for toml in $(find $RUSTC_SRC/vendor/$rustix -name "Cargo.toml"); do
sed -i s/'default = \['/'default = \["use-libc",'/ $toml
done
done
# Build a dynamically-linked `rustc`
sed -i s/'RUSTFLAGS="'/'RUSTFLAGS="-Ctarget-feature=-crt-static '/ run_rustc/Makefile
EOF
# We now prepare our working tree by defining what will be Rust's self-contained libraries
RUN --network=none <<-EOF
set -eux
mkdir self-contained
for file in rcrt1.o crti.o crtn.o; do
cp /usr/lib/${file} self-contained/
done
for file in crtbegin crtend; do
cp $LLVM_LIB/clang_rt.${file}.o self-contained/${file}S.o
done
# Populate each prefix `mrustc` will build with the self-contained toolchain
for prefix in prefix-s prefix-2 prefix; do
PREFIX_LIB=run_rustc/output/$prefix/lib/rustlib/$TARGET/lib
mkdir -p $PREFIX_LIB
ln -s $(realpath ./self-contained) $PREFIX_LIB/self-contained
done
EOF
# Build `mrustc`, `minicargo`
RUN --network=none <<-EOF
set -eux
# `mrustc` wants to compile in version information obtained with `git`, which we don't care for
# and don't bother adding a dependency upon `git` to enable
STUBBED_GIT=0
if [ ! -f /usr/bin/git ]; then
echo 'int main() { return 0; }' > git.c
$CC git.c -o /usr/bin/git
rm git.c
STUBBED_GIT=1
fi
# TODO: Revisit why this requires disabling `libc++`'s assertions
make CXXFLAGS="-g0 -O2 -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE"
if [ $STUBBED_GIT -eq 1 ]; then
rm /usr/bin/git
fi
make -f minicargo.mk bin/minicargo
EOF
# Build `rustc`, `cargo` with `mrustc`, `minicargo`
RUN --network=none <<-EOF
set -eux
export RUSTC_TARGET="${TARGET}"
export RUSTC_VERSION="${BOOTSTRAP_RUST_VERSION}.0"
export RUSTC_INSTALL_BINDIR="bin"
export OUTDIR_SUF=
export MRUSTC_TARGET_VER="${BOOTSTRAP_RUST_VERSION}"
# Don't compile any debug information
export CCC_OVERRIDE_OPTIONS="$CCC_OVERRIDE_OPTIONS +-g0"
# Remove `gcc`-specific flags since we're using `clang`
# Limit optimizations due to `clang`-compiled `mrustc` output seemingly having undefined behavior
export CCC_OVERRIDE_OPTIONS="$CCC_OVERRIDE_OPTIONS x-fno-tree-sra O2 +-fno-strict-return +-fno-delete-null-pointer-checks"
# Explicitly disable usage of `rustix`'s' 'raw' (assembly) backend, which `mrustc` compiles to
# an inline `__asm__` which `gcc` accepts yet `clang` does not. While we disable some vendored
# libraries with `ENV`, we only do this here as it's a bootstrap-only limitation, not a
# preference.
export CARGO_CFG_RUSTIX_NO_LINUX_RAW=1
# Compile `rustc`, `cargo`
make -f minicargo.mk output/rustc
make -f minicargo.mk output/cargo
EOF
# Rust, when linking the C++ standard library, does so based off of the declared `llvm-config`. Our
# `LLVM_CONFIG` lacks `libc++` (pointing to a historical LLVM intending to be solely the LLVM IR),
# but our system does have (and only has) `libc++`, so we explicitly direct Rust to use `libc++`.
ENV LLVM_USE_LIBCXX=1
RUN --network=none <<-EOF
set -eux
export RUSTC_TARGET="${TARGET}"
export RUSTC_VERSION="${BOOTSTRAP_RUST_VERSION}.0"
export RUSTC_INSTALL_BINDIR="bin"
export OUTDIR_SUF=
export CCC_OVERRIDE_OPTIONS="$CCC_OVERRIDE_OPTIONS +-g0"
# Building the standard library is cheap (only taking a few minutes), but has been
# observed to sporadically fail. Since it's such a cheap operation, to limit requiring
# human intervention, this will re-attempt it a limited amount of times.
# TODO: Identify why this sometimes fails and fix the underlying root cause
STD_ATTEMPTS=5
while [ $STD_ATTEMPTS -ne 0 ]; do
make -C run_rustc output/prefix-s/lib/rustlib/$ARCH-unknown-linux-musl/lib/libstd.rlib || true
STD_ATTEMPTS=$(( $STD_ATTEMPTS - 1 ))
done
make -C run_rustc
# Move the sysroot `mrustc` created to the format expected by the rest of this process
mkdir /rust-${RUSTC_VERSION}
cp -R run_rustc/output/prefix /rust-${RUSTC_VERSION}/usr
EOF
WORKDIR /
ENV CONFIGURE_FLAGS=
COPY --chmod=0755 <<-'EOF' build
set -eux
TARGET_VERSION=${1}
BUILD_VERSION=${2}
TOOLS=${3:-cargo}
PREFIX=/rust-${TARGET_VERSION}/usr
BUILD_PREFIX=/rust-${BUILD_VERSION}/usr
ln -sf /usr/bin/clang /usr/bin/cc
ln -sf /usr/bin/clang++ /usr/bin/c++
cd rustc-${TARGET_VERSION}-src
/sanitize_rust-src .
# Remove all outstanding `cargo-checksum` files as we removed files they may or may not commit to
for crate in $(ls ./vendor); do
if [ -f "./vendor/$crate/.cargo-checksum.json" ]; then
# Outright removal of this file will cause an error
# It being a stub with no actual metadata won't however
echo '{ "files": {} }' > "./vendor/$crate/.cargo-checksum.json"
fi
done
# Remove all checksums from existing lockfiles as they've now been invalidated.
for file in $(find . -type f -name "Cargo.lock"); do
cp "$file" "${file}.bak"
WITHOUT_CHECKSUMS=$(grep -v '^checksum = "' "$file")
echo "$WITHOUT_CHECKSUMS" > "$file"
done
# Remove specification of the `--frozen` argument, saying not to use the exact existing lockfiles,
# with the `--offline` argument, saying not to use the internet to decide the lockfile.
for file in $(find ./src/bootstrap -type f); do
sed -i s/'"--frozen"'/'"--offline"'/ "$file"
done
export RUSTFLAGS="${RUSTFLAGS:-}"
# Tune how `rustc` is built for a faster build process.
export RUSTFLAGS="-Clinker=clang -Clink-arg=-Wl,-fuse-ld=mold $RUSTFLAGS"
# For intermediary compilers, which aren't part of the committed output, we're more aggressive.
if [ ! "$TARGET_VERSION" = "$VERSION" ]; then
# Disable generating/embedding LLVM bitcode within the objects as it won't be used
export RUSTFLAGS="-Cembed-bitcode=false $RUSTFLAGS"
# Enable native codegen as this intermediary step doesn't have to be reproducible
export RUSTFLAGS="-Ctarget-cpu=native $RUSTFLAGS"
# But handle the edge-case https://github.com/rust-lang/rust/pull/148841 presents
if [ $(printf "%s" "$BUILD_VERSION" | cut -d'.' -f2) -lt 93 ]; then
export RUSTFLAGS="$RUSTFLAGS -Ctarget-feature=-avx512f"
fi
# Set `codegen-units` to `nproc`, which will break reproducible builds as Rust builds are only
# deterministic with a consistent amount of units.
export RUSTFLAGS="-Ccodegen-units=$(nproc) $RUSTFLAGS"
# Also, if the compiler is sufficiently modern, enable the threaded frontend. This was available
# under nightly as soon ~1.75, but we delay enabling it until it was more tested and stable.
# Note the usage of threads may produce a non-deterministic output without flags such as
# `-Zcodegen-source-order` to sort the outputs after their compilation.
if [ $(printf "%s" "$BUILD_VERSION" | cut -d'.' -f2) -ge 85 ]; then
THREADS_TO_USE=8
if [ $(nproc) -lt $THREADS_TO_USE ]; then
THREADS_TO_USE=$(nproc)
fi
export RUSTFLAGS="-Zthreads=$THREADS_TO_USE $RUSTFLAGS"
fi
fi
python3 ./src/bootstrap/configure.py \
--build="${TARGET}" \
--host="${TARGET}" \
--target="${TARGET}" \
--local-rust-root="${BUILD_PREFIX}" \
--tools="${TOOLS}" \
--llvm-root="${LLVM_ROOT}" \
--llvm-libunwind="system" \
--enable-local-rust \
--enable-clang \
--enable-option-checking \
--enable-vendor \
--dist-compression-formats=gz \
--disable-docs \
--python="python3" \
--prefix="${PREFIX}/usr" \
--sysconfdir="${PREFIX}/etc" \
--release-channel="stable" \
--set="install.prefix=${PREFIX}" \
--set="target.${TARGET}.crt-static=false" \
--set="target.${TARGET}.musl-root=/usr" \
--set="target.${TARGET}.llvm-config=${LLVM_BINDIR}/llvm-config" \
--set="rust.optimize=2" \
--set="rust.lld=false" \
--set="rust.llvm-tools=false" \
$CONFIGURE_FLAGS
if [ ! "${TARGET_VERSION}" = "${VERSION}" ]; then
# We only build the first-stage Rust compiler, as sufficient for further bootstrapping.
#
# We specifically choose `library`, as in, the Rust standard library, as what to build up to.
#
# For more context on the changes made, see
# https:/blog.rust-lang.org/inside-rust/2025/05/29/redesigning-the-initial-bootstrap-sequence.
python3 x.py build --stage 1 library
STAGE_FOR_CARGO=1
if [ $(printf "%s" "$TARGET_VERSION" | cut -d'.' -f2) -lt 90 ]; then
# We specify to build `cargo` with the original toolchain, as acceptable, as building with the
# just-built toolchain causes Rust's bootstrap to try to flush it out _much_ more.
STAGE_FOR_CARGO=0
fi
# We also build `cargo`, as required to continue the bootstrap.
python3 x.py build --stage $STAGE_FOR_CARGO src/tools/cargo
# Manually 'install' it
mkdir -p ${PREFIX}
mv build/host/stage1/* ${PREFIX}/
mv $(find build/host/ -type f -name "cargo" | head -n1) ${PREFIX}/bin/
else
python3 x.py install
fi
# Restore the original lockfiles into the installed sources
if [ -d ${PREFIX}/lib/rustlib/src/rust ]; then
cd ${PREFIX}/lib/rustlib/src/rust
find . -type f -name "Cargo.lock" | while IFS="\n" read -r lockfile; do
mv /rustc-${TARGET_VERSION}-src/${lockfile}.bak $lockfile
done
fi
cd /
[ "${TARGET_VERSION}" == "${VERSION}" ] || rm -rf rustc-${TARGET_VERSION}-src /rust-${BUILD_VERSION}
EOF
ADD fetch/rustc-1.91.1-src.tar.gz .
RUN --network=none ./build 1.91.1 1.90.0 ""
ADD fetch/rustc-1.92.0-src.tar.gz .
RUN --network=none ./build 1.92.0 1.91.1 ""
ADD fetch/rustc-1.93.1-src.tar.gz .
RUN --network=none ./build 1.93.1 1.92.0 ""
ADD fetch/rustc-1.94.1-src.tar.gz .
RUN --network=none ./build 1.94.1 1.93.1 ""
ENV LLVM_VERSION="system"
ADD fetch/rustc-1.95.0-src.tar.gz .
RUN --network=none ./build 1.95.0 1.94.1 ""
ADD fetch/rustc-1.96.0-src.tar.gz .
# Patch the default for `musl` targets to be dynamically, not statically, linked
RUN --network=none <<-EOF
set -eux
find ./rustc-${VERSION}-src/compiler/rustc_target/src/spec/targets/ -type f | grep "musl" | while IFS="\n" read -r file; do
sed -i s/"crt_static_default = true"/"crt_static_default = false"/ "$file"
done
EOF
RUN --network=none ./build ${VERSION} 1.95.0 cargo,clippy,rustfmt,rust-demangler,src
RUN --network=none <<-EOF
set -eux
mv /rust-${VERSION} /rootfs
find /rootfs -type f -name "*.log" -delete
find /rootfs -type f -name "*.a" -delete
find /rootfs -type f -name "manifest-*" | while IFS="\n" read -r manifest; do
sort -o "$manifest" "$manifest"
done
EOF
FROM stagex/core-filesystem AS package
COPY --from=build /rootfs/ /Copied to clipboard!