blob: f3e285ff9d3685ffdfff138020eb2360e98979fb [file] [log] [blame]
# Copyright 2020 The ChromiumOS Authors
# Distributed under the terms of the GNU General Public License v2
# Bootstraps newer versions of rustc from older versions of rustc. In the past,
# this package was bootstrapped from the `mrustc` compiler, to avoid trusting
# trust attacks. We use this as our stage0 compiler for `dev-lang/rust`, rather
# than downloading an upstream bootstrap binary.
#
# The version of this ebuild reflects the version of rustc that will
# ultimately be installed.
EAPI=7
inherit toolchain-funcs
DESCRIPTION="Bootstraps the rustc Rust compiler using mrustc"
HOMEPAGE="https://github.com/thepowersgang/mrustc"
SLOT="${PV}"
KEYWORDS="*"
# THIS_VERSION_HAS_PREBUILT is nonempty if there's a prebuilt that should be
# downloaded and installed for this version of rust-bootstrap.
THIS_VERSION_HAS_PREBUILT=1
# PRIOR_RUST_BOOTSTRAP_VERSION is the version of rust-bootstrap we need in
# order to build the current version of rust-bootstrap.
PRIOR_RUST_BOOTSTRAP_VERSION="1.75.0"
LICENSE="MIT Apache-2.0 BSD-1 BSD-2 BSD-4 UoI-NCSA"
is_only_installing_prebuilt() {
[[ -n "${THIS_VERSION_HAS_PREBUILT}" ]]
}
# NOTE: We have to mirror rustc's sources, even if we're only copying prebuilts
# around. This is because our prebuilt tarballs contain no licenses, and portage
# requires licenses.
SRC_URI="gs://chromeos-localmirror/distfiles/rustc-${PV}-src.tar.gz"
if is_only_installing_prebuilt; then
SRC_URI+=" gs://chromeos-localmirror/distfiles/rust-bootstrap-${PV}.tbz2"
else
# If this package isn't simply installing a prebuilt, we need to BDEPEND
# on the parent rust-bootstrap, to have something to build from. The
# expectation is that `is_only_installing_prebuilt` will essentially
# always be true in production, so this should rarely pull in the prior
# rust-bootstrap package.
BDEPEND="
dev-lang/rust-bootstrap:${PRIOR_RUST_BOOTSTRAP_VERSION}
dev-util/cmake
dev-util/ninja
net-misc/curl
"
fi
DEPEND="dev-libs/openssl"
RDEPEND="${DEPEND}"
# These tasks take a long time to run for not much benefit: Most of the files
# they check are never installed. Those that are are only there to bootstrap
# the rust ebuild, which has the same RESTRICT anyway.
RESTRICT="binchecks strip"
pkg_setup() {
# We manually apply patches to rustc, so that we can pass the necessary
# -p value & be in the correct directory. To prevent default from
# trying and failing to apply patches, we set PATCHES to empty.
PATCHES=( )
S="${WORKDIR}/rustc-${PV}-src"
}
src_prepare() {
# Call the default implementation. This applies PATCHES.
default
is_only_installing_prebuilt && return
einfo "No rust-bootstrap prebuilt available; building from source"
einfo "Patching rustc-${PV}"
(
cd "${WORKDIR}/rustc-${PV}-src" || die
eapply -p2 "${FILESDIR}/${PN}-1.48.0-libc++.patch"
)
# In order to build rustc with host=x86_64-pc-linux-gnu, the
# bootstrap compiler needs to recognize x86_64-pc-linux-gnu.
local host_patch="${FILESDIR}/rust-bootstrap-add-host-target.patch"
local specs_dir="${WORKDIR}/rustc-${PV}-src/compiler/rustc_target/src/spec/targets"
(cd "${WORKDIR}/rustc-${PV}-src" || die; eapply -p1 "${host_patch}")
(
cd "${specs_dir}" &&
sed -e 's:"unknown":"pc":g' x86_64_unknown_linux_gnu.rs >x86_64_pc_linux_gnu.rs
) || die
}
src_configure() {
# Avoid the default implementation, which overwrites vendored
# config.guess and config.sub files, which then causes checksum
# errors during the build, e.g.
# error: the listed checksum of `/var/tmp/portage/dev-lang/rust-bootstrap-1.46.0/work/rustc-1.46.0-src/vendor/backtrace-sys/src/libbacktrace/config.guess` has changed:
# expected: 12e217c83267f1ff4bad5d9b2b847032d91e89ec957deb34ec8cb5cef00eba1e
# actual: 312ea023101dc1de54aa8c50ed0e82cb9c47276316033475ea403cb86fe88ffe
# (The dev-lang/rust ebuilds in Chrome OS and Gentoo also have custom
# src_configure implementations.)
true
}
# Prints the absolute path to the given tool, or `die`s.
tool_abspath() {
local cmd tool="$1"
cmd="$(type -P "${tool}")" || die "Couldn't look up ${tool}"
realpath --no-symlinks "${cmd}" || die
}
src_compile() {
is_only_installing_prebuilt && return
# 1. Build initial rustc using mrustc
# -----------------------------------
#
# All of these specify:
# - CC and CXX so that we build with Clang instead of a GCC version that defaults to pre-C99 C.
# - LLVM_TARGETS, else it will be empty and rustc will not work.
# - RUSTC_VERSION because the Makefiles will otherwise set it to an incorrect value.
# - OPENSSL_DIR so that cargo knows where to look for OpenSSL headers.
# - OPENSSL_LIB_DIR so that cargo knows where to look for OpenSSL libraries.
export CC=$(tc-getBUILD_CC)
export CXX=$(tc-getBUILD_CXX)
export PKG_CONFIG=$(tc-getBUILD_PKG_CONFIG)
export OPENSSL_DIR="${ESYSROOT}/usr"
export OPENSSL_LIB_DIR="${ESYSROOT}/usr/$(get_libdir)"
# TODO: Are these needed? ^
# ccache llvm builds if FEATURES=ccache is set. Don't set it to true
# unconditionally, since having `ccache=true` slows builds down by a
# handful of seconds, even with `CCACHE_DISABLE=true` set.
local use_ccache=false
[[ -z "${CCACHE_DISABLE:-}" ]] && use_ccache=true
local ar ranlib
# These need to be absolute paths for Rust to accept them; see
# discussion on b/277968325 comments 6-10.
ar="$(tool_abspath "$(tc-getBUILD_AR)")"
ranlib="$(tool_abspath "$(tc-getBUILD_RANLIB)")"
einfo "Building rustc-${PV} using rustc-${PRIOR_RUST_BOOTSTRAP_VERSION}"
local rustc_dir="${WORKDIR}/rustc-${PV}-src"
cd "${rustc_dir}" || die "Could not chdir to ${rustc_dir}"
cat > config.toml <<EOF
[build]
cargo = "/opt/rust-bootstrap-${PRIOR_RUST_BOOTSTRAP_VERSION}/bin/cargo"
rustc = "/opt/rust-bootstrap-${PRIOR_RUST_BOOTSTRAP_VERSION}/bin/rustc"
docs = false
vendor = true
# extended means we also build cargo and a few other commands.
extended = true
# For rust-bootstrap, we need only cargo.
tools = [ "cargo" ]
[install]
prefix = "${ED}/opt/rust-bootstrap-${PV}"
[rust]
default-linker = "${CC}"
[llvm]
download-ci-llvm = false
ccache = ${use_ccache}
# For rust-bootstrap, we only need x86_64, which LLVM calls X86.
experimental-targets = ""
targets = "X86"
static-libstdcpp = false
[target.x86_64-unknown-linux-gnu]
ar = "${ar}"
cc = "${CC}"
cxx = "${CXX}"
linker = "${CC}"
ranlib = "${ranlib}"
EOF
# --stage 2 causes this to use the previously-built compiler,
# instead of the default behavior of downloading one from
# upstream.
./x.py --stage 2 build || die
# Remove the src/rust symlink which will be dangling after sources are
# removed, and the containing src directory.
rm "${WORKDIR}/rustc-${PV}-src/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src/rust" || die
rmdir "${WORKDIR}/rustc-${PV}-src/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src" || die
}
src_install() {
local obj tools
if is_only_installing_prebuilt; then
obj="${WORKDIR}/opt/rust-bootstrap-${PV}"
tools="${obj}/bin"
else
obj="${WORKDIR}/rustc-${PV}-src/build/x86_64-unknown-linux-gnu/stage2"
tools="${obj}-tools/x86_64-unknown-linux-gnu/release/"
fi
exeinto "/opt/${P}/bin"
# With rustc-1.45.2 at least, regardless of the value of install.libdir,
# the rpath seems to end up as $ORIGIN/../lib. So install the libraries there.
insinto "/opt/${P}/lib"
doexe "${obj}/bin/rustc"
doexe "${tools}/cargo"
doins -r "${obj}/lib/"*
find "${D}" -name '*.so' -exec chmod +x '{}' ';'
}