blob: ac770ab263aab75f0d57ecc670f18cb92fadeca1 [file] [log] [blame]
Mike Frysinger51a0a6b2022-09-09 09:21:07 -04001# Copyright 2020 The ChromiumOS Authors
George Burgess IV2e2bdda2021-07-28 04:40:02 +00002# 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
22EAPI=7
23
24inherit toolchain-funcs
25
26DESCRIPTION="Bootstraps the rustc Rust compiler using mrustc"
27HOMEPAGE="https://github.com/thepowersgang/mrustc"
28MRUSTC_VERSION="0.9"
29MRUSTC_NAME="mrustc-${MRUSTC_VERSION}"
30
31SLOT="${PV}"
32KEYWORDS="*"
33IUSE="-fullbootstrap"
34
35INITIAL_RUSTC_VERSION="1.29.0"
36# Versions of rustc to build after the initial one.
37RUSTC_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 IVdf40ff02021-08-01 09:41:49 +000059 1.51.0
George Burgess IVdb84f752021-08-05 06:43:19 +000060 1.52.0
Bob Haarmanc1d2b0c2021-09-15 23:56:57 +000061 1.53.0
George Burgess IV5fdb4882022-01-21 02:31:08 -080062 1.54.0
63 1.55.0
64 1.56.1
65 1.57.0
Bob Haarmanb5128bf2022-04-11 11:27:38 -070066 1.58.1
George Burgess IV88961b82022-07-14 11:42:39 -070067 1.59.0
Michael Benfieldfbcc7a82022-07-13 23:20:28 +000068 1.60.0
George Burgess IV997d7af2022-09-22 14:58:57 -070069 1.61.0
Michael Benfieldb7aaf3a2022-11-03 21:12:40 +000070 1.62.0
Michael Benfielde3a69b02022-11-10 19:21:47 +000071 1.63.0
George Burgess IV2e2bdda2021-07-28 04:40:02 +000072)
73
74RUSTC_FULL_BOOTSTRAP_SEQUENCE=()
75
76for version in "${RUSTC_RAW_FULL_BOOTSTRAP_SEQUENCE[@]}"; do
77 if [[ ! "${PV}" > "${version}" ]]; then
78 break
79 fi
80 RUSTC_FULL_BOOTSTRAP_SEQUENCE+=( "${version}" )
81done
82
83# When not using fullbootstrap, use this version as a starting point.
84PREBUILT_VERSION="${RUSTC_FULL_BOOTSTRAP_SEQUENCE[-1]}"
85SRC_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 )"
89for version in "${RUSTC_FULL_BOOTSTRAP_SEQUENCE[@]}"; do
90 SRC_URI+=" fullbootstrap? ( gs://chromeos-localmirror/distfiles/rustc-${version}-src.tar.gz )"
91done
92
93LICENSE="MIT Apache-2.0 BSD-1 BSD-2 BSD-4 UoI-NCSA"
94
95DEPEND="dev-libs/openssl
96 net-libs/libssh2"
97RDEPEND="${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.
102RESTRICT="binchecks strip"
103
104pkg_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
129src_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
137src_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
167src_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
179src_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 Benfieldfbcc7a82022-07-13 23:20:28 +0000214 # 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 IV2e2bdda2021-07-28 04:40:02 +0000219 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]
223cargo = "${prev_cargo}"
224rustc = "${prev_rustc}"
225docs = false
226vendor = true
227# extended means we also build cargo and a few other commands.
228extended = true
229# For rust-bootstrap, we need only cargo.
230tools = [ "cargo" ]
231
232[install]
233prefix = "${ED}/opt/rust-bootstrap-${next_version}"
234
235[rust]
236default-linker = "${CC}"
237
238[llvm]
239# For rust-bootstrap, we only need x86_64, which LLVM calls X86.
240targets = "X86"
Michael Benfieldfbcc7a82022-07-13 23:20:28 +0000241${static_libstdcpp}
George Burgess IV2e2bdda2021-07-28 04:40:02 +0000242
243[target.x86_64-unknown-linux-gnu]
244cc = "${CC}"
245cxx = "${CXX}"
246linker = "${CC}"
247EOF
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
272src_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}