xref: /aosp_15_r20/external/coreboot/util/crossgcc/buildgcc (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1#!/usr/bin/env sh
2# shellcheck disable=SC2030,SC2031,SC2059
3# The above line must be directly after the shebang line.
4# Disables these warnings:
5# 2030 - Modification of var is local (to subshell caused by pipeline).
6#        shell check 0.4.6 gets confused by the read -t 1 command and interprets
7#        the '1' as $1 getting modified.
8# 2031 - var was modified in a subshell. That change might be lost.
9#        caused by shell check bug with SC2030?  This causes any $1 from that
10#        point on to be flagged.
11# 2059 - Don't use variables in the printf format string. Use printf "..%s.." "$foo".
12#        This is used for all of our color printing.
13
14#
15# SPDX-License-Identifier: GPL-2.0-only
16
17cd "$(dirname "$0")" || exit 1
18
19if [ -z "$CROSSGCC_VERSION" ]; then
20	CROSSGCC_VERSION="$(git log -n 1 --pretty=%cd --date=short .)_$(git log -n 1 --pretty=%h .)"
21fi
22
23# default settings
24PACKAGE=GCC
25TARGETDIR=$(pwd)/xgcc
26TARGETARCH=i386-elf
27DEFAULT_LANGUAGES=c
28LANGUAGES=
29DESTDIR=
30SAVETEMPS=0
31BOOTSTRAP=0
32THREADS=1
33FETCH_ONLY=0
34USE_COREBOOT_MIRROR=0
35COREBOOT_MIRROR_URL="https://www.coreboot.org/releases/crossgcc-sources"
36
37# GCC toolchain version numbers
38GMP_VERSION=6.3.0
39MPFR_VERSION=4.2.1
40MPC_VERSION=1.3.1
41GCC_VERSION=14.1.0
42BINUTILS_VERSION=2.42
43IASL_VERSION="20230628"
44# CLANG version number
45CLANG_VERSION=18.1.6
46CMAKE_VERSION=3.29.3
47NASM_VERSION=2.16.03
48
49# Filename for each package
50GMP_ARCHIVE="gmp-${GMP_VERSION}.tar.xz"
51MPFR_ARCHIVE="mpfr-${MPFR_VERSION}.tar.xz"
52MPC_ARCHIVE="mpc-${MPC_VERSION}.tar.gz"
53GCC_ARCHIVE="gcc-${GCC_VERSION}.tar.xz"
54BINUTILS_ARCHIVE="binutils-${BINUTILS_VERSION}.tar.xz"
55IASL_ARCHIVE="acpica-unix-${IASL_VERSION}.tar.gz"
56# CLANG toolchain FILE locations
57LLD_ARCHIVE="lld-${CLANG_VERSION}.src.tar.xz"
58LLVM_ARCHIVE="llvm-${CLANG_VERSION}.src.tar.xz"
59CLANG_ARCHIVE="clang-${CLANG_VERSION}.src.tar.xz"
60CRT_ARCHIVE="compiler-rt-${CLANG_VERSION}.src.tar.xz"
61CTE_ARCHIVE="clang-tools-extra-${CLANG_VERSION}.src.tar.xz"
62LLVMCMAKE_ARCHIVE="cmake-${CLANG_VERSION}.src.tar.xz"
63LIBUNWIND_ARCHIVE="libunwind-${CLANG_VERSION}.src.tar.xz"
64CMAKE_ARCHIVE="cmake-${CMAKE_VERSION}.tar.gz"
65NASM_ARCHIVE="nasm-${NASM_VERSION}.tar.bz2"
66
67# These URLs are sanitized by the jenkins toolchain test builder, so if
68# a completely new URL is added here, it probably needs to be added
69# to the jenkins build as well, or the builder won't download it.
70
71# GCC toolchain archive locations
72GMP_BASE_URL="https://ftpmirror.gnu.org/gmp"
73MPFR_BASE_URL="https://ftpmirror.gnu.org/mpfr"
74MPC_BASE_URL="https://ftpmirror.gnu.org/mpc"
75GCC_BASE_URL="https://ftpmirror.gnu.org/gcc/gcc-${GCC_VERSION}"
76BINUTILS_BASE_URL="https://ftpmirror.gnu.org/binutils"
77IASL_BASE_URL="https://downloadmirror.intel.com/783534"
78# CLANG toolchain archive locations
79LLVM_BASE_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VERSION}"
80CLANG_BASE_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VERSION}"
81CRT_BASE_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VERSION}"
82CTE_BASE_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VERSION}"
83LLVMCMAKE_BASE_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VERSION}"
84LLD_BASE_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VERSION}"
85LIBUNWIND_BASE_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VERSION}"
86CMAKE_BASE_URL="https://cmake.org/files/v${CMAKE_VERSION%.*}"
87NASM_BASE_URL="https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VERSION}"
88
89ALL_ARCHIVES="$GMP_BASE_URL/$GMP_ARCHIVE $MPFR_BASE_URL/$MPFR_ARCHIVE $MPC_BASE_URL/$MPC_ARCHIVE \
90	$GCC_BASE_URL/$GCC_ARCHIVE $BINUTILS_BASE_URL/$BINUTILS_ARCHIVE $IASL_BASE_URL/$IASL_ARCHIVE \
91	$LLD_BASE_URL/$LLD_ARCHIVE $LLVM_BASE_URL/$LLVM_ARCHIVE $CLANG_BASE_URL/$CLANG_ARCHIVE \
92	$LLVMCMAKE_BASE_URL/$LLVMCMAKE_ARCHIVE $CRT_BASE_URL/$CRT_ARCHIVE $CTE_BASE_URL/$CTE_ARCHIVE \
93	$LIBUNWIND_BASE_URL/$LIBUNWIND_ARCHIVE $CMAKE_BASE_URL/$CMAKE_ARCHIVE $NASM_BASE_URL/$NASM_ARCHIVE"
94
95# GCC toolchain directories
96GMP_DIR="gmp-${GMP_VERSION}"
97MPFR_DIR="mpfr-${MPFR_VERSION}"
98MPC_DIR="mpc-${MPC_VERSION}"
99# shellcheck disable=SC2034
100GCC_DIR="gcc-${GCC_VERSION}"
101# shellcheck disable=SC2034
102BINUTILS_DIR="binutils-${BINUTILS_VERSION}"
103IASL_DIR="acpica-unix-${IASL_VERSION}"
104# CLANG toolchain directories
105LLD_DIR="lld-${CLANG_VERSION}.src"
106LLVM_DIR="llvm-${CLANG_VERSION}.src"
107CLANG_DIR="clang-${CLANG_VERSION}.src"
108CRT_DIR="compiler-rt-${CLANG_VERSION}.src"
109CTE_DIR="clang-tools-extra-${CLANG_VERSION}.src"
110LLVMCMAKE_DIR="cmake-${CLANG_VERSION}.src"
111LIBUNWIND_DIR="libunwind-${CLANG_VERSION}.src"
112CMAKE_DIR="cmake-${CMAKE_VERSION}"
113NASM_DIR="nasm-${NASM_VERSION}"
114
115unset MAKELEVEL MAKEFLAGS
116
117red='\033[0;31m'
118RED='\033[1;31m'
119green='\033[0;32m'
120GREEN='\033[1;32m'
121blue='\033[0;34m'
122CYAN='\033[1;36m'
123NC='\033[0m' # No Color
124
125UNAME=$(if uname | grep -iq cygwin; then echo Cygwin; else uname; fi)
126HALT_FOR_TOOLS=0
127
128hostcc()
129{
130	# $1 "host" or "target"
131	if [ "$BOOTSTRAP" = 1 ] && [ "$1" = target ]; then
132		echo "$DESTDIR$TARGETDIR/bin/gcc"
133	else
134		echo "$CC"
135	fi
136}
137
138hostcxx()
139{
140	# $1 "host" or "target"
141	if [ "$BOOTSTRAP" = 1 ] && [ "$1" = target ]; then
142		echo "$DESTDIR$TARGETDIR/bin/g++"
143	else
144		echo "$CXX"
145	fi
146}
147
148normalize_dirs()
149{
150	mkdir -p "$DESTDIR$TARGETDIR/lib"
151	test -d "$DESTDIR$TARGETDIR/lib32" && mv "$DESTDIR$TARGETDIR"/lib32/* "$DESTDIR$TARGETDIR/lib"
152	test -d "$DESTDIR$TARGETDIR/lib64" && mv "$DESTDIR$TARGETDIR"/lib64/* "$DESTDIR$TARGETDIR/lib"
153	rm -rf "$DESTDIR$TARGETDIR/lib32" "$DESTDIR$TARGETDIR/lib64"
154
155	perl -pi -e "s,/lib32,/lib," "$DESTDIR$TARGETDIR"/lib/*.la
156	perl -pi -e "s,/lib64,/lib," "$DESTDIR$TARGETDIR"/lib/*.la
157}
158
159countdown()
160{
161	tout=${1:-10}
162
163	printf "\nPress Ctrl-C to abort, Enter to continue... %2ds" "$tout"
164	while [ "$tout" -gt 0 ]; do
165		sleep 1
166		tout=$((tout - 1))
167		printf "\b\b\b%2ds" $tout
168	done
169	printf "\n"
170}
171
172timeout()
173{
174	tout=${1:-10}
175
176	# Ignore SIGUSR1, should interrupt `read` though.
177	trap false USR1
178	# Clean up in case the user aborts.
179	trap 'kill $counter > /dev/null 2>&1' EXIT
180
181	(countdown "$tout"; kill -USR1 $$)&
182	counter=$!
183
184	# Some shells with sh compatibility mode (e.g. zsh, mksh) only
185	# let us interrupt `read` if a non-standard -t parameter is given.
186	# shellcheck disable=SC2034,SC2039,SC2162
187	if echo | read -t 1 foo 2>/dev/null; then
188		read -t $((tout + 1)) foo
189	else
190		read foo
191	fi
192
193	kill $counter > /dev/null 2>&1
194	trap - USR1 EXIT
195}
196
197please_install()
198{
199	HALT_FOR_TOOLS=1
200	# shellcheck disable=SC1091
201	test -r /etc/os-release && . /etc/os-release
202	# vanilla debian doesn't define `ID_LIKE`, just `ID`
203	if [ -z "${ID_LIKE}" ] && [ -n "${ID}" ]; then
204		ID_LIKE=${ID}
205	fi
206	case "$ID_LIKE" in
207	debian) solution="sudo apt-get install $1" ;;
208	suse) solution="sudo zypper install $1" ;;
209	*) solution="using your OS packaging system" ;;
210	esac
211
212	printf "${RED}ERROR:${red} Missing tool: Please install '$1'. (eg $solution)${NC}\n" >&2
213	if [ -n "$2" ]; then
214		printf "${RED}ERROR:${red}               or install '$2'.${NC}\n" >&2
215	fi
216}
217
218searchtool()
219{
220	# $1 short name
221	# $2 search string
222	# $3 soft fail if set
223	# $4 alternative package to install on failure
224	# result: file name of that tool on stdout
225	#         or no output if nothing suitable was found
226	search=GNU
227	if [ -n "$2" ]; then
228		search="$2"
229	fi
230	for i in "$1" "g$1" "gnu$1"; do
231		if [ -x "$(command -v "$i" 2>/dev/null)" ]; then
232			if [ "$(cat /dev/null | $i --version 2>&1 | grep -c "$search")" \
233			    -gt 0 ]; then
234				echo "$i"
235				return
236			fi
237		fi
238	done
239	# A workaround for OSX 10.9 and some BSDs, whose nongnu
240	# patch and tar also work.
241	if [ "$UNAME" = "Darwin" ] || [ "$UNAME" = "FreeBSD" ] || [ "$UNAME" = "NetBSD" ] || [ "$UNAME" = "OpenBSD" ]; then
242		if [ "$1" = "patch" ] || [ "$1" = "tar" ]; then
243			if [ -x "$(command -v "$1" 2>/dev/null)" ]; then
244				echo "$1"
245				return
246			fi
247		fi
248	fi
249	if echo "$1" | grep -q "sum" ; then
250		algor=$(echo "$1" | sed -e 's,sum,,')
251		if [ -x "$(command -v "$1" 2>/dev/null)" ]; then
252			#xxxsum [file]
253			echo "$1"
254			return
255		elif [ -x "$(command -v "$algor" 2>/dev/null)" ]; then
256			#xxx [file]
257			echo "$algor"
258			return
259		elif [ -x "$(command -v openssl 2>/dev/null)" ]; then
260			#openssl xxx [file]
261			echo openssl "$algor"
262			return
263		elif [ -x "$(command -v cksum 2>/dev/null)" ]; then
264			#cksum -a xxx [file]
265			#cksum has special options in NetBSD. Actually, NetBSD will use the second case above.
266			echo "buildgcc" | cksum -a "$algor" > /dev/null 2>/dev/null && \
267			echo cksum -a "$algor"
268			return
269		fi
270	fi
271
272	[ -z "$3" ] && please_install "$1" "$4"
273	false
274}
275
276# Run a compile check of the specified library option to see if it's installed
277check_for_library() {
278	LIBRARY_FLAGS="$1"
279	LIBRARY_PACKAGES="$2"
280	LIBTEST_FILE=.libtest
281
282	echo "int main(int argc, char **argv) { (void) argc; (void) argv; return 0; }" > "${LIBTEST_FILE}.c"
283
284	# shellcheck disable=SC2086
285	"$CC" $CFLAGS $LIBRARY_FLAGS "${LIBTEST_FILE}.c" -o "${LIBTEST_FILE}" >/dev/null 2>&1 || \
286		please_install "$LIBRARY_PACKAGES"
287	rm -rf "${LIBTEST_FILE}.c" "${LIBTEST_FILE}"
288}
289
290buildcc_major() {
291	echo "${GCC_VERSION}" | cut -d. -f1
292}
293
294buildcc_minor() {
295	echo "${GCC_VERSION}" | cut -d. -f2
296}
297
298buildcc_version() {
299	echo "${GCC_VERSION}" | cut -d. -f1-2
300}
301
302hostcc_major() {
303	(echo __GNUC__ | ${CC} -E - 2>/dev/null || echo 0) | tail -1
304}
305
306hostcc_minor() {
307	(echo __GNUC_MINOR__ | ${CC} -E - 2>/dev/null || echo 0) | tail -1
308}
309
310hostcc_version() {
311	printf "%d.%d" "$(hostcc_major)" "$(hostcc_minor)"
312}
313
314hostcc_has_gnat1() {
315	[ -x "$(${CC} -print-prog-name=gnat1)" ]
316}
317
318have_gnat() {
319	hostcc_has_gnat1 && \
320	searchtool gnatbind "Free Software Foundation" nofail > /dev/null
321}
322
323ada_requested() {
324	echo "${LANGUAGES}" | grep -q '\<ada\>'
325}
326
327download() {
328	package=$1
329	# shellcheck disable=SC2086
330	if [ "${USE_COREBOOT_MIRROR}" -eq 0 ]; then
331		url="$(eval echo \$$package"_BASE_URL")"
332	else
333		url="${COREBOOT_MIRROR_URL}"
334	fi
335
336	file="$(eval echo \$$package"_ARCHIVE")"
337	printf " * ${file} "
338
339	if test -f "tarballs/${file}"; then
340		printf "(cached)... "
341	else
342		printf "(downloading from ${url}/${file})"
343		rm -f "tarballs/${file}"
344		cd tarballs || exit 1
345		download_showing_percentage "${url}/${file}"
346		cd ..
347	fi
348
349	if [ ! -f "tarballs/${file}" ]; then
350		printf "${RED}Failed to download ${file}.${NC}\n"
351		exit 1
352	fi
353}
354
355# Compute the hash of the package given in $1, and print it raw (just the
356# hexadecimal hash).
357compute_hash() {
358	package=$1
359	# shellcheck disable=SC2086
360	file="$(eval echo \$$package"_ARCHIVE")"
361
362	if test -z "$CHECKSUM"; then
363		echo "${RED}\$CHECKSUM program missing. This is bad.${NC}" 1>&2
364		exit 1
365	fi
366
367	$CHECKSUM "tarballs/$file" 2>/dev/null | sed -e 's@.*\([0-9a-f]\{40,\}\).*@\1@'
368}
369
370error_hash_missing() {
371	package="$1"
372	# shellcheck disable=SC2086
373	file="$(eval echo \$$package"_ARCHIVE")"
374
375	fullhashfile="util/crossgcc/sum/$file.cksum"
376	printf "${RED}hash file missing:${NC}\n\n" 1>&2
377	printf "Please verify util/crossgcc/tarball/$file carefully\n" 1>&2
378	printf "(using PGP if possible), and then rename\n" 1>&2
379	printf "        ${CYAN}${fullhashfile}.calc${NC}\n" 1>&2
380	printf "     to ${CYAN}${fullhashfile}${NC}\n\n" 1>&2
381
382	exit 1
383}
384
385# Read the known hash file of the package given in $1, and print it raw.
386get_known_hash() {
387	package=$1
388	# shellcheck disable=SC2086
389	file="$(eval echo \$$package"_ARCHIVE")"
390	hashfile="sum/$file.cksum"
391
392	if [ ! -f "$hashfile" ]; then
393		calc_hash="$(compute_hash "$package")" || exit 1
394		echo "$calc_hash  tarballs/$file" > "${hashfile}.calc"
395
396		error_hash_missing "$package"
397		exit 1
398	fi
399
400	sed -e 's@.*\([0-9a-f]\{40,\}\).*@\1@' < "$hashfile"
401}
402
403error_hash_mismatch() {
404	package=$1
405	known_hash="$2"
406	computed_hash="$3"
407	# shellcheck disable=SC2086
408	file="$(eval echo \$$package"_ARCHIVE")"
409
410	printf "${RED}hash mismatch:${NC}\n\n"
411	printf "             expected (known) hash: $known_hash\n"
412	printf "calculated hash of downloaded file: $computed_hash\n\n"
413
414	printf "If you think this is due to a network error, please delete\n"
415	printf "  ${CYAN}util/crossgcc/tarballs/$file${NC}\n"
416	printf "and try again. If the problem persists, it may be due to an\n"
417	printf "administration error on the file server, or you might be\n"
418	printf "subject to a Man-in-the-Middle attack\n\n"
419
420	exit 1
421}
422
423# verify_hash - Check that the hash of the file given in $1 matches the known
424# hash; Bail out on mismatch or missing hash file.
425verify_hash() {
426	package=$1
427
428	known_hash="$(get_known_hash "$package")" || exit "$?"
429	computed_hash="$(compute_hash "$package")" || exit "$?"
430
431	if [ "$known_hash" != "$computed_hash" ]; then
432		error_hash_mismatch "$package" "$known_hash" "$computed_hash"
433		exit 1
434	fi
435
436	printf "${GREEN}hash verified (${known_hash})${NC}\n"
437}
438
439unpack_and_patch() {
440	package="$1"
441	# shellcheck disable=SC2086
442	archive="$(eval echo \$$package"_ARCHIVE")"
443	# shellcheck disable=SC2086
444	dir="$(eval echo \$$package"_DIR")"
445	test -d "${dir}" && test -f "${dir}/.unpack_success" || (
446		printf " * "$archive"\n"
447		FLAGS=zxf
448		suffix=$(echo "$archive" | sed 's,.*\.,,')
449		if [ "$suffix" = "gz" ] && [ -n "$PIGZ" ]; then FLAGS="-I pigz -xf"
450		elif [ "$suffix" = "gz" ]; then FLAGS=zxf
451		elif [ "$suffix" = "bz2" ] && [ -n "$LBZIP2" ]; then FLAGS="-I lbzip2 -xf"
452		elif [ "$suffix" = "bz2" ]; then FLAGS=jxf
453		elif [ "$suffix" = "xz" ]; then FLAGS="--xz -xf"
454		elif [ "$suffix" = "lzma" ]; then FLAGS="--lzma -xf"
455		fi
456		# shellcheck disable=SC2086
457		$TAR $FLAGS "tarballs/$archive"
458		for patch in patches/${dir}_*.patch; do
459			test -r "$patch" || continue
460			printf "   o $(basename "$patch")\n"
461			(cd "${dir}" || exit 1; $PATCH -s -N -p1 <"../${patch}") || {
462				printf "\n${RED}Failed $patch.${NC}\n"
463				exit 1
464			}
465		done
466		touch "${dir}/.unpack_success"
467	)
468}
469
470fn_exists()
471{
472	# shellcheck disable=SC2039
473	type "$1" >/dev/null 2>&1
474}
475
476is_package_enabled()
477{
478	echo "$PACKAGES" |grep -q "\<$1\>"
479}
480
481package_uses_targetarch()
482{
483	if [ "$1" = "GCC" ] || [ "$1" = "BINUTILS" ]; then
484		true
485	else
486		false
487	fi
488}
489
490generic_build()
491{
492	package=$1
493	host_target=$2
494	builddir=$3
495	success=$4
496	version=$5
497
498	fn_exists "build_$package" || return
499
500	mkdir -p "$builddir"
501
502	if [ -f "$success" ]; then
503		printf "Skipping $package v$version for $host_target as it is already built\n"
504	else
505		printf "Building $package v$version for $host_target ... "
506		DIR="$PWD"
507		cd "$builddir" || exit 1
508		rm -f .failed
509		"build_${package}" "$host_target" > build.log 2>&1
510		cd "$DIR" || exit 1
511		if [ ! -f "$builddir/.failed" ]; then
512			touch "$success";
513		else
514			printf "${RED}failed${NC}. Check '$builddir/build.log'.\n"
515			exit 1
516		fi
517		printf "${green}ok${NC}\n"
518	fi
519}
520
521build_for_host()
522{
523	package="$1"
524	# shellcheck disable=SC2086
525	version="$(eval echo \$$package"_VERSION")"
526	generic_build "$package" host "build-$package" "${DESTDIR}${TARGETDIR}/.${package}.${version}.success" "$version"
527}
528
529build_for_target()
530{
531	package="$1"
532	# shellcheck disable=SC2086
533	version="$(eval echo \$$package"_VERSION")"
534	generic_build "$package" target "build-${TARGETARCH}-$package" "${DESTDIR}${TARGETDIR}/.${TARGETARCH}-${package}.${version}.success" "$version"
535}
536
537build()
538{
539	if package_uses_targetarch "$1"; then
540		if [ $BOOTSTRAP -eq 1 ] && [ ! -f "${DESTDIR}${TARGETDIR}/.GCC.${GCC_VERSION}.success" ]; then
541			build_for_host GCC
542		fi
543		build_for_target "$1"
544	else
545		build_for_host "$1"
546	fi
547}
548
549exit_handler()
550{
551	printf "${NC}Stop\n"
552	exit 1
553}
554
555cleanup()
556{
557	if [ $SAVETEMPS -ne 0 ]; then
558		printf "Leaving temporary files around... ${green}ok${NC}\n"
559		return
560	fi
561
562	printf "Cleaning up temporary files... "
563	for package in $PACKAGES; do
564		# shellcheck disable=SC2086
565		rm -rf "build-${TARGETARCH}-$package" "build-$package" "$(eval echo \$$package"_DIR")"
566	done
567	rm -f getopt
568	printf "${green}ok${NC}\n"
569}
570
571myhelp()
572{
573	printf "Usage: $0 [-V] [-c] [-p <platform>] [-d <target directory>] [-D <dest dir>] [-C] [-G] [-S]\n"
574	printf "       $0 [-V|--version]\n"
575	printf "       $0 [-h|--help]\n\n"
576
577	printf "Options:\n"
578	printf "    [-W|--print-version           Print machine readable version\n"
579	printf "    [-V|--version]                print version number and exit\n"
580	printf "    [-h|--help]                   print this help and exit\n"
581	printf "    [-c|--clean]                  remove temporary files before build\n"
582	printf "    [-t|--savetemps]              don't remove temporary files after build\n"
583	printf "    [-y|--ccache]                 Use ccache when building cross compiler\n"
584	printf "    [-n|--nocolor]                don't print color codes in output\n"
585	printf "    [-u|--urls]                   print the urls for all packages\n"
586	printf "    [-j|--jobs <num>]             run <num> jobs in parallel in make\n"
587	printf "    [-s]--supported <tool>        print supported version of a tool\n"
588	printf "    [-d|--directory <target dir>] target directory to install cross compiler to\n"
589	printf "        (defaults to $TARGETDIR)\n\n"
590	printf "    [-D|--destdir <dest dir>]     destination directory to install cross compiler to\n"
591	printf "                                  (for RPM builds, default unset)\n"
592	printf "    [-f|--fetch]                  Download tarballs, but don't build anything\n"
593	printf "    [-P|--package <package>]      Build a specific package: GCC, CLANG, IASL\n"
594	printf "                                  (defaults to $PACKAGE)\n"
595	printf "GCC specific options:\n"
596	printf "    [-b|--bootstrap]              bootstrap the host compiler before building\n"
597	printf "                                  the cross compiler\n"
598	printf "    [-p|--platform <platform>]    target platform to build cross compiler for\n"
599	printf "                                  (defaults to $TARGETARCH)\n"
600	printf "    [-l|--languages <languages>]  comma separated list of target languages\n"
601	printf "                                  (defaults to $DEFAULT_LANGUAGES)\n"
602	printf "Platforms for GCC:\n"
603	printf "    x86_64 i386-elf i386-mingw32 riscv-elf arm aarch64\n"
604	printf "    powerpc64le-linux-gnu nds32le-elf\n\n"
605}
606
607printversion() {
608	printf "${blue}Welcome to the ${red}coreboot${blue} cross toolchain builder v$CROSSGCC_VERSION ${NC}\n\n"
609}
610
611myversion()
612{
613	printversion
614
615	cat << EOF
616Copyright (C) 2008-2010 by coresystems GmbH
617Copyright (C) 2011 by Sage Electronic Engineering
618
619This program is free software; you can redistribute it and/or modify
620it under the terms of the GNU General Public License as published by
621the Free Software Foundation; version 2 of the License.
622
623This program is distributed in the hope that it will be useful,
624but WITHOUT ANY WARRANTY; without even the implied warranty of
625MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
626GNU General Public License for more details.
627
628EOF
629}
630
631have_hostcflags_from_gmp() {
632	grep -q __GMP_CFLAGS "$DESTDIR$TARGETDIR/include/gmp.h" >/dev/null 2>&1
633}
634
635set_hostcflags_from_gmp() {
636	# Now set CFLAGS to match GMP CFLAGS but strip out -pedantic
637	# as GCC 4.6.x fails if it's there.
638	HOSTCFLAGS="$(grep __GMP_CFLAGS "$DESTDIR$TARGETDIR/include/gmp.h" |cut -d\" -f2 |\
639	    sed s,-pedantic,,)"
640	export HOSTCFLAGS
641}
642
643build_GMP() {
644	# Check if GCC enables `-pie` by default (possible since GCC 6).
645	# We need PIC in all static libraries then.
646	if $CC -dumpspecs 2>/dev/null | grep -q '[{;][[:space:]]*:-pie\>'
647	then
648		OPTIONS="$OPTIONS --with-pic"
649	fi
650
651	# shellcheck disable=SC2086
652	CC="$(hostcc host)" CXX="$(hostcxx host)" \
653	../${GMP_DIR}/configure \
654		--disable-shared \
655		--enable-fat \
656		--prefix="$TARGETDIR" \
657		$OPTIONS || touch .failed
658	# shellcheck disable=SC2086
659	$MAKE $JOBS || touch .failed
660	$MAKE install DESTDIR=$DESTDIR || touch .failed
661
662	normalize_dirs
663
664	set_hostcflags_from_gmp
665}
666
667build_MPFR() {
668	test "$UNAME" = "Darwin" && CFLAGS="$CFLAGS -force_cpusubtype_ALL"
669	CC="$(hostcc host)" CXX="$(hostcxx host)" \
670	../${MPFR_DIR}/configure \
671		--disable-shared \
672		--prefix="$TARGETDIR" \
673		--infodir="$TARGETDIR/info" \
674		--with-gmp="$DESTDIR$TARGETDIR" \
675		CFLAGS="$HOSTCFLAGS" || touch .failed
676	# shellcheck disable=SC2086
677	$MAKE $JOBS || touch .failed
678	$MAKE install DESTDIR=$DESTDIR || touch .failed
679
680	normalize_dirs
681
682	# work around build problem of libgmp.la
683	if [ "$DESTDIR" != "" ]; then
684	    perl -pi -e "s,$DESTDIR,," "$DESTDIR$TARGETDIR/lib/libgmp.la"
685	fi
686}
687
688build_MPC() {
689	CC="$(hostcc host)" CXX="$(hostcxx host)" \
690	../${MPC_DIR}/configure \
691		--disable-shared \
692		--prefix="$TARGETDIR" \
693		--infodir="$TARGETDIR/info" \
694		--with-mpfr="$DESTDIR$TARGETDIR" \
695		--with-gmp="$DESTDIR$TARGETDIR" \
696		CFLAGS="$HOSTCFLAGS" || touch .failed
697
698	# work around build problem of libmpfr.la
699	if [ "$DESTDIR" != "" ]; then
700	    perl -pi -e "s,$TARGETDIR/lib/libgmp.la,$DESTDIR\$&," "$DESTDIR$TARGETDIR/lib/libmpfr.la"
701	fi
702
703	# shellcheck disable=SC2086
704	$MAKE $JOBS || touch .failed
705	$MAKE install DESTDIR=$DESTDIR || touch .failed
706
707	# work around build problem of libmpfr.la
708	if [ "$DESTDIR" != "" ]; then
709	    perl -pi -e "s,$DESTDIR,," "$DESTDIR$TARGETDIR/lib/libmpfr.la"
710	fi
711
712	normalize_dirs
713}
714
715build_BINUTILS() {
716	if [ $TARGETARCH = "x86_64-elf" ]; then
717		ADDITIONALTARGET=",i386-elf"
718	fi
719	# shellcheck disable=SC2086
720	CC="$(hostcc target)" CXX="$(hostcxx target)" \
721	../binutils-${BINUTILS_VERSION}/configure \
722		--prefix="$TARGETDIR" \
723		--target=${TARGETARCH} \
724		--enable-targets=${TARGETARCH}${ADDITIONALTARGET} \
725		--disable-werror \
726		--disable-nls \
727		--enable-lto \
728		--enable-gold \
729		--enable-multilib \
730		--disable-docs \
731		--disable-texinfo \
732		${TARGET_BINUTILS_OPTIONS} \
733		CFLAGS="$HOSTCFLAGS" \
734		CXXFLAGS="$HOSTCFLAGS" || touch .failed
735	# shellcheck disable=SC2086
736	$MAKE $JOBS || touch .failed
737	$MAKE install DESTDIR=$DESTDIR || touch .failed
738}
739
740bootstrap_GCC() {
741	# shellcheck disable=SC2086
742	CC="$(hostcc host)" CXX="$(hostcxx host)" \
743		CFLAGS="$HOSTCFLAGS" \
744		CFLAGS_FOR_BUILD="$HOSTCFLAGS" \
745		CFLAGS_FOR_TARGET="$HOSTCFLAGS -fPIC" \
746		CXXFLAGS="$HOSTCFLAGS" \
747		CXXFLAGS_FOR_BUILD="$HOSTCFLAGS" \
748		CXXFLAGS_FOR_TARGET="$HOSTCFLAGS -fPIC" \
749		../gcc-${GCC_VERSION}/configure \
750		--prefix="$TARGETDIR" \
751		--libexecdir="$TARGETDIR/lib" \
752		--enable-bootstrap \
753		--disable-werror \
754		--disable-nls \
755		--disable-shared \
756		--disable-multilib \
757		--disable-libssp \
758		--disable-libquadmath \
759		--disable-libcc1 \
760		--disable-libsanitizer \
761		${GCC_OPTIONS} \
762		--enable-languages="${LANGUAGES}" \
763		--with-gmp="$DESTDIR$TARGETDIR" \
764		--with-mpfr="$DESTDIR$TARGETDIR" \
765		--with-mpc="$DESTDIR$TARGETDIR" \
766		--with-pkgversion="coreboot bootstrap v$CROSSGCC_VERSION" \
767		&& \
768	# shellcheck disable=SC2086
769	$MAKE $JOBS BOOT_CFLAGS="$HOSTCFLAGS" BUILD_CONFIG="" bootstrap && \
770	$MAKE	install-gcc \
771		install-target-libgcc \
772		maybe-install-target-libada \
773		maybe-install-target-libstdc++-v3 \
774		DESTDIR=$DESTDIR || touch .failed
775}
776
777build_cross_GCC() {
778	# Work around crazy code generator in GCC that confuses CLANG.
779	$CC --version | grep clang >/dev/null 2>&1 && \
780		CLANGFLAGS="-fbracket-depth=1024"
781	[ -n "$CXX" ] && $CXX --version | grep clang >/dev/null 2>&1 && \
782		CLANGCXXFLAGS="-fbracket-depth=1024"
783
784	# standard code model is medlow but all mainboards are compiled with medany code model
785	if [ "${TARGETARCH}" = "riscv64-elf" ]; then
786		CFLAGS_FOR_TARGET_EXTRA="-mcmodel=medany"
787	fi
788
789	# GCC does not honor HOSTCFLAGS at all. CFLAGS are used for
790	# both target and host object files.
791	# There's a work-around called CFLAGS_FOR_BUILD and CFLAGS_FOR_TARGET
792	# but it does not seem to work properly. At least the host library
793	# libiberty is not compiled with CFLAGS_FOR_BUILD.
794	# Also set the CXX version of the flags because GCC is now compiled
795	# using C++.
796	# shellcheck disable=SC2086
797	CC="$(hostcc target)" CXX="$(hostcxx target)" \
798		CFLAGS_FOR_TARGET="${CFLAGS_FOR_TARGET_EXTRA} -O2 -Dinhibit_libc" \
799		CFLAGS="$HOSTCFLAGS $CLANGFLAGS" \
800		CFLAGS_FOR_BUILD="$HOSTCFLAGS $CLANGFLAGS" \
801		CXXFLAGS="$HOSTCFLAGS $CLANGCXXFLAGS" \
802		CXXFLAGS_FOR_BUILD="$HOSTCFLAGS $CLANGCXXFLAGS" \
803		../gcc-${GCC_VERSION}/configure \
804		--prefix="$TARGETDIR" \
805		--libexecdir="$TARGETDIR/lib" \
806		--target=${TARGETARCH} \
807		--disable-werror \
808		--disable-shared \
809		--enable-lto \
810		--enable-plugins \
811		--enable-gold \
812		--enable-ld=default \
813		--disable-libssp \
814		--disable-bootstrap \
815		--disable-nls \
816		--disable-libquadmath \
817		--without-headers \
818		--disable-threads \
819		--enable-interwork \
820		--enable-multilib \
821		--enable-targets=all \
822		--disable-libatomic \
823		--disable-libcc1 \
824		--disable-decimal-float \
825		${GCC_OPTIONS} \
826		${TARGET_GCC_OPTIONS} \
827		--enable-languages="${LANGUAGES}" \
828		--with-system-zlib \
829		--with-gmp="$DESTDIR$TARGETDIR" \
830		--with-mpfr="$DESTDIR$TARGETDIR" \
831		--with-mpc="$DESTDIR$TARGETDIR" \
832		--with-gnu-as \
833		--with-gnu-ld \
834		--with-pkgversion="coreboot toolchain v$CROSSGCC_VERSION" \
835		&& \
836	mkdir -p gcc/$TARGETARCH && \
837	rm -f "gcc/$TARGETARCH/$GCC_VERSION" && \
838	ln -s "$DESTDIR$TARGETDIR/$TARGETARCH/bin" "gcc/$TARGETARCH/$GCC_VERSION" && \
839	$MAKE $JOBS CFLAGS_FOR_BUILD="$HOSTCFLAGS" all-gcc && \
840	$MAKE install-gcc DESTDIR="$DESTDIR" || touch .failed
841
842	if [ ! -f .failed ] && [ "$(echo $TARGETARCH | grep -c -- -mingw32)" -eq 0 ]; then
843		# shellcheck disable=SC2086
844		$MAKE $JOBS CFLAGS_FOR_BUILD="$HOSTCFLAGS" all-target-libgcc && \
845		$MAKE install-target-libgcc DESTDIR=$DESTDIR || touch .failed
846	fi
847}
848
849build_GCC() {
850	if [ "$1" = host ]; then
851		bootstrap_GCC "$1"
852	else
853		build_cross_GCC "$1"
854	fi
855}
856
857build_IASL() {
858	RDIR=$PWD
859	cd ../$IASL_DIR/generate/unix || exit 1
860	CFLAGS="$HOSTCFLAGS"
861	HOST="_LINUX"
862	test "$UNAME" = "Darwin" && HOST="_APPLE" && OPT_LDFLAGS="-Wl,-no_fixup_chains"
863	test "$UNAME" = "FreeBSD" && HOST="_FreeBSD"
864	test "$UNAME" = "Cygwin" && HOST="_CYGWIN"
865	HOST="$HOST" CFLAGS="$CFLAGS" \
866	OPT_LDFLAGS="$OPT_LDFLAGS" \
867	OPT_CFLAGS="-O -D_FORTIFY_SOURCE=2 -D COREBOOT_TOOLCHAIN_VERSION='\"coreboot toolchain v$CROSSGCC_VERSION\"' " \
868	$MAKE $JOBS CC="$(hostcc host)" iasl acpibin acpidump acpiexec acpihelp acpisrc acpixtract
869	mkdir -p "$DESTDIR$TARGETDIR/bin/"
870	(cd "$DESTDIR$TARGETDIR/bin" && rm -f iasl acpibin acpidump acpiexec acpihelp acpisrc acpixtract) || touch "$RDIR/.failed"
871	(cd bin && cp iasl acpibin acpidump acpiexec acpihelp acpisrc acpixtract "$DESTDIR$TARGETDIR/bin") || touch "$RDIR/.failed"
872}
873
874build_LLVM() {
875
876	ln -nsf "$LLD_DIR" ../lld
877	ln -nsf "$LLVM_DIR" ../llvm
878	ln -nsf "$CLANG_DIR" ../clang
879	ln -nsf "$CTE_DIR" ../clang-tools-extra
880	ln -nsf "$CRT_DIR" ../compiler-rt
881	ln -nsf "$LLVMCMAKE_DIR" ../cmake
882	ln -nsf "$LIBUNWIND_DIR" ../libunwind
883
884	$CMAKE -G "Unix Makefiles" \
885		-DCMAKE_INSTALL_PREFIX="$DESTDIR$TARGETDIR" \
886		-DCLANG_VENDOR="coreboot toolchain v$CROSSGCC_VERSION - " \
887		-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;compiler-rt;lld" \
888		-DLLVM_INCLUDE_BENCHMARKS="OFF" \
889		-DLLVM_INCLUDE_TESTS="OFF" \
890		-DLLVM_INCLUDE_EXAMPLES="OFF" \
891		-DCMAKE_BUILD_TYPE=Release \
892		-DLLVM_TARGETS_TO_BUILD="AArch64;ARM;PowerPC;RISCV;X86" \
893		../llvm || touch .failed
894	# shellcheck disable=SC2086
895	$MAKE $JOBS || touch .failed
896	$MAKE install || touch .failed
897
898	rm -f ../llvm ../clang ../clang-tools-extra ../compiler-rt ../cmake ../lld ../libunwind
899
900	cp -a ../$CLANG_DIR/tools/scan-build/* "$DESTDIR$TARGETDIR/bin"
901	cp -a ../$CLANG_DIR/tools/scan-view/* "$DESTDIR$TARGETDIR/bin"
902}
903
904build_CMAKE() {
905	CC="$(hostcc host)" CXX="$(hostcxx host)" CFLAGS="$HOSTCFLAGS" \
906	../${CMAKE_DIR}/configure \
907		--parallel=${THREADS} \
908		--prefix="$TARGETDIR" || touch .failed
909	# shellcheck disable=SC2086
910	$MAKE $JOBS || touch .failed
911	$MAKE install DESTDIR=$DESTDIR || touch .failed
912}
913
914build_NASM() {
915	CC="$(hostcc host)" CXX="$(hostcxx host)" CFLAGS="$HOSTCFLAGS" \
916	../${NASM_DIR}/configure \
917		--prefix="$TARGETDIR" || touch .failed
918	# shellcheck disable=SC2086
919	$MAKE $JOBS || touch .failed
920	$MAKE install DESTDIR=$DESTDIR || touch .failed
921
922	normalize_dirs
923}
924
925print_supported() {
926	case "$PRINTSUPPORTED" in
927		BINUTILS|binutils)  printf "%s\n" "$BINUTILS_VERSION";;
928		CLANG|clang)  printf "%s\n" "$CLANG_VERSION";;
929		GCC|gcc)  printf "%s\n" "$GCC_VERSION";;
930		GMP|gmp)   printf "%s\n" "$GMP_VERSION";;
931		IASL|iasl) printf "%s\n" "$IASL_VERSION";;
932		MPC|mpc)  printf "%s\n" "$MPC_VERSION";;
933		MPFR|mpfr)  printf "%s\n" "$MPFR_VERSION";;
934		NASM|nasm) printf "%s\n" "${NASM_VERSION}";;
935		*) printf "Unknown tool %s\n" "$PRINTSUPPORTED";;
936	esac
937}
938
939trap exit_handler 1 2 3 15
940
941# Look if we have getopt. If not, build it.
942export PATH=$PATH:.
943getopt - > /dev/null 2>/dev/null || gcc -o getopt getopt.c
944
945# parse parameters.. try to find out whether we're running GNU getopt
946getoptbrand="$(getopt -V 2>/dev/null | sed -e '1!d' -e 's,^\(......\).*,\1,')"
947if [ "${getoptbrand}" = "getopt" ]; then
948	# Detected GNU getopt that supports long options.
949	args=$(getopt -l print-version,version,help,clean,directory:,bootstrap,bootstrap-only,platform:,languages:,package:,jobs:,destdir:,savetemps,scripting,ccache,supported:,urls,nocolor,mirror,fetch -o WVhcd:bBp:l:P:j:D:tSys:unmf -- "$@")
950	getopt_ret=$?
951	eval set -- "$args"
952else
953	# Detected non-GNU getopt
954	args=$(getopt WVhcd:bBp:l:P:j:D:tSys:unm $*)
955	getopt_ret=$?
956	# shellcheck disable=SC2086
957	set -- $args
958fi
959
960if [ $getopt_ret != 0 ]; then
961	myhelp
962	exit 1
963fi
964
965while true ; do
966        case "$1" in
967		-W|--print-version)	shift; echo $CROSSGCC_VERSION; exit 0;;
968		-V|--version)		shift; myversion; exit 0;;
969		-h|--help)		shift; myhelp; exit 0;;
970		-c|--clean)		shift; clean=1;;
971		-t|--savetemps)		shift; SAVETEMPS=1;;
972		-d|--directory)		shift; TARGETDIR="$1"; shift;;
973		-b|--bootstrap)		shift; BOOTSTRAP=1;;
974		-B|--bootstrap-only)	shift; BOOTSTRAPONLY=1; BOOTSTRAP=1;;
975		-p|--platform)		shift; TARGETARCH="$1"; shift;;
976		-l|--languages)		shift; LANGUAGES="$1"; shift;;
977		-m|--mirror)		shift; USE_COREBOOT_MIRROR=1;;
978		-D|--destdir)		shift; DESTDIR="$1"; shift;;
979		-f|--fetch)		shift; FETCH_ONLY=1;;
980		-j|--jobs)		shift; THREADS="$1"; JOBS="-j $1"; shift;;
981		-P|--package)		shift; PACKAGE="$1"; shift;;
982		-y|--ccache)		shift; USECCACHE=1;;
983		-s|--supported)		shift; PRINTSUPPORTED="$1"; shift;;
984		-u|--urls)		shift; printf "%s\n" "$ALL_ARCHIVES"; exit 0;;
985		-n|--nocolor)		shift; \
986			unset red RED green GREEN blue BLUE cyan CYAN NC;;
987		--)		shift; break;;
988		*)		break;;
989	esac
990done
991
992if [ $# -gt 0 ]; then
993	printf "Excessive arguments: $*\n"
994	myhelp
995	exit 1
996fi
997
998if [ -n "$PRINTSUPPORTED" ]; then
999	print_supported
1000	exit 0
1001fi
1002
1003#print toolchain builder version string as the header
1004printversion
1005
1006printf "Building toolchain using %d thread(s).\n\n" "$THREADS"
1007
1008case "$TARGETARCH" in
1009	x86_64-elf)		;;
1010	x86_64*)		TARGETARCH=x86_64-elf;;
1011	i386-elf)		;;
1012	i386-mingw32)		;;
1013	riscv-elf)		TARGETARCH=riscv64-elf
1014				TARGET_GCC_OPTIONS="$TARGET_GCC_OPTIONS --with-isa-spec=20191213"
1015				TARGET_BINUTILS_OPTIONS="$TARGET_BINUTILS_OPTIONS --with-isa-spec=20191213";;
1016	powerpc64*-linux*)	;;
1017	i386*)			TARGETARCH=i386-elf;;
1018	arm*)			TARGETARCH=arm-eabi;;
1019	aarch64*)		TARGETARCH=aarch64-elf;;
1020	nds32le-elf)		;;
1021	*)			printf "${red}WARNING: Unsupported architecture $TARGETARCH.${NC}\n\n"; ;;
1022esac
1023
1024# Figure out which packages to build
1025
1026case "$PACKAGE" in
1027	GCC|gcc)
1028		echo "Target architecture is $TARGETARCH"
1029		NAME="${TARGETARCH} cross GCC"
1030		PACKAGES="GMP MPFR MPC BINUTILS GCC"
1031		;;
1032	CLANG|clang)
1033		NAME="LLVM clang"
1034		LLVM_VERSION=${CLANG_VERSION}
1035		PACKAGES="CMAKE LLVM CLANG CRT CTE LLVMCMAKE LLD LIBUNWIND"
1036		CMAKE=${DESTDIR}${TARGETDIR}/bin/cmake
1037		;;
1038	IASL|iasl)
1039		NAME="IASL ACPI compiler"
1040		PACKAGES=IASL
1041		;;
1042	CMAKE|cmake)
1043		NAME="CMake"
1044		PACKAGES=CMAKE
1045		;;
1046	NASM|nasm)
1047		NAME="NASM"
1048		PACKAGES=NASM
1049		;;
1050	*)
1051		printf "${red}ERROR: Unsupported package $PACKAGE. (Supported packages are GCC, CLANG, IASL, and NASM)${NC}\n\n";
1052		exit 1
1053		;;
1054esac
1055
1056# Find all the required tools:
1057
1058TAR=$(searchtool tar) || exit $?
1059PATCH=$(searchtool patch) || exit $?
1060MAKE=$(searchtool make) || exit $?
1061SHA1SUM=$(searchtool sha1sum)
1062#SHA512SUM=$(searchtool sha512sum)
1063#MD5SUM=$(searchtool md5sum)
1064CHECKSUM=$SHA1SUM
1065LBZIP2=$(searchtool lbzip2 "" nofail)
1066PIGZ=$(searchtool pigz "" nofail)
1067
1068searchtool m4 > /dev/null
1069searchtool bison > /dev/null
1070searchtool flex flex > /dev/null
1071searchtool bzip2 "bzip2," > /dev/null
1072searchtool xz "XZ Utils" "" "xz-utils" > /dev/null
1073
1074if searchtool wget "GNU" nofail > /dev/null; then
1075	download_showing_percentage() {
1076		url=$1
1077		printf "... ${red}  0%%"
1078		wget --tries=3 "$url" 2>&1 | while read -r line; do
1079			echo "$line" | grep -o "\<[0-9]\{1,3\}%" | awk '{printf("\b\b\b\b%4s", $1)}'
1080		done
1081		printf "${NC}... "
1082	}
1083elif searchtool curl "^curl " > /dev/null; then
1084	download_showing_percentage() {
1085		url=$1
1086		echo
1087		curl -O --progress-bar --location --retry 3 "$url"
1088	}
1089fi
1090
1091# Allow $CC override from the environment.
1092if [ -n "$CC" ]; then
1093	if [ ! -x "$(command -v "$CC" 2>/dev/null)" ]; then
1094		printf "${RED}ERROR:${red} CC is set to '%s' but wasn't found.${NC}\n" "$CC"
1095		HALT_FOR_TOOLS=1
1096	fi
1097else
1098	if searchtool gnatgcc "Free Software Foundation" nofail > /dev/null; then
1099		# gnatgcc is deprecated and in recent GCC releases its purpose is
1100		# fulfilled by the gcc binary. In case of a deprecated gnatgcc
1101		# version is installed, it doesn't provide the expected output and
1102		# hostcc_has_gnat1() fails. In this case, just set the value of CC
1103		# to gcc.
1104		# TODO: Remove this whole branch when time is appropriate as the
1105		#       second branch fulfills our needs.
1106		CC=gnatgcc
1107		if ! hostcc_has_gnat1; then
1108			CC=gcc
1109		fi
1110	elif searchtool gcc "Free Software Foundation" nofail > /dev/null; then
1111		CC=gcc
1112	else
1113		searchtool cc '^' nofail > /dev/null || please_install gcc
1114		CC=cc
1115	fi
1116fi
1117
1118# We can leave $CXX empty if it's not set since *buildgcc* never
1119# calls it directly. This way configure scripts can search for
1120# themselves and we still override it when a bootstrapped g++ is
1121# to be used (cf. hostcxx()).
1122if [ -n "$CXX" ]; then
1123	if [ ! -x "$(command -v "$CXX" 2>/dev/null)" ]; then
1124		printf "${RED}ERROR:${red} CXX is set to '%s' but wasn't found.${NC}\n" "$CXX"
1125		HALT_FOR_TOOLS=1
1126	fi
1127else
1128	searchtool g++ "Free Software Foundation" nofail > /dev/null || \
1129	searchtool clang "clang version" nofail > /dev/null || \
1130	searchtool clang "LLVM" "" "g++" > /dev/null
1131fi
1132
1133check_for_library "-lz" "zlib (zlib1g-dev or zlib-devel)"
1134
1135if [ "$HALT_FOR_TOOLS" -ne 0 ]; then
1136	exit 1
1137fi
1138
1139# This initial cleanup is useful when updating the toolchain script.
1140
1141if [ "$clean" = "1" ]; then
1142	cleanup
1143fi
1144
1145# Set up host compiler and flags needed for various OSes
1146
1147if is_package_enabled "GCC"; then
1148# sane preset: let the configure script figure out things by itself
1149# more importantly, avoid any values that might already linger in the variable
1150OPTIONS="ABI="
1151if [ "$UNAME" = "Darwin" ]; then
1152	#GCC_OPTIONS="$GCC_OPTIONS --enable-threads=posix"
1153
1154	# generally the OS X compiler can create x64 binaries.
1155	# Per default it generated i386 binaries in 10.5 and x64
1156	# binaries in 10.6 (even if the kernel is 32bit)
1157	# For some weird reason, 10.5 autodetects an ABI=64 though
1158	# so we're setting the ABI explicitly here.
1159	if [ "$(sysctl -n hw.optional.x86_64 2>/dev/null)" -eq 1 ] 2>/dev/null; then
1160		OPTIONS="ABI=64"
1161	elif [ "$(sysctl -n hw.optional.arm64 2>/dev/null)" -eq 1 ] 2>/dev/null; then
1162		OPTIONS="ABI=64"
1163	else
1164		OPTIONS="ABI=32"
1165	fi
1166
1167	# In Xcode 4.5.2 the default compiler is clang.
1168	# However, this compiler fails to compile gcc 4.7.x. As a
1169	# workaround it's possible to compile gcc with llvm-gcc.
1170	if $CC -v 2>&1 | grep -q LLVM; then
1171		CC=llvm-gcc
1172	fi
1173elif [ "$UNAME" = "Linux" ] || [ "$UNAME" = "Cygwin" ]; then
1174	# gmp is overeager with detecting 64bit CPUs even if they run
1175	# a 32bit kernel and userland.
1176	if [ "$(uname -m 2>/dev/null)" = "i686" ]; then
1177		OPTIONS="ABI=32"
1178	fi
1179elif [ "$UNAME" = "NetBSD" ]; then
1180	# same for NetBSD but this one reports an i386
1181	if [ "$(uname -m 2>/dev/null)" = "i386" ]; then
1182		OPTIONS="ABI=32"
1183	fi
1184fi
1185if [ -z "${LANGUAGES}" ]; then
1186	if have_gnat; then
1187		printf "\nFound compatible Ada compiler, enabling Ada support by default.\n\n"
1188		LANGUAGES="ada,${DEFAULT_LANGUAGES}"
1189	else
1190		printf "\n${red}WARNING${NC}\n"
1191		printf "No compatible Ada compiler (GNAT) found. You can continue without\n"
1192		printf "Ada support, but this will limit the features of ${blue}coreboot${NC} (e.g.\n"
1193		printf "native graphics initialization won't be available on most Intel\n"
1194		printf "boards).\n\n"
1195
1196		printf "Usually, you can install GNAT with your package management system\n"
1197		printf "(the package is called \`gnat\` or \`gcc-ada\`). It has to match the\n"
1198		printf "\`gcc\` package in version. If there are multiple versions of GCC in-\n"
1199		printf "stalled, you can point this script to the matching version through\n"
1200		printf "the \`CC\` and \`CXX\` environment variables.\n\n"
1201
1202		printf "e.g. on Ubuntu 14.04, if \`gcc\` is \`gcc-4.8\`:\n"
1203		printf "    apt-get install gnat-4.8 && make crossgcc\n\n"
1204
1205		printf "on Ubuntu 16.04, if \`gcc\` is \`gcc-5\`:\n"
1206		printf "    apt-get install gnat-5 && make crossgcc\n"
1207		timeout 30
1208		LANGUAGES="${DEFAULT_LANGUAGES}"
1209	fi
1210fi
1211if [ "$BOOTSTRAP" != 1 ] && \
1212	{ [ "$(hostcc_major)" -lt 4 ] || \
1213	{ [ "$(hostcc_major)" -eq 4 ] && \
1214	[ "$(hostcc_minor)" -lt 9 ] ; } ; }
1215then
1216	printf "\n${red}WARNING${NC}\n"
1217	printf "Building coreboot requires a host compiler newer than 4.9.x while\n"
1218	printf "yours is $(hostcc_version).\n"
1219	printf "Enabling bootstrapping to provide a sufficiently new compiler:\n"
1220	printf "This will take significantly longer than a usual build.\n"
1221	printf "Alternatively you can abort now and update your host compiler.\n"
1222	timeout 15
1223	BOOTSTRAP=1
1224fi
1225if ada_requested; then
1226	if ! have_gnat; then
1227		please_install gnat gcc-ada
1228		exit 1
1229	fi
1230fi
1231fi # GCC
1232
1233export HOSTCFLAGS="-Os"
1234if have_hostcflags_from_gmp; then
1235	set_hostcflags_from_gmp
1236fi
1237
1238if [ "$USECCACHE" = 1 ]; then
1239	CC="ccache $CC"
1240fi
1241
1242# Prepare target directory for building GCC
1243# (dependencies must be in the PATH)
1244mkdir -p "$DESTDIR$TARGETDIR/bin"
1245mkdir -p "$DESTDIR$TARGETDIR/share"
1246export PATH=$DESTDIR$TARGETDIR/bin:$PATH
1247
1248# Download, unpack, patch and build all packages
1249
1250printf "Downloading and verifying tarballs ...\n"
1251mkdir -p tarballs
1252for P in $PACKAGES; do
1253	download "$P" || exit "$?"
1254	verify_hash "$P" || exit "$?"
1255done
1256printf "Downloaded tarballs ... ${green}ok${NC}\n"
1257
1258if [ ${FETCH_ONLY} -eq 1 ]; then
1259	exit 0
1260fi
1261
1262printf "Unpacking and patching ...\n"
1263for P in $PACKAGES; do
1264	unpack_and_patch $P || exit 1
1265done
1266printf "Unpacked and patched ... ${green}ok${NC}\n"
1267
1268if [ -n "$BOOTSTRAPONLY" ]; then
1269	printf "Building bootstrap compiler only ...\n"
1270	for pkg in GMP MPFR MPC GCC; do
1271		build_for_host $pkg
1272	done
1273	exit 0
1274fi
1275
1276printf "Building packages ...\n"
1277for package in $PACKAGES; do
1278	build $package
1279done
1280printf "Packages built ... ${green}ok${NC}\n"
1281
1282# Adding git information of current tree to target directory
1283# for reproducibility
1284PROGNAME=$(basename "$0")
1285rm -f "$DESTDIR$TARGETDIR/share/$PROGNAME-*"
1286cp "$PROGNAME" "$DESTDIR$TARGETDIR/share/$PROGNAME-$CROSSGCC_VERSION"
1287
1288# Adding edk2 tools template
1289mkdir -p "$DESTDIR$TARGETDIR/share/edk2config"
1290sed -e "s,@@PREFIX@@,$TARGETDIR,g" edk2tools.txt > "$DESTDIR$TARGETDIR/share/edk2config/tools_def.txt"
1291printf "Copied EDK2 tools template ... ${green}ok${NC}\n"
1292
1293cleanup
1294
1295printf "\n${green}You can now run $NAME from $TARGETDIR.${NC}\n"
1296