rust: add a rust-host package

Rust is in a weird spot right now: it requires cross-compilers to build,
but we also want to use it to build things for the host. This has led to
quite a bit of pain, so the hope is that we can split Rust into
_either_:
- dev-lang/rust-host & dev-lang/rust, where the former only installs
  artifacts necessary for host binary builds, and the latter installs
  all of the remaining artifacts that dev-lang/rust provides today
- dev-lang/rust for host binaries, and cross-*/rust-libs for each target
  we support

It's unclear what benefits the latter brings over the former, and the
former is simpler to write, maintain, and work with (multiple cross-*
packages will have to deal with mutual exclusion over our shared build/
directory; a single package for all cross-compilers has no such issue),
so do that for now.

Since it's convenient, also include the crrev.com/c/3573236 fix.

BUG=b:227370760, b:227507212
TEST=CQ; emerge rust-host rust; cros_sdk --bootstrap

Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/3561803
Tested-by: George Burgess <gbiv@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>

In order for us to update our ChromeOS base, we need to generate a
rust-host prebuilt for our current rust version. If the rust ebuilds are
updated, and a rust-host prebuilt is missing for the previous rust
version, SDK in-place update scripts will have their assumptions broken.

BUG=b/257271340
TEST=presubmit
RELEASE_NOTE=None

Change-Id: I2e44e23e3cdae0b4867522c6968587a0642c2450
Reviewed-on: https://cos-review.googlesource.com/c/third_party/overlays/chromiumos-overlay/+/39568
Reviewed-by: Vaibhav Rustagi <vaibhavrustagi@google.com>
Tested-by: Cusky Presubmit Bot <presubmit@cos-infra-prod.iam.gserviceaccount.com>
diff --git a/dev-lang/rust-host/Manifest b/dev-lang/rust-host/Manifest
new file mode 100644
index 0000000..611542e
--- /dev/null
+++ b/dev-lang/rust-host/Manifest
@@ -0,0 +1 @@
+DIST rustc-1.58.1-src.tar.gz 183834489 BLAKE2B ecc926726ac323cfadd72551ec6df7e435d1d4d6e57f4612d0959f3125182fcf98a4cd70fd25d09781bac22b9857a3a6629a97c7f902d71c345fc9c38dbaa21a SHA512 556de73500bb66796e1d6ec063f26d60e7fe03d496e0783b3b92b54d1aea8354999a6eff325a68eabdaa61cf2b356168768686bfc2ccb48766308490f9c4d945
diff --git a/dev-lang/rust-host/OWNERS b/dev-lang/rust-host/OWNERS
new file mode 100644
index 0000000..31243ec
--- /dev/null
+++ b/dev-lang/rust-host/OWNERS
@@ -0,0 +1 @@
+include chromiumos/third_party/toolchain-utils:/OWNERS.toolchain
diff --git a/dev-lang/rust-host/files b/dev-lang/rust-host/files
new file mode 120000
index 0000000..9c6e852
--- /dev/null
+++ b/dev-lang/rust-host/files
@@ -0,0 +1 @@
+../rust/files/
\ No newline at end of file
diff --git a/dev-lang/rust-host/rust-host-1.58.1-r1.ebuild b/dev-lang/rust-host/rust-host-1.58.1-r1.ebuild
new file mode 120000
index 0000000..1c6c659
--- /dev/null
+++ b/dev-lang/rust-host/rust-host-1.58.1-r1.ebuild
@@ -0,0 +1 @@
+rust-host-1.58.1.ebuild
\ No newline at end of file
diff --git a/dev-lang/rust-host/rust-host-1.58.1.ebuild b/dev-lang/rust-host/rust-host-1.58.1.ebuild
new file mode 100644
index 0000000..5f510e9
--- /dev/null
+++ b/dev-lang/rust-host/rust-host-1.58.1.ebuild
@@ -0,0 +1,46 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=7
+
+RUSTC_TARGET_TRIPLES=(
+	x86_64-pc-linux-gnu
+)
+RUSTC_BARE_TARGET_TRIPLES=()
+
+inherit cros-rustc
+
+DESCRIPTION="The parts of our Rust toolchain necessary to build host binaries"
+
+KEYWORDS="*"
+
+# dev-lang/rust-1.58.1-r1 introduced the split between dev-lang/rust and
+# dev-lang/rust-host; note that here to work around file collisions.
+RDEPEND="!<dev-lang/rust-1.58.1-r1"
+
+src_install() {
+	local obj="${CROS_RUSTC_BUILD_DIR}/x86_64-unknown-linux-gnu/stage2"
+	local tools="${obj}-tools/x86_64-unknown-linux-gnu/release/"
+	dobin "${obj}/bin/rustc" "${obj}/bin/rustdoc"
+	dobin "${tools}/cargo"
+	dobin "${tools}/rustfmt" "${tools}/cargo-fmt"
+	dobin "${tools}/clippy-driver" "${tools}/cargo-clippy"
+	dobin src/etc/rust-gdb src/etc/rust-lldb
+	insinto "/usr/$(get_libdir)"
+	doins -r "${obj}/lib/"*
+	doins -r "${obj}/lib64/"*
+
+	# Install miscellaneous LLVM tools.
+	#
+	# These tools are already provided in the SDK, but they're built with
+	# the version of LLVM built by sys-devel/llvm. Rust uses an independent
+	# version of LLVM, so the use of these tools is sometimes necessary to
+	# produce artifacts that work with `rustc` and such.
+	#
+	# Our long-term plan is to have Rust using the same version of LLVM as
+	# sys-devel/llvm. When that happens, all of the below will be removed, with
+	# the expectation that users will migrate to the LLVM tools on `$PATH`.
+	local llvm_tools="${CROS_RUSTC_BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/bin"
+	exeinto "/usr/libexec/rust"
+	doexe "${llvm_tools}/llvm-profdata"
+}
diff --git a/dev-lang/rust/rust-1.58.1-r1.ebuild b/dev-lang/rust/rust-1.58.1-r1.ebuild
new file mode 120000
index 0000000..8a2616e
--- /dev/null
+++ b/dev-lang/rust/rust-1.58.1-r1.ebuild
@@ -0,0 +1 @@
+rust-1.58.1.ebuild
\ No newline at end of file
diff --git a/dev-lang/rust/rust-1.58.1.ebuild b/dev-lang/rust/rust-1.58.1.ebuild
index 509b5a3..3ea6daf 100644
--- a/dev-lang/rust/rust-1.58.1.ebuild
+++ b/dev-lang/rust/rust-1.58.1.ebuild
@@ -3,216 +3,72 @@
 
 EAPI=7
 
