blob: 5ca4fc8fefcb2cb863cec4fdd39e5cdcb58575cd [file] [log] [blame]
George Burgess IV33581f72019-01-23 13:26:47 -08001#!/bin/bash
2#
3# Copyright (C) 2010 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18# This script is used to rebuild the Linux 32-bit cross-toolchain
19# that allows you to generate 32-bit binaries that target Ubuntu 8.04
20# (a.k.a. Hardy Heron) instead of the host system (which usually is 10.04,
21# a.k.a. Lucid Lynx)
22#
23# Use --help for complete usage information.
24#
25# WARNING: At this time, the generated toolchain binaries will *not* run
26# with GLibc 2.15, only the machine code it generates.
27#
28
29PROGNAME="`basename \"$0\"`"
30PATCHES_DIR="$( cd "$( dirname "$0" )" && pwd )/toolchain-patches"
31SYSROOT_PATCHES_DIR="$( cd "$( dirname "$0" )" && pwd )/sysroot-patches"
32
33###########################################################################
34###########################################################################
35#####
36##### C O N F I G U R A T I O N
37#####
38###########################################################################
39###########################################################################
40
41panic ()
42{
43 echo "ERROR: $@"
44 exit 1
45}
46
47fail_panic ()
48{
49 if [ $? != 0 ] ; then
50 echo "ERROR: $@"
51 exit 1
52 fi
53}
54
55
56# We only support running this script on Linux
57OS=$(uname -s)
58if [ "$OS" != Linux ]; then
59 panic "This script can only run on Linux machines!"
60fi
61
62UBUNTU_ARCHS="i386 amd64"
63
64# Used to set the host bitness of the generted toolchain binaries
65# First call with the build machine's bitness, and later with 32
66# if --32-bits option is used.
67# $1: 32 or 64
68set_host_bits ()
69{
70 HOST_BITS=$1
71 GMP_ABI=$1
72 case $1 in
73 32)
74 HOST_ARCH=i686
75 GCC_TARGET=i686-linux
76 GMP_TARGET=i386-linux
77 ;;
78 64)
79 HOST_ARCH=x86_64
80 GCC_TARGET=x86_64-linux
81 GMP_TARGET=x86_64-linux
82 ;;
83 *)
84 panic "Invalid host bitness (32 or 64 expected): $1"
85 esac
86}
87
88# Determine build machine bitness
89BUILD_ARCH=$(uname -m)
90case "$BUILD_ARCH" in
91 x86_64|amd64)
92 BUILD_BITS=64
93 BUILD_ARCH=x86_64
94 BUILD_GCC_TARGET=x86_64-linux
95 set_host_bits 64
96 ;;
97 i?86)
98 BUILD_BITS=32
99 BUILD_ARCH=i686
100 BUILD_GCC_TARGET=i686-linux
101 set_host_bits 32
102 ;;
103 *)
104 panic "Unknown build CPU architecture: $BUILD_ARCH"
105esac
106
107# Versions of various toolchain components, do not touch unless you know
108# what you're doing!
109
110BINUTILS_VERSION=2.27
111GMP_VERSION=5.0.5
112MPFR_VERSION=3.1.1
113MPC_VERSION=1.0.1
114GCC_VERSION=4.8.3
115CLOOG_VERSION=0.18.0
116ISL_VERSION=0.11.1
117
118GLIBC_VERSION=2.17
119
120GIT_CMD=git
121GIT_DATE=
122GIT_BRANCH=master
123GIT_REFERENCE=
124GIT_BASE=
125GIT_BASE_DEFAULT=https://android.googlesource.com/toolchain
126
127# Location where we're going to install the toolchain during the build
128# This will depend on the phase of the build.
129install_dir () { echo "$WORK_DIR/$PHASE/$TOOLCHAIN_NAME"; }
130
131# Given an input string that looks like <major>.<minor>.<patch>
132# Return <major>.<minor> only.
133major_minor_only () {
134 local MAJOR=$(echo -n "$1" | cut -f1 -d.)
135 local MINOR=$(echo -n "$1" | cut -f2 -d.)
136 echo "$MAJOR.$MINOR"
137}
138
139# Location where we're going to install the final binaries
140# If empty, TOOLCHAIN_ARCHIVE will be generated
141PREFIX_DIR=
142
143# Location of the final sysroot. This must be a sub-directory of INSTALL_DIR
144# to ensure that the toolchain binaries are properly relocatable (i.e. can
145# be used when moved to another directory).
146sysroot_dir () { echo "$(install_dir)/sysroot"; }
147
148# Try to parallelize the build for faster performance.
149JOBS=$(cat /proc/cpuinfo | grep -c processor)
150
151# The base URL of the Ubuntu mirror we're going to use.
152UBUNTU_MIRROR=http://old-releases.ubuntu.com/
153
154# Ubuntu release name we want packages from. Can be a name or a number
155# (i.e. "precise" or "12.04")
156UBUNTU_RELEASE=raring
157
158
159# The list of packages we need to download from the Ubuntu servers and
160# extract into the original sysroot
161#
162# Call add_ubuntu_package <package-name> to add a package to the list,
163# which will be processed later.
164#
165UBUNTU_PACKAGES=
166
167add_ubuntu_package ()
168{
169 UBUNTU_PACKAGES="$UBUNTU_PACKAGES $@"
170}
171
172# The package files containing kernel headers for Hardy and the C
173# library headers and binaries
174add_ubuntu_package \
175 linux-libc-dev \
176 libc6 \
177 libc6-dev \
178 libcap2 \
179 libcap-dev \
180 libattr1 \
181 libattr1-dev \
182 libacl1 \
183 libacl1-dev \
184
185# The X11 headers and binaries (for the emulator)
186add_ubuntu_package \
187 libx11-6 \
188 libx11-dev \
189 libxau6 \
190 libxcb1-dev \
191 libxdmcp6 \
192 libxext-dev \
193 libxfixes-dev \
194 libxi-dev \
195 x11proto-core-dev \
196 x11proto-fixes-dev \
197 x11proto-xext-dev \
198 x11proto-input-dev \
199 x11proto-kb-dev
200
201# The OpenGL-related headers and libraries (for GLES emulation)
202add_ubuntu_package \
203 mesa-common-dev \
204 libgl1-mesa-dev \
205 libgl1-mesa-glx \
206 libxxf86vm1 \
207 libxext6 \
208 libxdamage1 \
209 libxfixes3 \
210 libdrm2
211
212# Audio libraries (required by the emulator)
213add_ubuntu_package \
214 libasound2 \
215 libasound2-dev \
216 libesd0-dev \
217 libaudiofile-dev \
218 libpulse0 \
219 libpulse-dev
220
221# ZLib and others.
222add_ubuntu_package \
223 zlib1g \
224 zlib1g-dev \
225 libncurses5 \
226 libncurses5-dev \
227 libtinfo5 \
228 libtinfo-dev
229
230
231
232###########################################################################
233###########################################################################
234#####
235##### E N D O F C O N F I G U R A T I O N
236#####
237###########################################################################
238###########################################################################
239
240# Parse all options
241OPTION_HELP=no
242VERBOSE=0
243FORCE=no
244ONLY_SYSROOT=no
245ONLY_TOOLCHAIN_DIR=
246BOOTSTRAP=
247PARAMETERS=
248FORCE_32=
249LIST_TASKS=
250
251for opt do
252 optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
253 case $opt in
254 --help|-h|-\?) OPTION_HELP=yes
255 ;;
256 --verbose) VERBOSE=$(( $VERBOSE + 1 ))
257 ;;
258 --force) FORCE="yes"
259 ;;
260 --32-bits) FORCE_32=true
261 ;;
262 --ubuntu-mirror=*) UBUNTU_MIRROR=$optarg
263 ;;
264 --ubuntu-release=*) UBUNTU_RELEASE=$optarg
265 ;;
266 --prefix=*) PREFIX_DIR=$optarg
267 ;;
268 --work-dir=*) WORK_DIR=$optarg
269 ;;
270 --gcc-version=*) GCC_VERSION=$optarg
271 ;;
272 --binutils-version=*) BINUTILS_VERSION=$optarg
273 ;;
274 --gmp-version=*) GMP_VERSION=$optarg
275 ;;
276 --mpfr-version=*) MPFR_VERSION=$optarg
277 ;;
278 --mpc-version=*) MPC_VERSION=$optarg
279 ;;
280 --isl-version=*) ISL_VERSION=$optarg
281 ;;
282 --cloog-version=*) CLOOG_VERSION=$oparg
283 ;;
284 --git=*) GIT_CMD=$optarg
285 ;;
286 --git-date=*) GIT_DATE=$optarg
287 ;;
288 --git-branch=*) GIT_BRANCH=$optarg
289 ;;
290 --git-base=*) GIT_BASE=$optarg
291 ;;
292 --git-reference=*) GIT_REFERENCE=$optarg
293 ;;
294 --out-dir=*) OPTION_OUT_DIR=$optarg
295 ;;
296 --cc=*) OPTION_CC=$optarg
297 ;;
298 --jobs=*) JOBS=$optarg
299 ;;
300 -j*) JOBS=${opt#-j}
301 ;;
302 --only-sysroot) ONLY_SYSROOT=yes
303 ;;
304 --bootstrap) BOOTSTRAP=yes
305 ;;
306 --list-tasks) LIST_TASKS=yes
307 ;;
308 -*)
309 echo "unknown option '$opt', use --help"
310 exit 1
311 ;;
312 *)
313 if [ -z "$PARAMETERS" ]; then
314 PARAMETERS=$opt
315 else
316 PARAMETERS="$PARAMETERS $opt"
317 fi
318 esac
319done
320
321if [ "$OPTION_HELP" = "yes" ]; then
322 cat << EOF
323
324Usage: $PROGNAME [options] [<path-to-toolchain-sources>]
325
326This script is used to rebuild a custom Linux host toolchain that targets
327GLibc $GLIBC_VERSION or higher. The machine code generated by this toolchain
328will run properly on Ubuntu $UBUNTU_RELEASE or higher.
329
330If you're running on a 32-bit system, it will generate a 32-bit toolchain.
331If you're running on a 64-bit system, it will generate a 64-bit toolchain
332unless you use the --32-bits option.
333
334You can provide the path to a local copy of the toolchain sources repository
335as a first parameter. If you don't, the sources will be downloaded and
336extracted automatically into your work directory.
337
338Note that this script will download various binary packages from Ubuntu
339servers in order to prepare a compatible "sysroot".
340
341By default, it generates a package archive ($TOOLCHAIN_ARCHIVE) but you can,
342as an alternative, ask for direct installation with --prefix=<path>
343
344Use the bootstrap option to re-generate the toolchain with itself. This is
345useful if you want to ensure that the generated compiler binaries will work
346properly on Ubuntu 8.04 or higher. By default, they will only run on systems
347that match your build system's C library ABI, or higher.
348
349Options: [defaults in brackets after descriptions]
350EOF
351 echo "Standard options:"
352 echo " --help Print this message"
353 echo " --force Force-rebuild everything"
354 echo " --prefix=PATH Installation path [$PREFIX_DIR]"
355 echo " --ubuntu-mirror=URL Ubuntu mirror URL [$UBUNTU_MIRROR]"
356 echo " --ubuntu-release=NAME Ubuntu release name [$UBUNTU_RELEASE]"
357 echo " --work-dir=PATH Temporary work directory [/tmp/gcc.<random>]"
358 echo " --only-sysroot Only download and build sysroot packages"
359 echo " --verbose Verbose output. Can be used twice."
360 echo " --binutils-version=VERSION Binutils version number [$BINUTILS_VERSION]"
361 echo " --gcc-version=VERSION GCC version number [$GCC_VERSION]"
362 echo " --gmp-version=VERSION GMP version number [$GMP_VERSION]"
363 echo " --mpfr-version=VERSION MPFR version numner [$MPFR_VERSION]"
364 echo " --mpc-version=VERSION MPC version number [$MPC_VERSION]"
365 echo " --isl-version=VERSION ISL version number [$ISL_VERSION]"
366 echo " --cloog-version=VERSION Cloog version number [$CLOOG_VERSION]"
367 echo " --jobs=COUNT Run COUNT build jobs in parallel [$JOBS]"
368 echo " -j<COUNT> Same as --jobs=COUNT."
369 echo " --git=<cmd> Use this version of the git tool [$GIT_CMD]"
370 echo " --git-date=<date> Specify specific git date when download sources [none]"
371 echo " --git-branch=<name> Specify which branch to use when downloading the sources [$GIT_BRANCH]"
372 echo " --git-reference=<path> Use a git reference repository"
373 echo " --git-base=<url> Use this git repository base [$GIT_BASE]"
374 echo " --bootstrap Bootstrap toolchain (i.e. compile it with itself)"
375 echo " --32-bits Generate 32-bit toolchain on 64-bit build system."
376 echo ""
377 exit 1
378fi
379
380if [ "$FORCE_32" ]; then
381 if [ "$BUILD_BITS" = 64 ]; then
382 set_host_bits 32
383 else
384 echo "Warning: --32-bits option ignored on 32-bit build machine."
385 fi
386fi
387
388# Determine root working directory for our script
389if [ -z "$WORK_DIR" ]; then
390 WORK_DIR=$(mktemp -d /tmp/$USER-gcc-$HOST_BITS-XXXXXX)
391 WORK_DIR_CLEANUP=true
392else
393 mkdir -p "$WORK_DIR"
394 fail_panic "Could not create directory: $WORK_DIR"
395 WORK_DIR_CLEANUP=false
396fi
397
398if [ -z "$PARAMETERS" ] ; then
399 if [ -n "$GIT_REFERENCE" ] ; then
400 if [ ! -d "$GIT_REFERENCE" -o ! -d "$GIT_REFERENCE/build" ]; then
401 echo "ERROR: Invalid reference repository directory path: $GIT_REFERENCE"
402 exit 1
403 fi
404 if [ -n "$GIT_BASE" ]; then
405 echo "Using git clone reference: $GIT_REFERENCE"
406 else
407 # If we have a reference without a base, use it as a download base instead.
408 GIT_BASE=$GIT_REFERENCE
409 GIT_REFERENCE=
410 echo "Using git clone base: $GIT_BASE"
411 fi
412 elif [ -z "$GIT_BASE" ]; then
413 GIT_BASE=$GIT_BASE_DEFAULT
414 echo "Auto-config: --git-base=$GIT_BASE"
415 fi
416
417 # Location where we will download the toolchain sources
418 TOOLCHAIN_SRC_DIR=$WORK_DIR/toolchain-src
419else
420 set_parameters () {
421 TOOLCHAIN_SRC_DIR="$1"
422 if [ ! -d "$TOOLCHAIN_SRC_DIR" ]; then
423 echo "ERROR: Not a directory: $1"
424 exit 1
425 fi
426 if [ ! -d "$TOOLCHAIN_SRC_DIR/build" ]; then
427 echo "ERROR: Missing directory: $1/build"
428 exit 1
429 fi
430 }
431
432 set_parameters $PARAMETERS
433fi
434
435# Location of original sysroot. This is where we're going to extract all
436# binary Ubuntu packages.
437ORG_SYSROOT_DIR=$WORK_DIR/sysroot
438
439# Name of the final generated toolchain
440TOOLCHAIN_NAME=$GCC_TARGET-glibc$GLIBC_VERSION-$(major_minor_only $GCC_VERSION)
441
442# Name of the final toolchain binary tarball that this script will create
443TOOLCHAIN_ARCHIVE=/tmp/$TOOLCHAIN_NAME.tar.bz2
444
445# A file that will contain details about all the sources used to generate
446# the final toolchain. This includes both SHA-1 for toolchain git repositories
447# and SHA-1 hashes for downloaded Ubuntu packages.
448SOURCES_LIST=$WORK_DIR/SOURCES
449
450# Determine Make flags
451MAKE_FLAGS="-j$JOBS"
452
453# Create the work directory
454mkdir -p "$WORK_DIR"
455mkdir -p "$TOOLCHAIN_SRC_DIR"
456
457# Location where we download packages from the Ubuntu servers
458DOWNLOAD_DIR=$WORK_DIR/download
459
460# Empty the SOURCES file
461rm -f "$SOURCES_LIST" && touch "$SOURCES_LIST"
462
463
464if [ "$VERBOSE" -ge 1 ] ; then
465 run () {
466 echo "## COMMAND: $@"
467 "$@"
468 }
469 log () {
470 echo "$@"
471 }
472 if [ "$VERBOSE" -ge 2 ] ; then
473 log2 () {
474 echo "$@"
475 }
476 else
477 log2 () {
478 return
479 }
480 fi
481else
482 run () {
483 "$@" >>$TMPLOG 2>&1
484 }
485 log () {
486 return
487 }
488 log2 () {
489 return
490 }
491fi
492
493# Sanitize a path list, we want to remove empty sub-dirs and
494# leading/trailing columns.
495sanitize_path_list ()
496{
497 local RESULT
498 RESULT=$(printf "%s\n" "$*" | tr ':' '\n' | awk '$1 != "" && $1 != "." { print $0; }' | tr '\n' ':')
499 printf "%s" ${RESULT%:}
500}
501
502PATH=$(sanitize_path_list $PATH)
503LD_LIBRARY_PATH=$(sanitize_path_list $LD_LIBRARY_PATH)
504
505BUILD_DIR=$WORK_DIR/build
506mkdir -p $BUILD_DIR
507
508TMPLOG=$BUILD_DIR/build.log
509rm -rf $TMPLOG && touch $TMPLOG
510
511build_dir_for () { echo "$BUILD_DIR/$PHASE/$1"; }
512
513TIMESTAMPS_DIR=$BUILD_DIR/timestamps
514mkdir -p $TIMESTAMPS_DIR
515
516stamp_check () {
517 [ -f "$TIMESTAMPS_DIR/$1" ]
518}
519
520stamp_clear () {
521 rm -f "$TIMESTAMPS_DIR/$1"
522}
523
524stamp_set () {
525 touch "$TIMESTAMPS_DIR/$1"
526}
527
528if [ "$FORCE" = "yes" ] ; then
529 echo "Cleaning up timestamps (forcing the build)."
530 rm -f $TIMESTAMPS_DIR/*
531fi
532
533if [ "$VERBOSE" = 0 ] ; then
534 echo "To follow build, run: tail -F $TMPLOG"
535fi
536
537# returns 0 iff the string in $2 matches the pattern in $1
538# $1: pattern
539# $2: string
540pattern_match ()
541{
542 echo "$2" | grep -q -E -e "$1"
543}
544
545# Find if a given shell program is available.
546# We need to take care of the fact that the 'which <foo>' command
547# may return either an empty string (Linux) or something like
548# "no <foo> in ..." (Darwin). Also, we need to redirect stderr
549# to /dev/null for Cygwin
550#
551# $1: variable name
552# $2: program name
553#
554# Result: set $1 to the full path of the corresponding command
555# or to the empty/undefined string if not available
556#
557find_program ()
558{
559 local PROG
560 PROG=`which $2 2>/dev/null`
561 if [ -n "$PROG" ] ; then
562 if pattern_match '^no ' "$PROG"; then
563 PROG=
564 fi
565 fi
566 eval $1="$PROG"
567}
568
569# Copy a directory, create target location if needed
570#
571# $1: source directory
572# $2: target directory location
573#
574copy_directory ()
575{
576 local SRCDIR="$1"
577 local DSTDIR="$2"
578 if [ ! -d "$SRCDIR" ] ; then
579 panic "Can't copy from non-directory: $SRCDIR"
580 fi
581 log2 "Directory copy: $SRCDIR -> $DSTDIR"
582 mkdir -p "$DSTDIR" && (cd "$SRCDIR" && tar cf - *) | (tar xf - -C "$DSTDIR")
583 fail_panic "Cannot copy to directory: $DSTDIR"
584}
585
586find_program CMD_WGET wget
587find_program CMD_CURL curl
588find_program CMD_SCP scp
589
590# Download a file with either 'curl', 'wget' or 'scp'
591#
592# $1: source URL (e.g. http://foo.com, ssh://blah, /some/path)
593# $2: target file
594download_file ()
595{
596 # Is this HTTP, HTTPS or FTP ?
597 if pattern_match "^(http|https|ftp):.*" "$1"; then
598 if [ -n "$CMD_WGET" ] ; then
599 run $CMD_WGET -O $2 $1
600 elif [ -n "$CMD_CURL" ] ; then
601 run $CMD_CURL -o $2 $1
602 else
603 echo "Please install wget or curl on this machine"
604 exit 1
605 fi
606 return
607 fi
608
609 # Is this SSH ?
610 # Accept both ssh://<path> or <machine>:<path>
611 #
612 if pattern_match "^(ssh|[^:]+):.*" "$1"; then
613 if [ -n "$CMD_SCP" ] ; then
614 scp_src=`echo $1 | sed -e s%ssh://%%g`
615 run $CMD_SCP $scp_src $2
616 else
617 echo "Please install scp on this machine"
618 exit 1
619 fi
620 return
621 fi
622
623 # Is this a file copy ?
624 # Accept both file://<path> or /<path>
625 #
626 if pattern_match "^(file://|/).*" "$1"; then
627 cp_src=`echo $1 | sed -e s%^file://%%g`
628 run cp -f $cp_src $2
629 return
630 fi
631
632 # Unknown schema
633 echo "ERROR: Unsupported source URI: $1"
634 exit 1
635}
636
637# A variant of 'download_file' used to specify the target directory
638# $1: source URL
639# $2: target directory
640download_file_to ()
641{
642 local URL="$1"
643 local DIR="$2"
644 local DST="$DIR/`basename $URL`"
645 mkdir -p $DIR
646 download_file "$URL" "$DST"
647}
648
649# Pack a given archive
650#
651# $1: archive file path (including extension)
652# $2: source directory for archive content
653# $3+: list of files (including patterns), all if empty
654pack_archive ()
655{
656 local ARCHIVE="$1"
657 local SRCDIR="$2"
658 local SRCFILES
659 local TARFLAGS ZIPFLAGS
660 shift; shift;
661 if [ -z "$1" ] ; then
662 SRCFILES="*"
663 else
664 SRCFILES="$@"
665 fi
666 if [ "`basename $ARCHIVE`" = "$ARCHIVE" ] ; then
667 ARCHIVE="`pwd`/$ARCHIVE"
668 fi
669 mkdir -p `dirname $ARCHIVE`
670 if [ "$VERBOSE" -ge 2 ] ; then
671 TARFLAGS="vcf"
672 ZIPFLAGS="-9r"
673 else
674 TARFLAGS="cf"
675 ZIPFLAGS="-9qr"
676 fi
677 case "$ARCHIVE" in
678 *.zip)
679 (cd $SRCDIR && run zip $ZIPFLAGS "$ARCHIVE" $SRCFILES)
680 ;;
681 *.tar)
682 (cd $SRCDIR && run tar $TARFLAGS "$ARCHIVE" $SRCFILES)
683 ;;
684 *.tar.gz)
685 (cd $SRCDIR && run tar z$TARFLAGS "$ARCHIVE" $SRCFILES)
686 ;;
687 *.tar.bz2)
688 (cd $SRCDIR && run tar j$TARFLAGS "$ARCHIVE" $SRCFILES)
689 ;;
690 *)
691 panic "Unsupported archive format: $ARCHIVE"
692 ;;
693 esac
694}
695
696no_trailing_slash ()
697{
698 echo ${1##/}
699}
700
701# Load the Ubuntu packages file. This is a long text file that will list
702# each package for a given release.
703#
704# $1: Ubuntu mirror base URL (e.g. http://mirrors.us.kernel.org/)
705# $2: Release name
706#
707get_ubuntu_packages_list ()
708{
709 local RELEASE=$2
710 local BASE="`no_trailing_slash \"$1\"`"
711 local SRCFILE DSTFILE
712 for UA in $UBUNTU_ARCHS; do
713 SRCFILE="$BASE/ubuntu/dists/$RELEASE/main/binary-$UA/Packages.bz2"
714 DSTFILE="$DOWNLOAD_DIR/Packages-$UA.bz2"
715 log "Trying to load $SRCFILE"
716 download_file "$SRCFILE" "$DSTFILE"
717 fail_panic "Could not download $SRCFILE"
718 (cd $DOWNLOAD_DIR && bunzip2 -cf Packages-$UA.bz2 > Packages-$UA)
719 fail_panic "Could not uncompress $DSTFILE to Packages-$UA"
720 done
721
722 # Write a small awk script used to extract filenames for a given package
723 cat > $DOWNLOAD_DIR/extract-filename.awk <<EOF
724BEGIN {
725 # escape special characters in package name
726 gsub("\\\\.","\\\\.",PKG)
727 gsub("\\\\+","\\\\+",PKG)
728 FILE = ""
729 PACKAGE = ""
730}
731
732\$1 == "Package:" {
733 if (\$2 == PKG) {
734 PACKAGE = \$2
735 } else {
736 PACKAGE = ""
737 }
738}
739
740\$1 == "Filename:" && PACKAGE == PKG {
741 FILE = \$2
742}
743
744END {
745 print FILE
746}
747EOF
748}
749
750# Convert an unversioned package name into a .deb package URL
751#
752# $1: Package name without version information (e.g. libc6-dev)
753# $2: Ubuntu mirror base URL
754# $3: Ubuntu arch ("i386" or "amd64")
755#
756get_ubuntu_package_deb_url ()
757{
758 # The following is an awk command to parse the Packages file and extract
759 # the filename of a given package.
760 local BASE="`no_trailing_slash \"$1\"`"
761 local FILE=`awk -f "$DOWNLOAD_DIR/extract-filename.awk" -v PKG=$1 $DOWNLOAD_DIR/Packages-$3`
762 if [ -z "$FILE" ]; then
763 log "Could not find filename for package $1"
764 exit 1
765 fi
766 echo "$2/ubuntu/$FILE"
767}
768
769# Does the host compiler generate 32-bit machine code?
770# If not, add the -m32 flag to the compiler name to ensure this.
771#
772compute_host_flags ()
773{
774 HOST_CC=${CC:-gcc}
775 HOST_CXX=${CXX-g++}
776 if [ -n "$USE_CCACHE" ]; then
777 echo -n "Checking for ccache..."
778 find_program CMD_CCACHE ccache
779 if [ -n "$CMD_CCACHE" ] ; then
780 echo "$HOST_CC" | tr ' ' '\n' | grep -q -e "ccache"
781 if [ $? = 0 ] ; then
782 echo "yes (ignored)"
783 else
784 echo "yes"
785 HOST_CC="ccache $HOST_CC"
786 HOST_CXX="ccache $HOST_CXX"
787 fi
788 else
789 echo "no"
790 fi
791 fi
792 echo -n "Checking compiler bitness... "
793 cat > "$BUILD_DIR"/conftest.c << EOF
794#include <stdio.h>
795int main(void) {
796 printf("%d\n",sizeof(void*)*8);
797 return 0;
798}
799EOF
800 $HOST_CC -o "$BUILD_DIR"/conftest "$BUILD_DIR"/conftest.c > "$BUILD_DIR"/conftest.log 2>&1
801 if [ $? != 0 ] ; then
802 echo "Could not compile test program!!"
803 echo "Error log is:"
804 cat "$BUILD_DIR"/conftest.log
805 rm "$BUID_DIR"/conftest.log
806 panic "Need a working build toolchain!"
807 fi
808 HOST_CC_BITS=$("$BUILD_DIR"/conftest)
809 echo -n "$HOST_CC_BITS"
810 case $HOST_CC_BITS in
811 32) # Nothing to do
812 ;;
813 64) # Do we need to force 32-bits
814 if [ "$FORCE_32" ]; then
815 echo " (forcing generation of 32-bit binaries)"
816 HOST_CC=$HOST_CC" -m32"
817 HOST_CXX=$HOST_CXX" -m32"
818 fi
819 ;;
820 *)
821 panic "Unknown bitness (32 or 64 expected) !!"
822 esac
823 echo ""
824 echo "Using build C compiler: $HOST_CC"
825 echo "Using build C++ compiler: $HOST_CXX"
826 echo "GCC target name: $GCC_TARGET"
827 echo "GMP target name: $GMP_TARGET"
828 echo "GMP ABI: $GMP_ABI"
829 export CC="$HOST_CC"
830 export CXX="$HOST_CXX"
831}
832
833compute_host_flags
834
835# Return the value of a given named variable
836# $1: variable name
837#
838# example:
839# FOO=BAR
840# BAR=ZOO
841# echo `var_value $FOO`
842# will print 'ZOO'
843#
844var_value ()
845{
846 eval echo \$$1
847}
848
849var_list_append ()
850{
851 local VARNAME=$1
852 local VARVAL=`var_value $VARNAME`
853 shift
854 if [ -z "$VARVAL" ] ; then
855 eval $VARNAME=\"$@\"
856 else
857 eval $VARNAME=\"$VARVAL $@\"
858 fi
859}
860
861var_list_prepend ()
862{
863 local VARNAME=$1
864 local VARVAL=`var_value $VARNAME`
865 shift
866 if [ -z "$VARVAL" ] ; then
867 eval $VARNAME=\"$@\"
868 else
869 eval $VARNAME=\"$@ $VARVAL\"
870 fi
871}
872
873_list_first ()
874{
875 echo $1
876}
877
878_list_rest ()
879{
880 shift
881 echo "$@"
882}
883
884_list_reverse ()
885{
886 local I1 I2 I3 I4 I5 I6 I7 I8 I9 REST RET
887 I1=$1; I2=$2; I3=$3; I4=$I4; I5=$I5; I6=$I6; I7=$I7; I8=$I8; I9=$I9
888 shift 9
889 RET=$I9${I8:+" "}$I8${I7:+" "}$I7${I6:+" "}$I6${I5:+" "}$I5${I4:+" "}$I4${I3:+" "}$I3${I2:+" "}$I2${I1:+" "}$I1
890 REST="$*"
891 if [ "$REST" ]; then
892 RET=$(_list_reverse $REST)$RET
893 fi
894 echo "$RET"
895}
896
897var_list_pop_first ()
898{
899 local VARNAME=$1
900 local VARVAL=`var_value $VARNAME`
901 local FIRST=`_list_first $VARVAL`
902 eval $VARNAME=\"`_list_rest $VARVAL`\"
903 echo "$FIRST"
904}
905
906_list_first ()
907{
908 echo $1
909}
910
911_list_rest ()
912{
913 shift
914 echo "$@"
915}
916
917var_list_first ()
918{
919 local VAL=`var_value $1`
920 _list_first $VAL
921}
922
923var_list_rest ()
924{
925 local VAL=`var_value $1`
926 _list_rest $VAL
927}
928
929ALL_TASKS=
930
931# Define a new task for this build script
932# $1: Task name (e.g. build_stuff)
933# $2: Task description
934# $3: Optional: command name (will be cmd_$1 by default)
935#
936task_define ()
937{
938 local TASK="$1"
939 local DESCR="$2"
940 local COMMAND="${3:-cmd_$1}"
941
942 var_list_append ALL_TASKS $TASK
943 task_set $TASK name "$TASK"
944 task_set $TASK descr "$DESCR"
945 task_set $TASK cmd "$COMMAND"
946 task_set $TASK deps ""
947}
948
949# Variant of task define for dual tasks
950# This really defines two tasks named '<task>_1' and '<task>_2"
951# $1: Task base name
952# $2: Task description
953# $3: Optional: command name (will be cmd_$1 by default)
954task2_define ()
955{
956 local TASK="$1"
957 local DESCR="$2"
958 local COMMAND="${3:-cmd_$1}"
959
960 task_define "${TASK}_1" "$DESCR 1/2" "phase_1 $COMMAND"
961 task_define "${TASK}_2" "$DESCR 2/2" "phase_2 $COMMAND"
962}
963
964task_set ()
965{
966 local TASK="$1"
967 local FIELD="$2"
968 shift; shift;
969 eval TASK_${TASK}__${FIELD}=\"$@\"
970}
971
972task_get ()
973{
974 var_value TASK_$1__$2
975}
976
977# return the list of dependencies for a given task
978task_get_deps ()
979{
980 task_get $1 deps
981}
982
983task_get_cmd ()
984{
985 task_get $1 cmd
986}
987
988task_get_descr ()
989{
990 task_get $1 descr
991}
992
993# $1: task name
994# $2+: other tasks this task depends on.
995task_depends ()
996{
997 local TASK="$1"
998 shift;
999 var_list_append TASK_${TASK}__deps $@
1000}
1001
1002# $1: dual task name
1003# $2+: other non-dual tasks this dual task depends on
1004task2_depends1 ()
1005{
1006 local TASK="$1"
1007 shift
1008 var_list_append TASK_${TASK}_1__deps $@
1009 var_list_append TASK_${TASK}_2__deps $@
1010}
1011
1012# $1: dual task name
1013# $2+: other dual tasks this dual task depends on
1014task2_depends2 ()
1015{
1016 local TASK="$1"
1017 local DEP
1018 shift
1019 for DEP; do
1020 var_list_append TASK_${TASK}_1__deps ${DEP}_1
1021 var_list_append TASK_${TASK}_2__deps ${DEP}_2
1022 done
1023}
1024
1025task_dump ()
1026{
1027 local TASK
1028 for TASK in $ALL_TASKS; do
1029 local DEPS="`task_get_deps $TASK`"
1030 local CMD="`task_get_cmd $TASK`"
1031 local DESCR="`task_get_descr $TASK`"
1032 echo "TASK $TASK: $DESCR: $CMD"
1033 echo "> $DEPS"
1034 done
1035}
1036
1037task_visit ()
1038{
1039 task_set $TASK visit 1
1040}
1041
1042task_unvisit ()
1043{
1044 task_set $TASK visit 0
1045}
1046
1047task_is_visited ()
1048{
1049 [ `task_get $TASK visit` = 1 ]
1050}
1051
1052task_queue_reset ()
1053{
1054 TASK_QUEUE=
1055}
1056
1057task_queue_push ()
1058{
1059 var_list_append TASK_QUEUE $1
1060}
1061
1062task_queue_pop ()
1063{
1064 local FIRST=`var_list_first TASK_QUEUE`
1065 TASK_QUEUE=`var_list_rest TASK_QUEUE`
1066}
1067
1068do_all_tasks ()
1069{
1070 local TASK
1071 local TASK_LIST=
1072 task_queue_reset
1073 # Clear visit flags
1074 for TASK in $ALL_TASKS; do
1075 task_unvisit $TASK
1076 done
1077 task_queue_push $1
1078 while [ -n "$TASK_QUEUE" ] ; do
1079 TASK=`task_queue_pop`
1080 if task_is_visited $TASK; then
1081 continue
1082 fi
1083 # Prepend the task to the list if its timestamp is not set
1084 if stamp_check $TASK; then
1085 var_list_prepend TASK_LIST $TASK
1086 fi
1087 # Add all dependencies to the work-queue
1088 local SUBTASK
1089 for SUBTASK in `task_get_deps $TASK`; do
1090 task_queue_push $SUBTASK
1091 done
1092 task_visit $TASK
1093 done
1094
1095 # Now, TASK_LIST contains the
1096}
1097
1098
1099# Return the first item of a space-separated list
1100list_first () {
1101 set -- "$@"
1102 echo "$1"
1103}
1104
1105# Append an item to a given list
1106list_append () {
1107 local ITEM=$1
1108 shift;
1109 echo $@${@:+" "}$1
1110}
1111
1112# Return the second-to-last items of a space-separated list
1113list_rest () {
1114 set -- "$@"
1115 shift
1116 echo "$@"
1117}
1118
1119# Reverse a space-separated list
1120list_reverse ()
1121{
1122 set -- "$@"
1123 local I1 I2 I3 I4 I5 I6 I7 I8 I9 REST RET
1124 I1=$1; I2=$2; I3=$3; I4=$4; I5=$5; I6=$6; I7=$7; I8=$8; I9=$9
1125 shift; shift; shift; shift; shift; shift; shift; shift; shift;
1126 RET=$I9${I9:+" "}$I8${I8:+" "}$I7${I7:+" "}$I6${I6:+" "}$I5${I5:+" "}$I4${I4:+" "}$I3${I3:+" "}$I2${I2:+" "}$I1
1127 REST="$*"
1128 if [ -n "$REST" ]; then
1129 RET=$(list_reverse $REST)" "$RET
1130 fi
1131 echo "$RET"
1132}
1133
1134# Used to build the list of tasks with a tree post-order traversal, i.e.
1135# the list starts at the leaves and finishes with the top level task,
1136# so that if task(A) depends on task(B), then A will always appear _after_
1137# B in the result.
1138#
1139# $1: space-separated list of tasks to visit
1140# Out: list of all tasks in post-order
1141#
1142task_build_postorder_list ()
1143{
1144 local TASK
1145 local STACK="$1"
1146 local RET=""
1147 for TASK in $ALL_TASKS; do
1148 stamp_clear $TASK.visit
1149 done
1150 while true; do
1151 # Peek at stack
1152 TASK=$(list_first $STACK)
1153 #echo >&2 "STACK: ($TASK) '$STACK'"
1154 if [ -z "$TASK" ]; then
1155 break
1156 fi
1157 HAS_DEPS=
1158 for DEP in $(task_get_deps $TASK); do
1159 #echo >&2 "CHECK: '$DEP'"
1160 if ! stamp_check $DEP.visit; then
1161 STACK=$DEP" "$STACK
1162 #echo >&2 "PUSH: '$DEP' => '$STACK'"
1163 HAS_DEPS=1
1164 fi
1165 done
1166
1167 if [ -z "$HAS_DEPS" ]; then
1168 #echo >&2 "ADD: $TASK -> '$RET'"
1169 STACK=$(list_rest $STACK)
1170 if ! stamp_check $TASK.visit; then
1171 RET=$RET${RET:+" "}$TASK
1172 stamp_set $TASK.visit
1173 fi
1174 fi
1175 done
1176 for TASK in $ALL_TASKS; do
1177 stamp_clear $TASK.visit
1178 done
1179 echo "$RET"
1180}
1181
1182run_task ()
1183{
1184 # Build the list of tasks, in reverse order (from leafs to last)
1185 local TASKS=$(task_build_postorder_list $1)
1186 # Do all tasks
1187 local TASK DEP DESCR
1188
1189 # Dump list of tasks:
1190# echo "ALL TASKS:"
1191# for TASK in $TASKS; do
1192# echo " $TASK"
1193# done
1194
1195 # Clean timestamps of any tasks whose any of its dependents needs
1196 # to be re-done.
1197 #
1198 for TASK in $TASKS; do
1199 for DEP in $(task_get_deps $TASK); do
1200 if ! stamp_check $DEP; then
1201 #echo "Redo: $TASK due to $DEP"
1202 stamp_clear $TASK
1203 break
1204 fi
1205 done
1206 done
1207
1208 for TASK in $TASKS; do
1209 DESCR=$(task_get_descr $TASK)
1210 if stamp_check $TASK; then
1211 echo "Skipping: $DESCR"
1212 continue
1213 fi
1214 echo "Running: $DESCR"
1215 if [ "$VERBOSE" -ge 1 ] ; then
1216 (eval $(task_get_cmd $TASK))
1217 else
1218 (eval $(task_get_cmd $TASK)) >> $TMPLOG 2>&1
1219 fi
1220 if [ $? != 0 ] ; then
1221 echo "ERROR: Cannot $DESCR"
1222 exit 1
1223 fi
1224
1225 stamp_set $TASK
1226 done
1227}
1228
1229# This function is used to clone a source repository either from a given
1230# git base or a git reference.
1231# $1: project/subdir name
1232# $2: path to SOURCES file
1233toolchain_clone ()
1234{
1235 local GITFLAGS
1236 GITFLAGS=
1237 if [ "$GIT_REFERENCE" ]; then
1238 GITFLAGS="$GITFLAGS --shared --reference $GIT_REFERENCE/$1"
1239 fi
1240 echo "cleaning up toolchain/$1"
1241 rm -rf $1
1242 fail_panic "Could not clean $(pwd)/$1"
1243 echo "downloading sources for toolchain/$1"
1244 if [ -d "$GIT_BASE/$1" ]; then
1245 log "cloning $GIT_BASE/$1"
1246 run $GIT_CMD clone $GITFLAGS $GIT_BASE/$1 $1
1247 else
1248 log "cloning $GITPREFIX/$1.git"
1249 run $GIT_CMD clone $GITFLAGS $GIT_BASE/$1.git $1
1250 fi
1251 fail_panic "Could not clone $GIT_BASE/$1.git ?"
1252 cd $1
1253 if [ "$GIT_BRANCH" != "master" ] ; then
1254 log "checking out $GIT_BRANCH branch of $1.git"
1255 run $GIT_CMD checkout -b $GIT_BRANCH origin/$GIT_BRANCH
1256 fail_panic "Could not checkout $1 ?"
1257 fi
1258 # If --git-date is used, or we have a default
1259 if [ -n "$GIT_DATE" ] ; then
1260 REVISION=`git rev-list -n 1 --until="$GIT_DATE" HEAD`
1261 echo "Using sources for date '$GIT_DATE': toolchain/$1 revision $REVISION"
1262 run $GIT_CMD checkout $REVISION
1263 fail_panic "Could not checkout $1 ?"
1264 fi
1265 (printf "%-32s " "toolchain/$1.git: " && git log -1 --format=oneline) >> $2
1266 cd ..
1267}
1268
1269task_define download_toolchain_sources "Download toolchain sources from $GIT_BASE "
1270cmd_download_toolchain_sources ()
1271{
1272 local SUBDIRS="binutils build gcc gdb gold gmp mpfr mpc isl cloog"
1273 (mkdir -p $TOOLCHAIN_SRC_DIR && cd $TOOLCHAIN_SRC_DIR &&
1274 # Create a temporary SOURCES file for the toolchain sources only
1275 # It's content will be copied to the final SOURCES file later.
1276 SOURCES_LIST=$TOOLCHAIN_SRC_DIR/SOURCES
1277 rm -f $SOURCES_LIST && touch $SOURCES_LIST
1278 for SUB in $SUBDIRS; do
1279 toolchain_clone $SUB $SOURCES_LIST
1280 done
1281 )
1282}
1283
1284task_define download_ubuntu_packages_list "Download Ubuntu packages list"
1285cmd_download_ubuntu_packages_list ()
1286{
1287 mkdir -p $DOWNLOAD_DIR
1288 get_ubuntu_packages_list "$UBUNTU_MIRROR" "$UBUNTU_RELEASE"
1289 fail_panic "Unable to download packages list, try --ubuntu-mirror=<url> to use another archive mirror"
1290}
1291
1292task_define download_packages "Download Ubuntu packages"
1293task_depends download_packages download_ubuntu_packages_list
1294cmd_download_packages ()
1295{
1296 local PACKAGE PKGURL
1297
1298 rm -f $DOWNLOAD_DIR/SOURCES && touch $DOWNLOAD_DIR/SOURCES
1299 for PACKAGE in $UBUNTU_PACKAGES; do
1300 echo "Downloading $PACKAGE"
1301 for UA in $UBUNTU_ARCHS; do
1302 PKGURL=`get_ubuntu_package_deb_url $PACKAGE $UBUNTU_MIRROR $UA`
1303 echo "URL: $PKGURL"
1304 download_file_to $PKGURL $DOWNLOAD_DIR
1305 fail_panic "Could not download $PKGURL"
1306 done
1307 done
1308 sha1sum $DOWNLOAD_DIR/*.deb | while read LINE; do
1309 PACKAGE=$(basename $(echo $LINE | awk '{ print $2;}'))
1310 SHA1=$(echo $LINE | awk '{ print $1; }')
1311 printf "%-64s %s\n" $PACKAGE $SHA1 >> $DOWNLOAD_DIR/SOURCES
1312 done
1313}
1314
1315task_define build_sysroot "Build sysroot"
1316task_depends build_sysroot download_packages
1317
1318cmd_build_sysroot ()
1319{
1320 local PACKAGE PKGURL SRC_PKG
1321 mkdir -p $SRC_PKG $ORG_SYSROOT_DIR
1322 for PACKAGE in $UBUNTU_PACKAGES; do
1323 for UA in $UBUNTU_ARCHS; do
1324 PKGURL=`get_ubuntu_package_deb_url $PACKAGE $UBUNTU_MIRROR $UA`
1325 SRC_PKG=$DOWNLOAD_DIR/`basename $PKGURL`
1326 echo "Extracting $SRC_PKG"
1327 dpkg -x $SRC_PKG $ORG_SYSROOT_DIR/$UA
1328 done
1329 done
1330}
1331
1332# Now, we need to patch libc.so which is actually a linker script
1333# referencing /lib* and /usr/lib*. Do the same for libpthread.so
1334patch_library ()
1335{
1336 echo "Patching $1"
1337 sed -i -e "s: /usr/lib[^ ]*/: :g;s: /lib[^ ]*/: :g" $1
1338}
1339
1340# Used to setup phase 1 the run a command
1341phase_1 ()
1342{
1343 PHASE=1
1344 $@
1345}
1346
1347# Used to setup phase 2 then run a command
1348phase_2 ()
1349{
1350 PHASE=1
1351 BINPREFIX=$(install_dir)/bin/${GCC_TARGET}-
1352 CC=${BINPREFIX}gcc
1353 CXX=${BINPREFIX}g++
1354 LD=${BINPREFIX}ld
1355 AR=${BINPREFIX}ar
1356 AS=${BINPREFIX}as
1357 RANLIB=${BINPREFIX}ranlib
1358 STRIP=${BINPREFIX}strip
1359 CC_FOR_TARGET=${BINPREFIX}gcc
1360 export CC CXX LD AR AS RANLIB STRIP CC_FOR_TARGET
1361 PHASE=2
1362 $@
1363}
1364
1365# Return the list of all symbolic links in a given directory, excluding
1366# any links in its sub-directories.
1367# $1: Sub-directory path.
1368find_symlinks_in () {
1369 (cd $1 && find . -maxdepth 1 -type l) | sed -e 's|^\./||g'
1370}
1371
1372# Apparently `patch` has issues dealing with prose above patches, but also
1373# doesn't like patches that immediately start with the '--- path/to/file' line.
1374# Use '-----' as our own special prose/patch sep.
1375remove_patch_description () {
1376 if ! grep -q '^-----$' "$1"; then
1377 cat "$1"
1378 else
1379 sed '1,/^-----$/d' "$1"
1380 fi
1381}
1382
1383task2_define copy_sysroot "Fix and copy sysroot"
1384task2_depends1 copy_sysroot build_sysroot
1385cmd_copy_sysroot ()
1386{
1387 local SL
1388
1389 # Copy the content of $ORG_SYSROOT_DIR/.../lib to $(sysroot_dir)/usr/lib32
1390 copy_directory $ORG_SYSROOT_DIR/i386/lib $(sysroot_dir)/usr/lib32
1391 copy_directory $ORG_SYSROOT_DIR/i386/usr/lib $(sysroot_dir)/usr/lib32
1392 copy_directory $ORG_SYSROOT_DIR/i386/usr/include $(sysroot_dir)/usr/include
1393
1394 copy_directory $ORG_SYSROOT_DIR/amd64/lib $(sysroot_dir)/usr/lib
1395 copy_directory $ORG_SYSROOT_DIR/amd64/usr/lib $(sysroot_dir)/usr/lib
1396 copy_directory $ORG_SYSROOT_DIR/amd64/usr/include $(sysroot_dir)/usr/include
1397
1398 # Ubuntu precise release has .so files in
1399 # /usr/lib/x86_64-linux-gnu and /usr/lib32/i386-linux-gnu.
1400 for LIB in $(sysroot_dir)/usr/lib/x86_64-linux-gnu \
1401 $(sysroot_dir)/usr/lib32/i386-linux-gnu; do
1402 mv $LIB/* `dirname $LIB` && rmdir $LIB
1403 fail_panic "Cannot move files in $LIB"
1404 done
1405
1406 for LIB in lib lib32; do
1407 # We need to fix the symlink like librt.so -> /lib*/librt.so.1
1408 # in $(sysroot_dir)/usr/$LIB, they should point to librt.so.1 instead now.
1409 SYMLINKS=$(find_symlinks_in $(sysroot_dir)/usr/$LIB)
1410 cd $(sysroot_dir)/usr/$LIB
1411 for SL in $SYMLINKS; do
1412 # convert /$LIB/libfoo.so.<n> into 'libfoo.so.<n>' for the target
1413 local DST=$(readlink $SL 2>/dev/null)
1414 local DST2=`basename $DST`
1415 if [ "$DST2" != "$DST" ]; then
1416 echo "Fixing symlink $SL --> $DST"
1417 rm $SL && ln -s $DST2 $SL
1418 fi
1419 done
1420 patch_library libc.so
1421 patch_library libpthread.so
1422 done
1423
1424 if [ -d "$SYSROOT_PATCHES_DIR" ]; then
1425 local sysroot_patches
1426 sysroot_patches="$(find "$SYSROOT_PATCHES_DIR" -name \*.patch)"
1427 fail_panic "Failed to enumerate sysroot patches"
1428 # Apply these patches to both subdirectories
1429 for patch in $sysroot_patches; do
1430 log "Applying sysroot patch $patch in $(sysroot_dir)"
1431 (cd "$(sysroot_dir)" && remove_patch_description "$patch" | patch -p1)
1432 fail_panic "Sysroot patch $patch does not apply"
1433 done
1434 else
1435 log "No sysroot patch dir detected; skipping sysroot patches."
1436 fi
1437}
1438
1439task_define patch_toolchain_sources "Patch toolchain sources."
1440task_depends patch_toolchain_sources download_toolchain_sources
1441cmd_patch_toolchain_sources ()
1442{
1443 log "PATCHES_DIR = $PATCHES_DIR"
1444 if [ ! -d "$PATCHES_DIR" ]; then
1445 log "$PATCHES_DIR doesn't exist"
1446 return 0
1447 fi
1448
1449 local PATCHES=`(cd $PATCHES_DIR && find . -name "*.patch" | sort ) 2> /dev/null`
1450 if [ -z "$PATCHES" ] ; then
1451 log "No patches files in $PATCHES_DIR"
1452 return 0
1453 fi
1454
1455 PATCHES=`echo $PATCHES | sed -e s%^\./%%g`
1456 for PATCH in $PATCHES; do
1457 PATCHDIR=`dirname $PATCH`
1458 PATCHNAME=`basename $PATCH`
1459 log "Applying $PATCHNAME into $TOOLCHAIN_SRC_DIR/$PATCHDIR"
1460 (cd $TOOLCHAIN_SRC_DIR/$PATCHDIR && patch -p1 < $PATCHES_DIR/$PATCH)
1461 fail_panic "Patch failure!! Please check your patches directory!"
1462 done
1463
1464 log "Done patching."
1465}
1466
1467task_define prepare_toolchain_sources "Prepare toolchain sources."
1468if [ -n "$GIT_BASE" -o -n "$GIT_REFERENCE" ]; then
1469 task_depends prepare_toolchain_sources patch_toolchain_sources
1470fi
1471cmd_prepare_toolchain_sources ()
1472{
1473 return
1474}
1475
1476task2_define configure_binutils "Configure binutils-$BINUTILS_VERSION"
1477task2_depends1 configure_binutils prepare_toolchain_sources
1478task2_depends2 configure_binutils copy_sysroot
1479cmd_configure_binutils ()
1480{
1481 OUT_DIR=$(build_dir_for binutils)
1482 mkdir -p $OUT_DIR && cd $OUT_DIR &&
1483 run $TOOLCHAIN_SRC_DIR/binutils/binutils-$BINUTILS_VERSION/configure \
1484 --prefix=$(install_dir) \
1485 --with-sysroot=$(sysroot_dir) \
1486 --target=$GCC_TARGET \
1487 --enable-gold=default \
1488 --enable-werror=no \
1489 --with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' \
1490 --with-gold-ldflags='-static-libgcc -static-libstdc++' \
1491 --with-bugurl=http://source.android.com/source/report-bugs.html
1492}
1493
1494task2_define build_binutils "Build binutils-$BINUTILS_VERSION"
1495task2_depends2 build_binutils configure_binutils
1496cmd_build_binutils ()
1497{
1498 cd $(build_dir_for binutils) &&
1499 make $MAKE_FLAGS
1500}
1501
1502task2_define install_binutils "Install binutils-$BINUTILS_VERSION"
1503task2_depends2 install_binutils build_binutils
1504cmd_install_binutils ()
1505{
1506 cd $(build_dir_for binutils) &&
1507 make install
1508}
1509
1510task2_define extract_gmp "Extract sources for gmp-$GMP_VERSION"
1511task2_depends1 extract_gmp prepare_toolchain_sources
1512cmd_extract_gmp ()
1513{
1514 OUT_DIR=$(build_dir_for gmp)
1515 GMP_TARBALL=$TOOLCHAIN_SRC_DIR/gmp/gmp-$GMP_VERSION.tar.bz2
1516 if [ ! -f "$GMP_TARBALL" ]; then
1517 GMP_TARBALL=$TOOLCHAIN_SRC_DIR/tarballs/gmp-$GMP_VERSION.tar.bz2
1518 if [ ! -f "$GMP_TARBALL" ]; then
1519 panic "Can't find gmp-$GMP_VERSION sources!!"
1520 fi
1521 fi
1522 mkdir -p $OUT_DIR && cd $OUT_DIR &&
1523 tar xjf "$GMP_TARBALL"
1524}
1525
1526task2_define configure_gmp "Configure gmp-$GMP_VERSION"
1527task2_depends2 configure_gmp extract_gmp install_binutils
1528cmd_configure_gmp ()
1529{
1530 export ABI=$GMP_ABI &&
1531 cd $(build_dir_for gmp) && mkdir -p build && cd build &&
1532 ../gmp-$GMP_VERSION/configure \
1533 --prefix=$(install_dir) \
1534 --host=$GMP_TARGET \
1535 --with-sysroot=$(install_dir) \
1536 --disable-shared
1537}
1538
1539task2_define build_gmp "Build gmp-$GMP_VERSION"
1540task2_depends2 build_gmp configure_gmp
1541cmd_build_gmp ()
1542{
1543 export ABI=$GMP_ABI &&
1544 cd $(build_dir_for gmp)/build &&
1545 make $MAKE_FLAGS
1546}
1547
1548task2_define install_gmp "Install gmp-$GMP_VERSION"
1549task2_depends2 install_gmp build_gmp
1550cmd_install_gmp ()
1551{
1552 cd $(build_dir_for gmp)/build &&
1553 make install
1554}
1555
1556# Third, build mpfr
1557task2_define extract_mpfr "Extract sources from mpfr-$MPFR_VERSION"
1558task2_depends1 extract_mpfr prepare_toolchain_sources
1559cmd_extract_mpfr ()
1560{
1561 OUT_DIR=$(build_dir_for mpfr)
1562 MPFR_TARBALL=$TOOLCHAIN_SRC_DIR/mpfr/mpfr-$MPFR_VERSION.tar.bz2
1563 if [ ! -f "$MPFR_TARBALL" ]; then
1564 MPFR_TARBALL=$TOOLCHAIN_SRC_DIR/tarballs/mpfr-$MPFR_VERSION.tar.bz2
1565 if [ ! -f "$MPFR_TARBALL" ]; then
1566 panic "Can't find mpfr-$MPFR_VERSION sources!!"
1567 fi
1568 fi
1569 mkdir -p $OUT_DIR && cd $OUT_DIR &&
1570 tar xjf "$MPFR_TARBALL"
1571}
1572
1573task2_define configure_mpfr "Configure mpfr-$MPFR_VERSION"
1574task2_depends2 configure_mpfr extract_mpfr install_gmp
1575cmd_configure_mpfr ()
1576{
1577 cd $(build_dir_for mpfr) && mkdir -p build && cd build &&
1578 run ../mpfr-$MPFR_VERSION/configure \
1579 --prefix=$(install_dir) \
1580 --host=$GMP_TARGET \
1581 --with-gmp=$(install_dir) \
1582 --with-sysroot=$(sysroot_dir) \
1583 --disable-shared
1584}
1585
1586task2_define build_mpfr "Build mpfr-$MPFR_VERSION"
1587task2_depends2 build_mpfr configure_mpfr
1588cmd_build_mpfr ()
1589{
1590 cd $(build_dir_for mpfr)/build &&
1591 run make $MAKE_FLAGS
1592}
1593
1594task2_define install_mpfr "Install mpfr-$MPFR_VERSION"
1595task2_depends2 install_mpfr build_mpfr
1596cmd_install_mpfr ()
1597{
1598 cd $(build_dir_for mpfr)/build &&
1599 run make install
1600}
1601
1602task2_define extract_mpc "Extract sources for mpc-$MPC_VERSION"
1603task2_depends1 extract_mpc prepare_toolchain_sources
1604cmd_extract_mpc ()
1605{
1606 OUT_DIR=$(build_dir_for mpc)
1607 MPC_TARBALL=$TOOLCHAIN_SRC_DIR/mpc/mpc-$MPC_VERSION.tar.gz
1608 if [ ! -f "$MPC_TARBALL" ]; then
1609 MPC_TARBALL=$TOOLCHAIN_SRC_DIR/tarballs/mpc-$MPC_VERSION.tar.gz
1610 if [ ! -f "$MPC_TARBALL" ]; then
1611 panic "Can't find mpc-$MPC_VERSION sources!!"
1612 fi
1613 fi
1614 mkdir -p $OUT_DIR && cd $OUT_DIR &&
1615 tar xzf "$MPC_TARBALL"
1616}
1617
1618task2_define configure_mpc "Configure mpc-$MPC_VERSION"
1619task2_depends2 configure_mpc extract_mpc install_mpfr
1620cmd_configure_mpc ()
1621{
1622 cd $(build_dir_for mpc) && mkdir -p build && cd build &&
1623 run ../mpc-$MPC_VERSION/configure \
1624 --prefix=$(install_dir) \
1625 --host=$GMP_TARGET \
1626 --with-gmp=$(install_dir) \
1627 --with-mpfr=$(install_dir) \
1628 --disable-shared
1629}
1630
1631task2_define build_mpc "Build mpc-$MPC_VERSION"
1632task2_depends2 build_mpc configure_mpc
1633cmd_build_mpc ()
1634{
1635 cd $(build_dir_for mpc)/build &&
1636 run make $MAKE_FLAGS
1637}
1638
1639task2_define install_mpc "Install mpc-$MPC_VERSION"
1640task2_depends2 install_mpc build_mpc
1641cmd_install_mpc ()
1642{
1643 cd $(build_dir_for mpc)/build &&
1644 run make install
1645}
1646
1647task2_define extract_isl "Extract sources for isl-$ISL_VERSION"
1648task2_depends2 extract_isl prepare_toolchain_sources
1649cmd_extract_isl ()
1650{
1651 OUT_DIR=$(build_dir_for isl)
1652 ISL_TARBALL=$TOOLCHAIN_SRC_DIR/isl/isl-$ISL_VERSION.tar.bz2
1653 if [ ! -f "$ISL_TARBALL" ]; then
1654 panic "Can't find isl-$ISL_VERSION sources!!"
1655 fi
1656 mkdir -p $OUT_DIR && cd $OUT_DIR &&
1657 tar xf "$ISL_TARBALL"
1658}
1659
1660task2_define configure_isl "Configuring isl-$ISL_VERSION"
1661task2_depends2 configure_isl extract_isl install_gmp
1662cmd_configure_isl ()
1663{
1664 cd $(build_dir_for isl) && mkdir -p build && cd build &&
1665 run ../isl-$ISL_VERSION/configure \
1666 --prefix=$(install_dir) \
1667 --host=$GMP_TARGET \
1668 --with-gmp-prefix=$(install_dir) \
1669 --with-sysroot=$(sysroot_dir) \
1670 --disable-shared
1671}
1672
1673task2_define build_isl "Building isl-$ISL_VERSION"
1674task2_depends2 build_isl configure_isl
1675cmd_build_isl ()
1676{
1677 cd $(build_dir_for isl)/build &&
1678 run make $MAKE_FLAGS
1679}
1680
1681task2_define install_isl "Installing isl-$ISL_VERSION"
1682task2_depends2 install_isl build_isl
1683cmd_install_isl ()
1684{
1685 cd $(build_dir_for isl)/build &&
1686 make install
1687}
1688
1689task2_define configure_cloog "Configure Cloog-$CLOOG_VERSION"
1690task2_depends2 configure_cloog prepare_toolchain_sources install_gmp install_isl
1691cmd_configure_cloog () {
1692 mkdir -p $(build_dir_for cloog)/build && cd $(build_dir_for cloog)/build &&
1693 run $TOOLCHAIN_SRC_DIR/cloog/cloog-$CLOOG_VERSION/configure \
1694 --prefix=$(install_dir) \
1695 --host=$GMP_TARGET \
1696 --with-gmp-prefix=$(install_dir) \
1697 --with-sysroot=$(sysroot_dir) \
1698 --disable-shared
1699}
1700
1701task2_define build_cloog "Building Cloog-$CLOOG_VERSION"
1702task2_depends2 build_cloog configure_cloog
1703cmd_build_cloog ()
1704{
1705 cd $(build_dir_for cloog)/build &&
1706 run make $MAKE_FLAGS
1707}
1708
1709task2_define install_cloog "Installing Cloog-$CLOOG_VERSION"
1710task2_depends2 install_cloog build_cloog
1711cmd_install_cloog ()
1712{
1713 cd $(build_dir_for cloog)/build &&
1714 run make install
1715}
1716
1717# Fourth, the compiler itself
1718task2_define configure_gcc "Configure gcc-$GCC_VERSION"
1719task2_depends1 configure_gcc prepare_toolchain_sources
1720task2_depends2 configure_gcc install_binutils install_gmp install_mpfr install_mpc install_cloog
1721cmd_configure_gcc ()
1722{
1723 local EXTRA_CONFIGURE_FLAGS=
1724 if [ "$GCC_VERSION" != "4.6" ]; then
1725 EXTRA_CONFIGURE_FLAGS="--with-cloog=$(install_dir)"
1726 fi
1727 OUT_DIR=$(build_dir_for gcc)
1728 mkdir -p $OUT_DIR && cd $OUT_DIR &&
1729 export CC=$HOST_CC &&
1730 export CC_FOR_TARGET="$HOST_CC" &&
1731 run $TOOLCHAIN_SRC_DIR/gcc/gcc-$GCC_VERSION/configure \
1732 --enable-multiarch \
1733 --with-arch-32=i686 \
1734 --with-abi=m64 \
1735 --prefix=$(install_dir) \
1736 --with-sysroot=$(sysroot_dir) \
1737 --disable-nls \
1738 --with-gmp=$(install_dir) \
1739 --with-mpfr=$(install_dir) \
1740 --with-mpc=$(install_dir) \
1741 --target=$GCC_TARGET \
1742 --with-arch=x86-64 \
1743 --with-multilib-list=m32,m64 \
1744 --disable-plugin \
1745 --disable-docs \
1746 --disable-bootstrap \
1747 --disable-libgomp \
1748 --disable-libmudflap \
1749 --disable-libquadmath \
1750 --enable-target-optspace \
1751 --enable-gold=default \
1752 --enable-languages=c,c++ \
1753 $EXTRA_CONFIGURE_FLAGS
1754}
1755
1756task2_define build_gcc "Build gcc-$GCC_VERSION"
1757task2_depends2 build_gcc configure_gcc
1758cmd_build_gcc ()
1759{
1760 cd $(build_dir_for gcc) &&
1761 make $MAKE_FLAGS
1762}
1763
1764task2_define install_gcc "Install gcc-$GCC_VERSION"
1765task2_depends2 install_gcc build_gcc
1766cmd_install_gcc ()
1767{
1768 cd $(build_dir_for gcc) &&
1769 make install
1770}
1771
1772task2_define cleanup_toolchain "Cleanup toolchain"
1773task2_depends2 cleanup_toolchain install_gcc
1774cmd_cleanup_toolchain ()
1775{
1776 # Remove un-needed directories and files
1777 rm -rf $(install_dir)/share
1778 rm -rf $(install_dir)/man
1779 rm -rf $(install_dir)/info
1780 rm -rf $(install_dir)/libexec/*/*/install-tools
1781 #rm -rf $(install_dir)/$GCC_TARGET/bin
1782 find $(install_dir) -name "*.la" -exec rm -f {} \;
1783
1784 (strip $(install_dir)/bin/*)
1785 (strip $(install_dir)/libexec/gcc/$GCC_TARGET/*/*)
1786
1787 true
1788}
1789
1790task2_define package_toolchain "Package final toolchain"
1791task2_depends2 package_toolchain cleanup_toolchain
1792cmd_package_toolchain ()
1793{
1794 # Copy this script to the install directory
1795 cp -f $0 $(install_dir)
1796 fail_panic "Could not copy build script to install directory"
1797
1798 # And the build-with-previous-gcc wrapper
1799 cp -f "$(dirname "$0")/build-with-previous-gcc.sh" "$(install_dir)"
1800 fail_panic "Could not copy build script wrapper to install directory"
1801
1802 for pdir in "$PATCHES_DIR" "$SYSROOT_PATCHES_DIR"; do
1803 if [ -d "$pdir" ]; then
1804 # Copy patches to the install directory
1805 cp -rf "$pdir" $(install_dir)
1806 fail_panic "Could not copy patch directory $pdir to install directory"
1807 fi
1808
1809 cp -rf "$pdir" $(install_dir)
1810 fail_panic "Could not copy patch directory to install directory"
1811 done
1812
1813 # Copy the SOURCES file as well
1814 cp $DOWNLOAD_DIR/SOURCES $(install_dir)/PACKAGE_SOURCES &&
1815 cp $TOOLCHAIN_SRC_DIR/SOURCES $(install_dir)/TOOLCHAIN_SOURCES
1816 fail_panic "Could not copy SOURCES files to install directory"
1817
1818 # Package everything
1819 pack_archive $TOOLCHAIN_ARCHIVE "`dirname $(install_dir)`" "`basename $(install_dir)`"
1820}
1821
1822task2_define install_toolchain "Install final toolchain"
1823task2_depends2 install_toolchain cleanup_toolchain
1824cmd_install_toolchain ()
1825{
1826 copy_directory "$(install_dir)" "$PREFIX_DIR/$TOOLCHAIN_NAME"
1827 cp -f $0 "$PREFIX_DIR/$TOOLCHAIN_NAME/"
1828}
1829
1830# Make sure that the second toolchain depends on the first one
1831task_depends configure_binutils_2 install_gcc_1
1832
1833if [ "$ONLY_SYSROOT" = "yes" ]; then
1834 MAIN_TASK=copy_sysroot
1835 COMPLETION_TEXT="Done, see sysroot files in $(sysroot_dir)"
1836elif [ -n "$PREFIX_DIR" ]; then
1837 if [ -z "$BOOTSTRAP" ]; then
1838 MAIN_TASK=install_toolchain_1
1839 else
1840 MAIN_TASK=install_toolchain_2
1841 fi
1842 COMPLETION_TEXT="Done, see $PREFIX_DIR/$TOOLCHAIN_NAME"
1843else
1844 if [ -z "$BOOTSTRAP" ]; then
1845 MAIN_TASK=package_toolchain_1
1846 else
1847 MAIN_TASK=package_toolchain_2
1848 fi
1849 COMPLETION_TEXT="Done, see $TOOLCHAIN_ARCHIVE"
1850fi
1851
1852if [ "$LIST_TASKS" ]; then
1853 task_dump
1854else
1855 run_task $MAIN_TASK
1856 echo "$COMPLETION_TEXT"
1857fi