Mike Frysinger | 51a0a6b | 2022-09-09 09:21:07 -0400 | [diff] [blame] | 1 | # Copyright 2020 The ChromiumOS Authors |
George Burgess IV | 2e2bdda | 2021-07-28 04:40:02 +0000 | [diff] [blame] | 2 | # Distributed under the terms of the GNU General Public License v2 |
| 3 | |
| 4 | # Bootstraps rustc (the official Rust compiler) using mrustc (a Rust |
| 5 | # compiler written in C++). |
| 6 | # |
| 7 | # The version of this ebuild reflects the version of rustc that will |
| 8 | # ultimately be installed. |
| 9 | # |
| 10 | # This ebuild can be used in two modes, controlled by the fullbootstrap |
| 11 | # USE flag: |
| 12 | # |
| 13 | # fullbootstrap: Build everything from source. This can take over |
| 14 | # 10 hours. |
| 15 | # |
| 16 | # -fullbootstrap: Start with a prebuilt from an earlier rust-bootstrap |
| 17 | # and build only versions after that from source. |
| 18 | # |
| 19 | # The default is -fullbootstrap, so that you only get the 10+ hour build |
| 20 | # time if you explicitly request it. |
| 21 | |
| 22 | EAPI=7 |
| 23 | |
| 24 | inherit toolchain-funcs |
| 25 | |
| 26 | DESCRIPTION="Bootstraps the rustc Rust compiler using mrustc" |
| 27 | HOMEPAGE="https://github.com/thepowersgang/mrustc" |
| 28 | MRUSTC_VERSION="0.9" |
| 29 | MRUSTC_NAME="mrustc-${MRUSTC_VERSION}" |
| 30 | |
| 31 | SLOT="${PV}" |
| 32 | KEYWORDS="*" |
| 33 | IUSE="-fullbootstrap" |
| 34 | |
| 35 | INITIAL_RUSTC_VERSION="1.29.0" |
| 36 | # Versions of rustc to build after the initial one. |
| 37 | RUSTC_RAW_FULL_BOOTSTRAP_SEQUENCE=( |
| 38 | 1.30.0 |
| 39 | 1.31.1 |
| 40 | 1.32.0 |
| 41 | 1.33.0 |
| 42 | 1.34.2 |
| 43 | 1.35.0 |
| 44 | 1.36.0 |
| 45 | 1.37.0 |
| 46 | 1.38.0 |
| 47 | 1.39.0 |
| 48 | 1.40.0 |
| 49 | 1.41.1 |
| 50 | 1.42.0 |
| 51 | 1.43.1 |
| 52 | 1.44.1 |
| 53 | 1.45.2 |
| 54 | 1.46.0 |
| 55 | 1.47.0 |
| 56 | 1.48.0 |
| 57 | 1.49.0 |
| 58 | 1.50.0 |
George Burgess IV | df40ff0 | 2021-08-01 09:41:49 +0000 | [diff] [blame] | 59 | 1.51.0 |
George Burgess IV | db84f75 | 2021-08-05 06:43:19 +0000 | [diff] [blame] | 60 | 1.52.0 |
Bob Haarman | c1d2b0c | 2021-09-15 23:56:57 +0000 | [diff] [blame] | 61 | 1.53.0 |
George Burgess IV | 5fdb488 | 2022-01-21 02:31:08 -0800 | [diff] [blame] | 62 | 1.54.0 |
| 63 | 1.55.0 |
| 64 | 1.56.1 |
| 65 | 1.57.0 |
Bob Haarman | b5128bf | 2022-04-11 11:27:38 -0700 | [diff] [blame] | 66 | 1.58.1 |
George Burgess IV | 88961b8 | 2022-07-14 11:42:39 -0700 | [diff] [blame] | 67 | 1.59.0 |
Michael Benfield | fbcc7a8 | 2022-07-13 23:20:28 +0000 | [diff] [blame] | 68 | 1.60.0 |
George Burgess IV | 997d7af | 2022-09-22 14:58:57 -0700 | [diff] [blame] | 69 | 1.61.0 |
Michael Benfield | b7aaf3a | 2022-11-03 21:12:40 +0000 | [diff] [blame] | 70 | 1.62.0 |
Michael Benfield | e3a69b0 | 2022-11-10 19:21:47 +0000 | [diff] [blame] | 71 | 1.63.0 |
George Burgess IV | 2e2bdda | 2021-07-28 04:40:02 +0000 | [diff] [blame] | 72 | ) |
| 73 | |
| 74 | RUSTC_FULL_BOOTSTRAP_SEQUENCE=() |
| 75 | |
| 76 | for version in "${RUSTC_RAW_FULL_BOOTSTRAP_SEQUENCE[@]}"; do |
| 77 | if [[ ! "${PV}" > "${version}" ]]; then |
| 78 | break |
| 79 | fi |
| 80 | RUSTC_FULL_BOOTSTRAP_SEQUENCE+=( "${version}" ) |
| 81 | done |
| 82 | |
| 83 | # When not using fullbootstrap, use this version as a starting point. |
| 84 | PREBUILT_VERSION="${RUSTC_FULL_BOOTSTRAP_SEQUENCE[-1]}" |
| 85 | SRC_URI="gs://chromeos-localmirror/distfiles/rustc-${PV}-src.tar.gz |
| 86 | !fullbootstrap? ( gs://chromeos-localmirror/distfiles/rust-bootstrap-${PREBUILT_VERSION}.tbz2 ) |
| 87 | fullbootstrap? ( gs://chromeos-localmirror/distfiles/${MRUSTC_NAME}.tar.gz ) |
| 88 | fullbootstrap? ( gs://chromeos-localmirror/distfiles/rustc-${INITIAL_RUSTC_VERSION}-src.tar.gz )" |
| 89 | for version in "${RUSTC_FULL_BOOTSTRAP_SEQUENCE[@]}"; do |
| 90 | SRC_URI+=" fullbootstrap? ( gs://chromeos-localmirror/distfiles/rustc-${version}-src.tar.gz )" |
| 91 | done |
| 92 | |
| 93 | LICENSE="MIT Apache-2.0 BSD-1 BSD-2 BSD-4 UoI-NCSA" |
| 94 | |
| 95 | DEPEND="dev-libs/openssl |
| 96 | net-libs/libssh2" |
| 97 | RDEPEND="${DEPEND}" |
| 98 | |
| 99 | # These tasks take a long time to run for not much benefit: Most of the files |
| 100 | # they check are never installed. Those that are are only there to bootstrap |
| 101 | # the rust ebuild, which has the same RESTRICT anyway. |
| 102 | RESTRICT="binchecks strip" |
| 103 | |
| 104 | pkg_setup() { |
| 105 | if use fullbootstrap; then |
| 106 | RUSTC_VERSION_SEQUENCE=( "${RUSTC_FULL_BOOTSTRAP_SEQUENCE[@]}" ) |
| 107 | PATCHES=( |
| 108 | "${FILESDIR}/${PN}-no-curl.patch" |
| 109 | "${FILESDIR}/${PN}-compilation-fixes.patch" |
| 110 | "${FILESDIR}/${PN}-8ddb05-invalid-output-constraint.patch" |
| 111 | "${FILESDIR}/${PN}-libgit2-sys-pkg-config.patch" |
| 112 | "${FILESDIR}/${PN}-cc.patch" |
| 113 | "${FILESDIR}/${PN}-printf.patch" |
| 114 | "${FILESDIR}/${PN}-1.48.0-libc++.patch" |
| 115 | ) |
| 116 | S="${WORKDIR}/${MRUSTC_NAME}" |
| 117 | else |
| 118 | RUSTC_VERSION_SEQUENCE=( ) |
| 119 | # We manually apply patches to rustcs in the version sequence, |
| 120 | # so that we can pass the necessary -p value. To prevent |
| 121 | # default from trying and failing to apply patches, we set |
| 122 | # PATCHES to empty. |
| 123 | PATCHES=( ) |
| 124 | S="${WORKDIR}/rustc-${PV}-src" |
| 125 | fi |
| 126 | RUSTC_VERSION_SEQUENCE+=( ${PV} ) |
| 127 | } |
| 128 | |
| 129 | src_unpack() { |
| 130 | default |
| 131 | if use fullbootstrap; then |
| 132 | # Move rustc sources to where mrustc expects them. |
| 133 | mv "${WORKDIR}/rustc-${INITIAL_RUSTC_VERSION}-src" "${S}" || die |
| 134 | fi |
| 135 | } |
| 136 | |
| 137 | src_prepare() { |
| 138 | # Call the default implementation. This applies PATCHES. |
| 139 | default |
| 140 | |
| 141 | if use fullbootstrap; then |
| 142 | |
| 143 | # The next few steps mirror what mrustc's Makefile does to configure the |
| 144 | # build for a specific rustc version. |
| 145 | (cd "rustc-${INITIAL_RUSTC_VERSION}-src" || die; eapply -p0 "${S}/rustc-${INITIAL_RUSTC_VERSION}-src.patch") |
| 146 | cd "${S}" || die |
| 147 | echo "${INITIAL_RUSTC_VERSION}" > "rust-version" || die |
| 148 | cp "rust-version" "rustc-${INITIAL_RUSTC_VERSION}-src/dl-version" || die |
| 149 | fi |
| 150 | |
| 151 | # There are some patches that need to be applied to the rustc versions |
| 152 | # we build with rustc. Apply them here. |
| 153 | local version |
| 154 | for version in "${RUSTC_VERSION_SEQUENCE[@]}"; do |
| 155 | einfo "Patching rustc-${version}" |
| 156 | # The location of files we patch changed in 1.48. |
| 157 | # We have patches with no version number for versions |
| 158 | # before 1.48, and with version number for after. |
| 159 | local libc_patch="${FILESDIR}/${PN}-1.48.0-libc++.patch" |
| 160 | if [[ "${version}" < "1.48.0" ]]; then |
| 161 | libc_patch="${FILESDIR}/${PN}-libc++.patch" |
| 162 | fi |
| 163 | (cd "${WORKDIR}/rustc-${version}-src" || die; eapply -p2 "${libc_patch}") |
| 164 | done |
| 165 | } |
| 166 | |
| 167 | src_configure() { |
| 168 | # Avoid the default implementation, which overwrites vendored |
| 169 | # config.guess and config.sub files, which then causes checksum |
| 170 | # errors during the build, e.g. |
| 171 | # 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: |
| 172 | # expected: 12e217c83267f1ff4bad5d9b2b847032d91e89ec957deb34ec8cb5cef00eba1e |
| 173 | # actual: 312ea023101dc1de54aa8c50ed0e82cb9c47276316033475ea403cb86fe88ffe |
| 174 | # (The dev-lang/rust ebuilds in Chrome OS and Gentoo also have custom |
| 175 | # src_configure implementations.) |
| 176 | true |
| 177 | } |
| 178 | |
| 179 | src_compile() { |
| 180 | # 1. Build initial rustc using mrustc |
| 181 | # ----------------------------------- |
| 182 | # |
| 183 | # All of these specify: |
| 184 | # - CC and CXX so that we build with Clang instead of a GCC version that defaults to pre-C99 C. |
| 185 | # - LLVM_TARGETS, else it will be empty and rustc will not work. |
| 186 | # - RUSTC_VERSION because the Makefiles will otherwise set it to an incorrect value. |
| 187 | # - OPENSSL_DIR so that cargo knows where to look for OpenSSL headers. |
| 188 | export CC=$(tc-getBUILD_CC) |
| 189 | export CXX=$(tc-getBUILD_CXX) |
| 190 | export PKG_CONFIG=$(tc-getBUILD_PKG_CONFIG) |
| 191 | export OPENSSL_DIR="${ESYSROOT}/usr" |
| 192 | # Only actually build mrustc when using fullbootstrap. |
| 193 | if use fullbootstrap; then |
| 194 | # Two separate commands, because invoking just the second command leads to race |
| 195 | # conditions. |
| 196 | emake LLVM_TARGETS=X86 RUSTC_VERSION=${INITIAL_RUSTC_VERSION} output/rustc output/cargo |
| 197 | emake LLVM_TARGETS=X86 RUSTC_VERSION=${INITIAL_RUSTC_VERSION} -C run_rustc |
| 198 | fi |
| 199 | |
| 200 | # 2. Build successive versions of rustc using previous rustc |
| 201 | # ---------------------------------------------------------- |
| 202 | if use fullbootstrap; then |
| 203 | local prev_version=${INITIAL_RUSTC_VERSION} |
| 204 | local prev_cargo="${S}/run_rustc/output/prefix/bin/cargo" |
| 205 | local prev_rustc="${S}/run_rustc/output/prefix/bin/rustc" |
| 206 | else |
| 207 | local prev_version=${PREBUILT_VERSION} |
| 208 | local prev_cargo="${WORKDIR}/opt/rust-bootstrap-${PREBUILT_VERSION}/bin/cargo" |
| 209 | local prev_rustc="${WORKDIR}/opt/rust-bootstrap-${PREBUILT_VERSION}/bin/rustc" |
| 210 | fi |
| 211 | local next_version rustc_dir |
| 212 | for next_version in "${RUSTC_VERSION_SEQUENCE[@]}"; do |
| 213 | einfo "Building rustc-${next_version} using rustc-${prev_version}" |
Michael Benfield | fbcc7a8 | 2022-07-13 23:20:28 +0000 | [diff] [blame] | 214 | # This became necessary in Rust 1.61.0. |
| 215 | local static_libstdcpp='static-libstdcpp = false' |
| 216 | if [[ "${next_version}" < "1.61.0" ]]; then |
| 217 | static_libstdcpp='' |
| 218 | fi |
George Burgess IV | 2e2bdda | 2021-07-28 04:40:02 +0000 | [diff] [blame] | 219 | rustc_dir="${WORKDIR}/rustc-${next_version}-src" |
| 220 | cd "${rustc_dir}" || die "Could not chdir to ${rustc_dir}" |
| 221 | cat > config.toml <<EOF |
| 222 | [build] |
| 223 | cargo = "${prev_cargo}" |
| 224 | rustc = "${prev_rustc}" |
| 225 | docs = false |
| 226 | vendor = true |
| 227 | # extended means we also build cargo and a few other commands. |
| 228 | extended = true |
| 229 | # For rust-bootstrap, we need only cargo. |
| 230 | tools = [ "cargo" ] |
| 231 | |
| 232 | [install] |
| 233 | prefix = "${ED}/opt/rust-bootstrap-${next_version}" |
| 234 | |
| 235 | [rust] |
| 236 | default-linker = "${CC}" |
| 237 | |
| 238 | [llvm] |
| 239 | # For rust-bootstrap, we only need x86_64, which LLVM calls X86. |
| 240 | targets = "X86" |
Michael Benfield | fbcc7a8 | 2022-07-13 23:20:28 +0000 | [diff] [blame] | 241 | ${static_libstdcpp} |
George Burgess IV | 2e2bdda | 2021-07-28 04:40:02 +0000 | [diff] [blame] | 242 | |
| 243 | [target.x86_64-unknown-linux-gnu] |
| 244 | cc = "${CC}" |
| 245 | cxx = "${CXX}" |
| 246 | linker = "${CC}" |
| 247 | EOF |
| 248 | |
| 249 | # --stage 2 causes this to use the previously-built compiler, |
| 250 | # instead of the default behavior of downloading one from |
| 251 | # upstream. |
| 252 | ./x.py --stage 2 build || die |
| 253 | # For some rustc versions (e.g. 1.31.1), the build script will exit with |
| 254 | # a nonzero exit status because miri fails to build when it is not in a git |
| 255 | # repository. This does not affect the ability to build the next rustc. |
| 256 | # So instead of looking at the exit code, we check if rustc and cargo |
| 257 | # were built. |
| 258 | prev_version=${next_version} |
| 259 | prev_cargo="${rustc_dir}/build/x86_64-unknown-linux-gnu/stage2-tools/x86_64-unknown-linux-gnu/release/cargo" |
| 260 | prev_rustc="${rustc_dir}/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" |
| 261 | [[ -x "${prev_rustc}" ]] || die "Failed to build ${prev_rustc}" |
| 262 | [[ -x "${prev_cargo}" ]] || die "Failed to build ${prev_cargo}" |
| 263 | einfo "Built rustc-${next_version}" |
| 264 | done |
| 265 | |
| 266 | # Remove the src/rust symlink which will be dangling after sources are |
| 267 | # removed, and the containing src directory. |
| 268 | rm "${WORKDIR}/rustc-${PV}-src/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src/rust" || die |
| 269 | rmdir "${WORKDIR}/rustc-${PV}-src/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src" || die |
| 270 | } |
| 271 | |
| 272 | src_install() { |
| 273 | local obj="${WORKDIR}/rustc-${PV}-src/build/x86_64-unknown-linux-gnu/stage2" |
| 274 | local tools="${obj}-tools/x86_64-unknown-linux-gnu/release/" |
| 275 | exeinto "/opt/${P}/bin" |
| 276 | # With rustc-1.45.2 at least, regardless of the value of install.libdir, |
| 277 | # the rpath seems to end up as $ORIGIN/../lib. So install the libraries there. |
| 278 | insinto "/opt/${P}/lib" |
| 279 | doexe "${obj}/bin/rustc" |
| 280 | doexe "${tools}/cargo" |
| 281 | doins -r "${obj}/lib/"* |
| 282 | find "${D}" -name '*.so' -exec chmod +x '{}' ';' |
| 283 | } |