-PYTHON_COMPAT=( python3_{6..9} )
-inherit python-any-r1 toolchain-funcs
-
-if [[ ${PV} = *beta* ]]; then
-	betaver=${PV//*beta}
-	BETA_SNAPSHOT="${betaver:0:4}-${betaver:4:2}-${betaver:6:2}"
-	MY_P="rustc-beta"
-	SLOT="beta/${PV}"
-	SRC="${BETA_SNAPSHOT}/rustc-beta-src.tar.gz"
-	KEYWORDS=""
-else
-	ABI_VER="$(ver_cut 1-2)"
-	SLOT="stable/${ABI_VER}"
-	MY_P="rustc-${PV}"
-	SRC="${MY_P}-src.tar.gz"
-	KEYWORDS="*"
-fi
-
-
-BOOTSTRAP_VERSION="1.57.0"
-
-DESCRIPTION="Systems programming language from Mozilla"
-HOMEPAGE="http://www.rust-lang.org/"
-
-SRC_URI="https://static.rust-lang.org/dist/${SRC} -> rustc-${PV}-src.tar.gz"
-
-LICENSE="|| ( MIT Apache-2.0 ) BSD-1 BSD-2 BSD-4 UoI-NCSA"
-
-RESTRICT="binchecks strip"
-REQUIRED_USE="amd64"
-
-DEPEND="${PYTHON_DEPS}
-	>=dev-libs/libxml2-2.9.6
-	>=dev-lang/perl-5.0
-"
-
-BDEPEND="dev-lang/rust-bootstrap:${BOOTSTRAP_VERSION}"
-RDEPEND="!dev-util/cargo"
-
-PATCHES=(
-	"${FILESDIR}/${P}-add-cros-targets.patch"
-	"${FILESDIR}/${P}-fix-rpath.patch"
-	"${FILESDIR}/${P}-Revert-CMake-Unconditionally-add-.h-and-.td-files-to.patch"
-	"${FILESDIR}/${P}-no-test-on-build.patch"
-	"${FILESDIR}/${P}-sanitizer-supported.patch"
-	"${FILESDIR}/${P}-cc.patch"
-	"${FILESDIR}/${P}-revert-libunwind-build.patch"
-	"${FILESDIR}/${P}-ld-argv0.patch"
-	"${FILESDIR}/${P}-Handle-sparse-git-repo-without-erroring.patch"
-	"${FILESDIR}/${P}-disable-mutable-noalias.patch"
-	"${FILESDIR}/${P}-add-armv7a-sanitizers.patch"
-	"${FILESDIR}/${P}-fix-libunwind-backtrace-visibility.patch"
-)
-
-S="${WORKDIR}/${MY_P}-src"
-
 # This is the list of target triples as they appear in the cros_sdk. If this
 # list gets changed, ensure that each of these values has a corresponding
 # compiler/rustc_target/src/spec file created below and a line referring to it
 # in 0001-add-cros-targets.patch.
 RUSTC_TARGET_TRIPLES=(
-	x86_64-pc-linux-gnu
 	x86_64-cros-linux-gnu
 	armv7a-cros-linux-gnueabihf
 	aarch64-cros-linux-gnu
 )
 
-# In this context BARE means the OS part of the triple is none and gcc is used for C/C++ and
-# linking.
+# In this context BARE means the OS part of the triple is none and gcc is used
+# for C/C++ and linking.
 RUSTC_BARE_TARGET_TRIPLES=(
 	thumbv6m-none-eabi # Cortex-M0, M0+, M1
 	thumbv7m-none-eabi # Cortex-M3
 	thumbv7em-none-eabihf # Cortex-M4F, M7F, FPU, hardfloat
 )
 
-pkg_setup() {
-	python-any-r1_pkg_setup
-	# Skips the toolchain check if we are installing a binpkg.
-	if [[ "${MERGE_TYPE}" != "binary" ]]; then
-		local tt
-		for tt in "${RUSTC_TARGET_TRIPLES[@]}" ; do
-			which "${tt}-clang" >/dev/null || die "missing toolchain ${tt}"
-		done
-		which "arm-none-eabi-gcc" >/dev/null || die "missing toolchain arm-none-eabi"
+inherit cros-rustc
+
+DESCRIPTION="Libraries needed to cross-compile Rust for cros/baremetal targets"
+
+# Use PVR to require simultaneous uprevs of both rust-host and rust, since
+# they're logically talking about the same sources.
+BDEPEND="~dev-lang/rust-host-${PV}"
+RDEPEND="~dev-lang/rust-host-${PV}"
+KEYWORDS="*"
+
+# NOTE: since CROS_RUSTC_BUILD_DIR is a local cache, the cases below can't
+# always presume that it exists.
+
+src_unpack() {
+	if cros-rustc_has_existing_checkout; then
+		einfo "Skipping unpack; checkout already exists"
+	else
+		ewarn "No existing cros-rustc checkout found. Did you" \
+			"remember to emerge dev-lang/rust-host?"
+		cros-rustc_src_unpack
 	fi
 }
 
 src_prepare() {
-	# Copy "unknown" vendor targets to create cros_sdk target triple
-	# variants as referred to in 0001-add-cros-targets.patch and RUSTC_TARGET_TRIPLES.
-	# armv7a is treated specially because the cros toolchain differs in
-	# more than just the vendor part of the target triple. The arch is
-	# armv7a in cros versus armv7.
-	pushd compiler/rustc_target/src/spec || die
-	sed -e 's:"unknown":"pc":g' x86_64_unknown_linux_gnu.rs >x86_64_pc_linux_gnu.rs || die
-	sed -e 's:"unknown":"cros":g' x86_64_unknown_linux_gnu.rs >x86_64_cros_linux_gnu.rs || die
-	sed -e 's:"unknown":"cros":g' armv7_unknown_linux_gnueabihf.rs >armv7a_cros_linux_gnueabihf.rs || die
-	sed -e 's:"unknown":"cros":g' aarch64_unknown_linux_gnu.rs >aarch64_cros_linux_gnu.rs || die
-	popd || die
-
-	# The miri tool is built because of 'extended = true' in cros-config.toml,
-	# but the build is busted. See the upstream issue: [https://github.com/rust-
-	# lang/rust/issues/56576]. Because miri isn't installed or needed, this sed
-	# script eradicates the command that builds it during the bootstrap script.
-	pushd src/bootstrap || die
-	sed -i 's@tool::Miri,@@g' builder.rs
-	popd || die
-
-	# Tsk. Tsk. The rust makefile for LLVM's compiler-rt uses -ffreestanding
-	# but one of the files includes <stdlib.h> causing occasional problems
-	# with MB_LEN_MAX. See crbug.com/730845 for the thrilling details. This
-	# line patches over the problematic include.
-	sed -e 's:#include <stdlib.h>:void abort(void);:g' \
-		-i "${ECONF_SOURCE:-.}"/src/llvm-project/compiler-rt/lib/builtins/int_util.c || die
-
-	# For the rustc_llvm module, the build will link with -nodefaultlibs and manually choose the
-	# std C++ library. For x86_64 Linux, the build script always chooses libstdc++ which will not
-	# work if LLVM was built with USE="default-libcxx". This snippet changes that choice to libc++
-	# in the case that clang++ defaults to libc++.
-	if "${CXX}" -### -x c++ - < /dev/null 2>&1 | grep -q -e '-lc++'; then
-		sed -i 's:"stdc++":"c++":g' compiler/rustc_llvm/build.rs || die
+	if cros-rustc_has_existing_checkout; then
+		einfo "Skipping src_prepare; checkout already exists"
+		# `src_prepare` requires this to be called before exiting. The
+		# actual use of user patches with this ebuild is not supported.
+		eapply_user
+	else
+		cros-rustc_src_prepare
 	fi
-
-	default
-}
-
-src_configure() {
-	local targets=""
-	local tt
-	for tt in "${RUSTC_TARGET_TRIPLES[@]}" "${RUSTC_BARE_TARGET_TRIPLES[@]}" ; do
-		targets+="\"${tt}\", "
-	done
-
-	local config=cros-config.toml
-	cat > "${config}" <<EOF
-[build]
-target = [${targets}]
-cargo = "/opt/rust-bootstrap-${BOOTSTRAP_VERSION}/bin/cargo"
-rustc = "/opt/rust-bootstrap-${BOOTSTRAP_VERSION}/bin/rustc"
-docs = false
-submodules = false
-python = "${EPYTHON}"
-vendor = true
-extended = true
-tools = ["cargo", "rustfmt", "clippy", "cargofmt"]
-sanitizers = true
-profiler = true
-
-[llvm]
-ninja = true
-targets = "AArch64;ARM;X86"
-
-[install]
-prefix = "${ED}usr"
-libdir = "$(get_libdir)"
-mandir = "share/man"
-
-[rust]
-default-linker = "${CBUILD}-clang"
-description = "${PF}"
-channel = "nightly"
-codegen-units = 0
-llvm-libunwind = 'in-tree'
-codegen-tests = false
-new-symbol-mangling = true
-
-EOF
-	for tt in "${RUSTC_TARGET_TRIPLES[@]}" ; do
-		cat >> cros-config.toml <<EOF
-[target."${tt}"]
-cc = "${tt}-clang"
-cxx = "${tt}-clang++"
-linker = "${tt}-clang++"
-
-EOF
-	done
 }
 
 src_compile() {
-	${EPYTHON} x.py build --stage 2 --config cros-config.toml || die
-
-	# Remove the src/rust symlink which will be dangling after sources are
-	# removed, and the containing src directory.
-	rm "${S}/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src/rust" || die
-	rmdir "${S}/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src" || die
+	local keep_stages=()
+	if cros-rustc_has_existing_stage1_build; then
+		einfo "Stage1 build exists; instructing x.py to use it"
+		keep_stages=("--keep-stage=0" "--keep-stage=1")
+	fi
+	cros-rustc_src_compile "${keep_stages[@]}" library/std
 }
 
 src_install() {
-	local obj="build/x86_64-unknown-linux-gnu/stage2"
-	local tools="${obj}-tools/x86_64-unknown-linux-gnu/release/"
-	dobin "${obj}/bin/rustc" "${obj}/bin/rustdoc"
-	dobin "${tools}/cargo"
-	dobin "${tools}/rustfmt" "${tools}/cargo-fmt"
-	dobin "${tools}/clippy-driver" "${tools}/cargo-clippy"
-	dobin src/etc/rust-gdb src/etc/rust-lldb
-	insinto "/usr/$(get_libdir)"
-	doins -r "${obj}/lib/"*
-	doins -r "${obj}/lib64/"*
-
-	# Install miscellaneous LLVM tools.
-	#
-	# These tools are already provided in the SDK, but they're built with
-	# the version of LLVM built by sys-devel/llvm. Rust uses an independent
-	# version of LLVM, so the use of these tools is sometimes necessary to
-	# produce artifacts that work with `rustc` and such.
-	#
-	# Our long-term plan is to have Rust using the same version of LLVM as
-	# sys-devel/llvm. When that happens, all of the below will be removed, with
-	# the expectation that users will migrate to the LLVM tools on `$PATH`.
-	local llvm_tools="build/x86_64-unknown-linux-gnu/llvm/bin"
-	exeinto "/usr/libexec/rust"
-	doexe "${llvm_tools}/llvm-profdata"
+	local obj="${CROS_RUSTC_BUILD_DIR}/x86_64-unknown-linux-gnu/stage2"
+	local triple
+	for triple in "${RUSTC_TARGET_TRIPLES[@]}" "${RUSTC_BARE_TARGET_TRIPLES[@]}"; do
+		insinto "/usr/$(get_libdir)/rustlib/${triple}"
+		doins -r "${obj}/lib64/rustlib/${triple}/"*
+	done
 }
diff --git a/eclass/cros-rustc.eclass b/eclass/cros-rustc.eclass
new file mode 100644
index 0000000..9708372
--- /dev/null
+++ b/eclass/cros-rustc.eclass
@@ -0,0 +1,260 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: cros-rustc.eclass
+# @MAINTAINER:
+# The Chromium OS Toolchain Team <chromeos-toolchain@google.com>
+# @BUGREPORTS:
+# Please report bugs via
+# https://issuetracker.google.com/issues/new?component=1038090&template=1576440
+# @VCSURL: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/HEAD/eclass/@ECLASS@
+# @BLURB: Eclass for building CrOS' Rust toolchain.
+# @DESCRIPTION:
+# This eclass is used to build both dev-lang/rust-host and dev-lang/rust.
+#
+# dev-lang/rust-host is an ebuild that provides all artifacts necessary for
+# building Rust for the host. dev-lang/rust supplements this with libraries for
+# cross-compiling. We maintain this split because we need to build Rust
+# binaries for the host prior to cross-* libraries being available.
+#
+# An important concept when building dev-lang/rust-host and dev-lang/rust is
+# continuity: these packages are expected to be built from _identical_ Rust
+# sources. This assumption:
+# - doesn't restrict us in any meaningful way,
+# - keeps us more consistent with upstream flows for building `rustc`, and
+# - allows us to significantly cut down on the build time of dev-lang/rust,
+#   since dev-lang/rust can skip unpacking sources, configuring them, and
+#   rebuilding LLVM + stage0 + stage1.
+#
+# Moreover, if you want to make meaningful changes to Rust, you'll need to
+# always reemerge _both_ dev-lang/rust-host and dev-lang/rust. dev-lang/rust
+# assumes that the sources unpacked by dev-lang/rust-host, if present, are
+# identical to the ones it will build. dev-lang/rust-host always starts with a
+# clean slate.
+
+if [[ -z ${_ECLASS_CROS_RUSTC} ]]; then
+_ECLASS_CROS_RUSTC="1"
+
+# Check for EAPI 7+.
+case "${EAPI:-0}" in
+[0123456]) die "unsupported EAPI (${EAPI}) in eclass (${ECLASS})" ;;
+esac
+
+EXPORT_FUNCTIONS pkg_setup src_unpack src_prepare src_configure src_compile
+
+PYTHON_COMPAT=( python3_{6..9} )
+inherit python-any-r1 toolchain-funcs
+
+# @ECLASS-VARIABLE: RUSTC_TARGET_TRIPLES
+# @DEFAULT_UNSET
+# @REQUIRED
+# @DESCRIPTION:
+# This is the list of target triples for rustc as they appear in the cros_sdk.
+# cros-rust_src_configure instructs cros-rust_src_compile to use
+# "${triple}-clang" when building each one of these.
+
+# @ECLASS-VARIABLE: RUSTC_BARE_TARGET_TRIPLES
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# These are the triples we use GCC with. `*-cros-*` triples should not be
+# included here.
+
+# There's a fair amount of direct commonality between dev-lang/rust and
+# dev-lang/rust-host. Capture that here.
+ABI_VER="$(ver_cut 1-2)"
+SLOT="stable/${ABI_VER}"
+MY_P="rustc-${PV}"
+SRC="${MY_P}-src.tar.gz"
+
+# The version of rust-bootstrap that we're using to build our current Rust
+# toolchain. This is generally the version released prior to the current one,
+# since Rust uses the beta compiler to build the nightly compiler.
+BOOTSTRAP_VERSION="1.57.0"
+
+HOMEPAGE="https://www.rust-lang.org/"
+
+SRC_URI="https://static.rust-lang.org/dist/${SRC} -> rustc-${PV}-src.tar.gz"
+
+LICENSE="|| ( MIT Apache-2.0 ) BSD-1 BSD-2 BSD-4 UoI-NCSA"
+
+RESTRICT="binchecks strip"
+
+DEPEND="${PYTHON_DEPS}
+	>=dev-libs/libxml2-2.9.6
+	>=dev-lang/perl-5.0
+"
+
+BDEPEND="dev-lang/rust-bootstrap:${BOOTSTRAP_VERSION}"
+
+PATCHES=(
+	"${FILESDIR}/rust-${PV}-add-cros-targets.patch"
+	"${FILESDIR}/rust-${PV}-fix-rpath.patch"
+	"${FILESDIR}/rust-${PV}-Revert-CMake-Unconditionally-add-.h-and-.td-files-to.patch"
+	"${FILESDIR}/rust-${PV}-no-test-on-build.patch"
+	"${FILESDIR}/rust-${PV}-sanitizer-supported.patch"
+	"${FILESDIR}/rust-${PV}-cc.patch"
+	"${FILESDIR}/rust-${PV}-revert-libunwind-build.patch"
+	"${FILESDIR}/rust-${PV}-ld-argv0.patch"
+	"${FILESDIR}/rust-${PV}-Handle-sparse-git-repo-without-erroring.patch"
+	"${FILESDIR}/rust-${PV}-disable-mutable-noalias.patch"
+	"${FILESDIR}/rust-${PV}-add-armv7a-sanitizers.patch"
+	"${FILESDIR}/rust-${PV}-fix-libunwind-backtrace-visibility.patch"
+)
+
+# Locations where we cache our build/src dirs.
+CROS_RUSTC_DIR="${SYSROOT}/var/cache/portage/${CATEGORY}/rust-artifacts"
+CROS_RUSTC_BUILD_DIR="${CROS_RUSTC_DIR}/build"
+CROS_RUSTC_SRC_DIR="${CROS_RUSTC_DIR}/src"
+
+S="${CROS_RUSTC_SRC_DIR}/${MY_P}-src"
+
+_CROS_RUSTC_PREPARED_STAMP="${CROS_RUSTC_SRC_DIR}/cros-rust-prepared"
+_CROS_RUSTC_STAGE1_EXISTS_STAMP="${CROS_RUSTC_BUILD_DIR}/cros-rust-has-stage1-build"
+
+# @FUNCTION: cros-rustc_has_existing_checkout
+# @DESCRIPTION:
+# Tests whether we have a properly src_prepare'd checkout in ${CROS_RUSTC_DIR}.
+cros-rustc_has_existing_checkout() {
+	[[ -e "${_CROS_RUSTC_PREPARED_STAMP}" ]]
+}
+
+# @FUNCTION: cros-rustc_has_existing_stage1_build
+# @DESCRIPTION:
+# Tests whether ${CROS_RUSTC_BUILD_DIR} has a valid stage1 toolchain available.
+cros-rustc_has_existing_stage1_build() {
+	[[ -e "${_CROS_RUSTC_STAGE1_EXISTS_STAMP}" ]]
+}
+
+cros-rustc_pkg_setup() {
+	python-any-r1_pkg_setup
+
+	if [[ ${MERGE_TYPE} != "binary" ]]; then
+		addwrite "${CROS_RUSTC_DIR}"
+		mkdir -p -m 755 "${CROS_RUSTC_DIR}"
+		chown "${PORTAGE_USERNAME}:${PORTAGE_GRPNAME}" "${CROS_RUSTC_DIR}"
+	fi
+}
+
+cros-rustc_src_unpack() {
+	local dirs=( "${CROS_RUSTC_BUILD_DIR}" "${CROS_RUSTC_SRC_DIR}" )
+	if [[ -e "${CROS_RUSTC_SRC_DIR}" || -e "${CROS_RUSTC_BUILD_DIR}" ]]; then
+		einfo "Removing old source/build directories..."
+		rm -rf "${dirs[@]}"
+	fi
+
+	mkdir -p -m 755 "${dirs[@]}"
+	(cd "${CROS_RUSTC_SRC_DIR}" && default)
+}
+
+cros-rustc_src_prepare() {
+	# Copy "unknown" vendor targets to create cros_sdk target triple
+	# variants as referred to in 0001-add-cros-targets.patch and
+	# RUSTC_TARGET_TRIPLES. armv7a is treated specially because the cros
+	# toolchain differs in more than just the vendor part of the target
+	# triple. The arch is armv7a in cros versus armv7.
+	pushd compiler/rustc_target/src/spec || die
+	sed -e 's:"unknown":"pc":g' x86_64_unknown_linux_gnu.rs >x86_64_pc_linux_gnu.rs || die
+	sed -e 's:"unknown":"cros":g' x86_64_unknown_linux_gnu.rs >x86_64_cros_linux_gnu.rs || die
+	sed -e 's:"unknown":"cros":g' armv7_unknown_linux_gnueabihf.rs >armv7a_cros_linux_gnueabihf.rs || die
+	sed -e 's:"unknown":"cros":g' aarch64_unknown_linux_gnu.rs >aarch64_cros_linux_gnu.rs || die
+	popd || die
+
+	# The miri tool is built because of 'extended = true' in
+	# cros-config.toml, but the build is busted. See the upstream issue:
+	# [https://github.com/rust- lang/rust/issues/56576]. Because miri isn't
+	# installed or needed, this sed script eradicates the command that
+	# builds it during the bootstrap script.
+	pushd src/bootstrap || die
+	sed -i 's@tool::Miri,@@g' builder.rs
+	popd || die
+
+	# Tsk. Tsk. The rust makefile for LLVM's compiler-rt uses -ffreestanding
+	# but one of the files includes <stdlib.h> causing occasional problems
+	# with MB_LEN_MAX. See crbug.com/730845 for the thrilling details. This
+	# line patches over the problematic include.
+	sed -e 's:#include <stdlib.h>:void abort(void);:g' \
+		-i "${ECONF_SOURCE:-.}"/src/llvm-project/compiler-rt/lib/builtins/int_util.c || die
+
+	# For the rustc_llvm module, the build will link with -nodefaultlibs and
+	# manually choose the std C++ library. For x86_64 Linux, the build
+	# script always chooses libstdc++ which will not work if LLVM was built
+	# with USE="default-libcxx". This snippet changes that choice to libc++
+	# in the case that clang++ defaults to libc++.
+	if "${CXX}" -### -x c++ - < /dev/null 2>&1 | grep -q -e '-lc++'; then
+		sed -i 's:"stdc++":"c++":g' compiler/rustc_llvm/build.rs || die
+	fi
+
+	default
+
+	touch "${_CROS_RUSTC_PREPARED_STAMP}"
+}
+
+cros-rustc_src_configure() {
+	tc-export PKG_CONFIG
+
+	local targets=""
+	local tt
+	for tt in "${RUSTC_TARGET_TRIPLES[@]}" "${RUSTC_BARE_TARGET_TRIPLES[@]}" ; do
+		targets+="\"${tt}\", "
+	done
+
+	local config=cros-config.toml
+	cat > "${config}" <<EOF
+[build]
+target = [${targets}]
+cargo = "/opt/rust-bootstrap-${BOOTSTRAP_VERSION}/bin/cargo"
+rustc = "/opt/rust-bootstrap-${BOOTSTRAP_VERSION}/bin/rustc"
+docs = false
+submodules = false
+python = "${EPYTHON}"
+vendor = true
+extended = true
+tools = ["cargo", "rustfmt", "clippy", "cargofmt"]
+sanitizers = true
+profiler = true
+build-dir = "${CROS_RUSTC_BUILD_DIR}"
+
+[llvm]
+ninja = true
+targets = "AArch64;ARM;X86"
+
+[install]
+prefix = "${ED}usr"
+libdir = "$(get_libdir)"
+mandir = "share/man"
+
+[rust]
+default-linker = "${CBUILD}-clang"
+description = "${PF}"
+channel = "nightly"
+codegen-units = 0
+llvm-libunwind = 'in-tree'
+codegen-tests = false
+new-symbol-mangling = true
+
+EOF
+
+	for tt in "${RUSTC_TARGET_TRIPLES[@]}" ; do
+		cat >> "${config}" <<EOF
+[target."${tt}"]
+cc = "${tt}-clang"
+cxx = "${tt}-clang++"
+linker = "${tt}-clang++"
+
+EOF
+	done
+}
+
+cros-rustc_src_compile() {
+	${EPYTHON} x.py build --stage 2 --config cros-config.toml "$@" || die
+
+	# Remove the src/rust symlink which will be dangling after sources are
+	# removed, and the containing src directory.
+	rm "${CROS_RUSTC_BUILD_DIR}/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src/rust" || die
+	rmdir "${CROS_RUSTC_BUILD_DIR}/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src" || die
+
+	# Since we always build for stage2, we're guaranteed that stage1 exists
+	# at this point.
+	touch "${_CROS_RUSTC_STAGE1_EXISTS_STAMP}"
+}
+fi
diff --git a/profiles/base/profile.bashrc b/profiles/base/profile.bashrc
index 4ce0343..f5c3244 100644
--- a/profiles/base/profile.bashrc
+++ b/profiles/base/profile.bashrc
@@ -196,7 +196,6 @@
 		dev-util/shellcheck:*) return 1;;
 		dev-haskell/*) return 1;;
 		dev-lang/ghc:*) return 1;;
-		dev-lang/rust:*) return 1;;
 		dev-python/pycairo:1.20*) return 1;;
 		media-video/ffmpeg:4.4*) return 1;;
 		net-analyzer/wireshark:3.4.*) return 1;;
@@ -212,7 +211,6 @@
 		app-text/xmlto:*|\
 		cross-*/gdb:*|\
 		dev-embedded/u-boot-tools:2018.05*|\
-		dev-lang/rust:*|\
 		dev-libs/libffi:3.1*|\
 		dev-libs/libusb-compat:0.1.5*|\
 		dev-libs/lzo:*|\
diff --git a/virtual/rust/rust-1.58.1-r1.ebuild b/virtual/rust/rust-1.58.1-r1.ebuild
new file mode 120000
index 0000000..8a2616e
--- /dev/null
+++ b/virtual/rust/rust-1.58.1-r1.ebuild
@@ -0,0 +1 @@
+rust-1.58.1.ebuild
\ No newline at end of file
diff --git a/virtual/target-chromium-os-sdk/target-chromium-os-sdk-9999.ebuild b/virtual/target-chromium-os-sdk/target-chromium-os-sdk-9999.ebuild
index 3c73435..84a332b 100644
--- a/virtual/target-chromium-os-sdk/target-chromium-os-sdk-9999.ebuild
+++ b/virtual/target-chromium-os-sdk/target-chromium-os-sdk-9999.ebuild
@@ -34,6 +34,7 @@
 	app-arch/p7zip
 	app-arch/tar
 	app-shells/bash
+	dev-lang/rust-host
 	net-misc/iputils
 	net-misc/rsync
 	sys-apps/baselayout