1 #!/bin/sh 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.7, only the machine code it generates. 27 # 28 29 PROGNAME="`basename \"$0\"`" 30 31 ########################################################################### 32 ########################################################################### 33 ##### 34 ##### C O N F I G U R A T I O N 35 ##### 36 ########################################################################### 37 ########################################################################### 38 39 # We only support running this script on Linux 40 OS=`uname -s` 41 case "$OS" in 42 Linux) 43 OS=linux 44 ;; 45 *) 46 echo "ERROR: This script can only run on Linux!" 47 exit 1 48 ;; 49 esac 50 51 # Location of temporary directory where everything will be downloaded 52 # configured, built and installed before we generate the final 53 # package archive 54 WORK_DIR=/tmp/gcc32 55 56 # Versions of various toolchain components, do not touch unless you know 57 # what you're doing! 58 BINUTILS_VERSION=2.19 59 GMP_VERSION=4.2.4 60 MPFR_VERSION=2.4.1 61 GCC_VERSION=4.4.3 62 GCC_TARGET=i686-linux 63 GMP_TARGET=i386-linux 64 65 GIT_CMD=git 66 GIT_DATE= 67 GIT_BRANCH=master 68 GIT_REFERENCE= 69 GIT_BASE= 70 GIT_BASE_DEFAULT=https://android.googlesource.com/toolchain 71 72 # Location where we will download the toolchain sources 73 TOOLCHAIN_SRC_DIR=$WORK_DIR/toolchain-src 74 75 # Location of original sysroot. This is where we're going to extract all 76 # binary Ubuntu packages. 77 ORG_SYSROOT_DIR=$WORK_DIR/sysroot 78 79 # Name of the final generated toolchain 80 TOOLCHAIN_NAME=$GCC_TARGET-glibc2.7-$GCC_VERSION 81 82 # Name of the final toolchain binary tarball that this script will create 83 TOOLCHAIN_ARCHIVE=/tmp/$TOOLCHAIN_NAME.tar.bz2 84 85 # Location where we're going to install the toolchain during the build 86 # This will depend on the phase of the build. 87 install_dir () { echo "$WORK_DIR/$PHASE/$TOOLCHAIN_NAME"; } 88 89 # A file that will contain details about all the sources used to generate 90 # the final toolchain. This includes both SHA-1 for toolchain git repositories 91 # and SHA-1 hashes for downloaded Ubuntu packages. 92 SOURCES_LIST=$WORK_DIR/SOURCES 93 94 # Location where we're going to install the final binaries 95 # If empty, TOOLCHAIN_ARCHIVE will be generated 96 PREFIX_DIR= 97 98 # Location of the final sysroot. This must be a sub-directory of INSTALL_DIR 99 # to ensure that the toolchain binaries are properly relocatable (i.e. can 100 # be used when moved to another directory). 101 sysroot_dir () { echo "$(install_dir)/sysroot"; } 102 103 # Try to parallelize the build for faster performance. 104 JOBS=`cat /proc/cpuinfo | grep processor | wc -l` 105 106 # The base URL of the Ubuntu mirror we're going to use. 107 UBUNTU_MIRROR=http://mirrors.us.kernel.org 108 109 # Ubuntu release name we want packages from. Can be a name or a number 110 # (i.e. "hardy" or "8.04") 111 UBUNTU_RELEASE=hardy 112 113 114 # The list of packages we need to download from the Ubuntu servers and 115 # extract into the original sysroot 116 # 117 # Call add_ubuntu_package <package-name> to add a package to the list, 118 # which will be processed later. 119 # 120 UBUNTU_PACKAGES= 121 122 add_ubuntu_package () 123 { 124 UBUNTU_PACKAGES="$UBUNTU_PACKAGES $@" 125 } 126 127 # The package files containing kernel headers for Hardy and the C 128 # library headers and binaries 129 add_ubuntu_package \ 130 linux-libc-dev \ 131 libc6 \ 132 libc6-dev 133 134 # The X11 headers and binaries (for the emulator) 135 add_ubuntu_package \ 136 libx11-6 \ 137 libx11-dev \ 138 libxcb-xlib0 \ 139 libxcb1 \ 140 libxau6 \ 141 libxdmcp6 \ 142 x11proto-core-dev \ 143 x11proto-xext-dev \ 144 x11proto-input-dev \ 145 x11proto-kb-dev 146 147 # The OpenGL-related headers and libraries (for GLES emulation) 148 add_ubuntu_package \ 149 mesa-common-dev \ 150 libgl1-mesa-dev \ 151 libgl1-mesa-glx \ 152 libxxf86vm1 \ 153 libxext6 \ 154 libxdamage1 \ 155 libxfixes3 \ 156 libdrm2 157 158 # Audio libraries (required by the emulator) 159 add_ubuntu_package \ 160 libasound2 \ 161 libasound2-dev \ 162 libesd-alsa0 \ 163 libesd0-dev \ 164 libaudiofile-dev \ 165 libpulse0 \ 166 libpulse-dev 167 168 # ZLib 169 add_ubuntu_package \ 170 zlib1g \ 171 zlib1g-dev \ 172 libncurses5 \ 173 libncurses5-dev 174 175 176 177 ########################################################################### 178 ########################################################################### 179 ##### 180 ##### E N D O F C O N F I G U R A T I O N 181 ##### 182 ########################################################################### 183 ########################################################################### 184 185 # Parse all options 186 OPTION_HELP=no 187 VERBOSE=no 188 VERBOSE2=no 189 NDK_ROOT= 190 FORCE=no 191 ONLY_SYSROOT=no 192 BOOTSTRAP= 193 PARAMETERS= 194 195 for opt do 196 optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'` 197 case "$opt" in 198 --help|-h|-\?) OPTION_HELP=yes 199 ;; 200 --verbose) 201 if [ "$VERBOSE" = "yes" ] ; then 202 VERBOSE2=yes 203 else 204 VERBOSE=yes 205 fi 206 ;; 207 --force) FORCE="yes" 208 ;; 209 --ubuntu-mirror=*) UBUNTU_MIRROR="$optarg" 210 ;; 211 --ubuntu-release=*) UBUNTU_RELEASE="$optarg" 212 ;; 213 --prefix=*) PREFIX_DIR="$optarg" 214 ;; 215 --work-dir=*) WORK_DIR="$optarg" 216 ;; 217 --gcc-version=*) GCC_VERSION="$optarg" 218 ;; 219 --binutils-version=*) BINUTILS_VERSION="$optarg" 220 ;; 221 --gmp-version=*) GMP_VERSION="$optarg" 222 ;; 223 --mpfr-version=*) MPFR_VERSION="$optarg" 224 ;; 225 --git=*) GIT_CMD=$optarg 226 ;; 227 --git-date=*) GIT_DATE=$optarg 228 ;; 229 --git-branch=*) GIT_BRANCH=$optarg 230 ;; 231 --git-base=*) GIT_BASE=$optarg 232 ;; 233 --git-reference=*) GIT_REFERENCE=$optarg 234 ;; 235 --out-dir=*) OPTION_OUT_DIR="$optarg" 236 ;; 237 --cc=*) OPTION_CC="$optarg" 238 ;; 239 --jobs=*) JOBS="$optarg" 240 ;; 241 -j*) JOBS=`expr "x$opt" : 'x-j\(.*\)'` 242 ;; 243 --only-sysroot) ONLY_SYSROOT=yes 244 ;; 245 --bootstrap) BOOTSTRAP=yes 246 ;; 247 -*) 248 echo "unknown option '$opt', use --help" 249 exit 1 250 ;; 251 *) 252 if [ -z "$PARAMETERS" ]; then 253 PARAMETERS="$opt" 254 else 255 PARAMETERS="$PARAMETERS $opt" 256 fi 257 esac 258 done 259 260 if [ "$OPTION_HELP" = "yes" ]; then 261 cat << EOF 262 263 Usage: $PROGNAME [options] <path-to-toolchain-sources> 264 265 This script is used to rebuild a 32-bit Linux host toolchain that targets 266 GLibc 2.7 or higher. The machine code generated by this toolchain will run 267 properly on Ubuntu 8.04 or higher. 268 269 You need to a patch corresponding to the patched toolchain sources that 270 are downloaded from android.git.toolchain.org/toolchain/. One way to do that 271 is to use the NDK's dedicated script to do it, e.g.: 272 273 \$NDK/build/tools/download-toolchain-sources.sh /tmp/toolchain-src 274 275 Then invoke this script as: 276 277 $PROGNAME /tmp/toolchain-src 278 279 Alternatively, you can use --ndk-dir=<path> to specify the location of 280 your NDK directory, and this script will directly download the toolchain 281 sources for you. 282 283 Note that this script will download various binary packages from Ubuntu 284 servers in order to prepare a compatible 32-bit "sysroot". 285 286 By default, it generates a package archive ($TOOLCHAIN_ARCHIVE) but you can, 287 as an alternative, ask for direct installation with --prefix=<path> 288 289 Options: [defaults in brackets after descriptions] 290 EOF 291 echo "Standard options:" 292 echo " --help Print this message" 293 echo " --force Force-rebuild everything" 294 echo " --prefix=PATH Installation path [$PREFIX_DIR]" 295 echo " --ubuntu-mirror=URL Ubuntu mirror URL [$UBUNTU_MIRROR]" 296 echo " --ubuntu-release=NAME Ubuntu release name [$UBUNTU_RELEASE]" 297 echo " --work-dir=PATH Temporary work directory [$WORK_DIR]" 298 echo " --only-sysroot Only dowload and build sysroot packages" 299 echo " --verbose Verbose output. Can be used twice." 300 echo " --binutils-version=VERSION Binutils version number [$BINUTILS_VERSION]" 301 echo " --gcc-version=VERSION GCC version number [$GCC_VERSION]." 302 echo " --gmp-version=VERSION GMP version number [$GMP_VERSION]." 303 echo " --mpfr-version=VERSION MPFR version numner [$MPFR_VERSION]." 304 echo " --ndk-dir=PATH Path to NDK (used to download toolchain sources)." 305 echo " --jobs=COUNT Run COUNT build jobs in parallel [$JOBS]" 306 echo " --git=<cmd> Use this version of the git tool [$GIT_CMD]" 307 echo " --git-date=<date> Specify specific git date when download sources [none]" 308 echo " --git-branch=<name> Specify which branch to use when downloading the sources [$GIT_BRANCH]" 309 echo " --git-reference=<path> Use a git reference repository" 310 echo " --git-base=<url> Use this git repository base [$GIT_BASE]" 311 echo " -j<COUNT> Same as --jobs=COUNT." 312 echo " --bootstrap Bootstrap toolchain (i.e. compile it with itself)" 313 echo "" 314 exit 1 315 fi 316 317 if [ -z "$PARAMETERS" ] ; then 318 if [ -n "$GIT_REFERENCE" ] ; then 319 if [ ! -d "$GIT_REFERENCE" -o ! -d "$GIT_REFERENCE/build" ]; then 320 echo "ERROR: Invalid reference repository directory path: $GIT_REFERENCE" 321 exit 1 322 fi 323 if [ -n "$GIT_BASE" ]; then 324 echo "Using git clone reference: $GIT_REFERENCE" 325 else 326 # If we have a reference without a base, use it as a download base instead. 327 GIT_BASE=$GIT_REFERENCE 328 GIT_REFERENCE= 329 echo "Using git clone base: $GIT_BASE" 330 fi 331 elif [ -z "$GIT_BASE" ]; then 332 echo "ERROR: You did not provide the path to the toolchain sources." 333 echo " You can make this script download them for you by using" 334 echo " the --git-base=<url> option, as in:" 335 echo "" 336 echo " $0 --git-base=$GIT_BASE_DEFAULT" 337 echo "" 338 echo " Alternatively, you can use --git-reference=<path> if you" 339 echo " already have a copy of the source repositories." 340 echo "" 341 echo " See --help for more git-related options." 342 echo "" 343 exit 1 344 fi 345 else 346 set_parameters () { 347 TOOLCHAIN_SRC_DIR="$1" 348 if [ ! -d "$TOOLCHAIN_SRC_DIR" ]; then 349 echo "ERROR: Not a directory: $1" 350 exit 1 351 fi 352 if [ ! -d "$TOOLCHAIN_SRC_DIR/build" ]; then 353 echo "ERROR: Missing directory: $1/build" 354 exit 1 355 fi 356 } 357 358 set_parameters $PARAMETERS 359 fi 360 361 # Determine Make flags 362 MAKE_FLAGS="-j$JOBS" 363 364 # Create the work directory 365 mkdir -p $WORK_DIR 366 367 # Location where we download packages from the Ubuntu servers 368 DOWNLOAD_DIR=$WORK_DIR/download 369 370 # Empty the SOURCES file 371 rm -f $SOURCES_LIST && touch $SOURCES_LIST 372 373 374 panic () 375 { 376 echo "ERROR: $@" 377 exit 1 378 } 379 380 fail_panic () 381 { 382 if [ $? != 0 ] ; then 383 echo "ERROR: $@" 384 exit 1 385 fi 386 } 387 388 if [ "$VERBOSE" = "yes" ] ; then 389 run () { 390 echo "## COMMAND: $@" 391 $@ 392 } 393 log () { 394 echo "$@" 395 } 396 if [ "$VERBOSE2" = "yes" ] ; then 397 log2 () { 398 echo "$@" 399 } 400 else 401 log2 () { 402 return 403 } 404 fi 405 else 406 run () { 407 $@ >>$TMPLOG 2>&1 408 } 409 log () { 410 return 411 } 412 log2 () { 413 return 414 } 415 fi 416 417 OLD_PATH="$PATH" 418 OLD_LD_LIBRARY_PATH="$LD_LIBRARY_PATH" 419 420 BUILD_DIR=$WORK_DIR/build 421 mkdir -p $BUILD_DIR 422 423 TMPLOG=$BUILD_DIR/build.log 424 rm -rf $TMPLOG && touch $TMPLOG 425 426 build_binutils_dir () { echo "$BUILD_DIR/$PHASE/binutils"; } 427 build_gmp_dir () { echo "$BUILD_DIR/$PHASE/gmp"; } 428 build_mpfr_dir () { echo "$BUILD_DIR/$PHASE/mpfr"; } 429 build_gcc_dir () { echo "$BUILD_DIR/$PHASE/gcc"; } 430 431 TIMESTAMPS_DIR=$BUILD_DIR/timestamps 432 mkdir -p $TIMESTAMPS_DIR 433 434 if [ "$FORCE" = "yes" ] ; then 435 echo "Cleaning up timestamps (forcing the build)." 436 rm -f $TIMESTAMPS_DIR/* 437 fi 438 439 if [ "$VERBOSE" = "no" ] ; then 440 echo "To follow build, run: tail -F $TMPLOG" 441 fi 442 443 # returns 0 iff the string in $2 matches the pattern in $1 444 # $1: pattern 445 # $2: string 446 pattern_match () 447 { 448 echo "$2" | grep -q -E -e "$1" 449 } 450 451 # Find if a given shell program is available. 452 # We need to take care of the fact that the 'which <foo>' command 453 # may return either an empty string (Linux) or something like 454 # "no <foo> in ..." (Darwin). Also, we need to redirect stderr 455 # to /dev/null for Cygwin 456 # 457 # $1: variable name 458 # $2: program name 459 # 460 # Result: set $1 to the full path of the corresponding command 461 # or to the empty/undefined string if not available 462 # 463 find_program () 464 { 465 local PROG 466 PROG=`which $2 2>/dev/null` 467 if [ -n "$PROG" ] ; then 468 if pattern_match '^no ' "$PROG"; then 469 PROG= 470 fi 471 fi 472 eval $1="$PROG" 473 } 474 475 # Copy a directory, create target location if needed 476 # 477 # $1: source directory 478 # $2: target directory location 479 # 480 copy_directory () 481 { 482 local SRCDIR="$1" 483 local DSTDIR="$2" 484 if [ ! -d "$SRCDIR" ] ; then 485 panic "Can't copy from non-directory: $SRCDIR" 486 fi 487 mkdir -p "$DSTDIR" && (cd "$SRCDIR" && tar cf - *) | (tar xf - -C "$DSTDIR") 488 fail_panic "Cannot copy to directory: $DSTDIR" 489 } 490 491 find_program CMD_WGET wget 492 find_program CMD_CURL curl 493 find_program CMD_SCP scp 494 495 # Download a file with either 'curl', 'wget' or 'scp' 496 # 497 # $1: source URL (e.g. http://foo.com, ssh://blah, /some/path) 498 # $2: target file 499 download_file () 500 { 501 # Is this HTTP, HTTPS or FTP ? 502 if pattern_match "^(http|https|ftp):.*" "$1"; then 503 if [ -n "$CMD_WGET" ] ; then 504 run $CMD_WGET -O $2 $1 505 elif [ -n "$CMD_CURL" ] ; then 506 run $CMD_CURL -o $2 $1 507 else 508 echo "Please install wget or curl on this machine" 509 exit 1 510 fi 511 return 512 fi 513 514 # Is this SSH ? 515 # Accept both ssh://<path> or <machine>:<path> 516 # 517 if pattern_match "^(ssh|[^:]+):.*" "$1"; then 518 if [ -n "$CMD_SCP" ] ; then 519 scp_src=`echo $1 | sed -e s%ssh://%%g` 520 run $CMD_SCP $scp_src $2 521 else 522 echo "Please install scp on this machine" 523 exit 1 524 fi 525 return 526 fi 527 528 # Is this a file copy ? 529 # Accept both file://<path> or /<path> 530 # 531 if pattern_match "^(file://|/).*" "$1"; then 532 cp_src=`echo $1 | sed -e s%^file://%%g` 533 run cp -f $cp_src $2 534 return 535 fi 536 537 # Unknown schema 538 echo "ERROR: Unsupported source URI: $1" 539 exit 1 540 } 541 542 # A variant of 'download_file' used to specify the target directory 543 # $1: source URL 544 # $2: target directory 545 download_file_to () 546 { 547 local URL="$1" 548 local DIR="$2" 549 local DST="$DIR/`basename $URL`" 550 mkdir -p $DIR 551 download_file "$URL" "$DST" 552 } 553 554 # Pack a given archive 555 # 556 # $1: archive file path (including extension) 557 # $2: source directory for archive content 558 # $3+: list of files (including patterns), all if empty 559 pack_archive () 560 { 561 local ARCHIVE="$1" 562 local SRCDIR="$2" 563 local SRCFILES 564 local TARFLAGS ZIPFLAGS 565 shift; shift; 566 if [ -z "$1" ] ; then 567 SRCFILES="*" 568 else 569 SRCFILES="$@" 570 fi 571 if [ "`basename $ARCHIVE`" = "$ARCHIVE" ] ; then 572 ARCHIVE="`pwd`/$ARCHIVE" 573 fi 574 mkdir -p `dirname $ARCHIVE` 575 if [ "$VERBOSE2" = "yes" ] ; then 576 TARFLAGS="vcf" 577 ZIPFLAGS="-9r" 578 else 579 TARFLAGS="cf" 580 ZIPFLAGS="-9qr" 581 fi 582 case "$ARCHIVE" in 583 *.zip) 584 (cd $SRCDIR && run zip $ZIPFLAGS "$ARCHIVE" $SRCFILES) 585 ;; 586 *.tar) 587 (cd $SRCDIR && run tar $TARFLAGS "$ARCHIVE" $SRCFILES) 588 ;; 589 *.tar.gz) 590 (cd $SRCDIR && run tar z$TARFLAGS "$ARCHIVE" $SRCFILES) 591 ;; 592 *.tar.bz2) 593 (cd $SRCDIR && run tar j$TARFLAGS "$ARCHIVE" $SRCFILES) 594 ;; 595 *) 596 panic "Unsupported archive format: $ARCHIVE" 597 ;; 598 esac 599 } 600 601 no_trailing_slash () 602 { 603 echo "$1" | sed -e 's!/$!!g' 604 } 605 606 # Load the Ubuntu packages file. This is a long text file that will list 607 # each package for a given release. 608 # 609 # $1: Ubuntu mirror base URL (e.g. http://mirrors.us.kernel.org/) 610 # $2: Release name 611 # 612 get_ubuntu_packages_list () 613 { 614 local RELEASE=$2 615 local BASE="`no_trailing_slash \"$1\"`" 616 local SRCFILE="$BASE/ubuntu/dists/$RELEASE/main/binary-i386/Packages.bz2" 617 local DSTFILE="$DOWNLOAD_DIR/Packages.bz2" 618 log "Trying to load $SRCFILE" 619 download_file "$SRCFILE" "$DSTFILE" 620 fail_panic "Could not download $SRCFILE" 621 (cd $DOWNLOAD_DIR && bunzip2 -f Packages.bz2) 622 fail_panic "Could not uncompress $DSTFILE" 623 624 # Write a small awk script used to extract filenames for a given package 625 cat > $DOWNLOAD_DIR/extract-filename.awk <<EOF 626 BEGIN { 627 # escape special characters in package name 628 gsub("\\\\.","\\\\.",PKG) 629 gsub("\\\\+","\\\\+",PKG) 630 FILE = "" 631 PACKAGE = "" 632 } 633 634 \$1 == "Package:" { 635 if (\$2 == PKG) { 636 PACKAGE = \$2 637 } else { 638 PACKAGE = "" 639 } 640 } 641 642 \$1 == "Filename:" && PACKAGE == PKG { 643 FILE = \$2 644 } 645 646 END { 647 print FILE 648 } 649 EOF 650 } 651 652 # Convert an unversioned package name into a .deb package URL 653 # 654 # $1: Package name without version information (e.g. libc6-dev) 655 # $2: Ubuntu mirror base URL 656 # 657 get_ubuntu_package_deb_url () 658 { 659 # The following is an awk command to parse the Packages file and extract 660 # the filename of a given package. 661 local BASE="`no_trailing_slash \"$1\"`" 662 local FILE=`awk -f "$DOWNLOAD_DIR/extract-filename.awk" -v PKG=$1 $DOWNLOAD_DIR/Packages` 663 if [ -z "$FILE" ]; then 664 log "Could not find filename for package $1" 665 exit 1 666 fi 667 echo "$2/ubuntu/$FILE" 668 } 669 670 # Does the host compiler generate 32-bit machine code? 671 # If not, add the -m32 flag to the compiler name to ensure this. 672 # 673 compute_host_flags () 674 { 675 HOST_CC=${CC:-gcc} 676 HOST_CXX=${CXX-g++} 677 echo -n "Checking for ccache..." 678 find_program CMD_CCACHE ccache 679 if [ -n "$CMD_CCACHE" ] ; then 680 echo "$HOST_CC" | tr ' ' '\n' | grep -q -e "ccache" 681 if [ $? = 0 ] ; then 682 echo "yes (ignored)" 683 else 684 echo "yes" 685 HOST_CC="ccache $HOST_CC" 686 HOST_CXX="ccache $HOST_CXX" 687 fi 688 else 689 echo "no" 690 fi 691 echo -n "Checking whether the compiler generates 32-bit code... " 692 cat > $BUILD_DIR/conftest.c << EOF 693 /* This will fail to compile if void* is not 32-bit */ 694 int test_array[1 - 2*(sizeof(void*) != 4)]; 695 EOF 696 $HOST_CC -o $BUILD_DIR/conftest.o -c $BUILD_DIR/conftest.c > $BUILD_DIR/conftest.log 2>&1 697 if [ $? != 0 ] ; then 698 echo "no" 699 HOST_CC="$HOST_CC -m32" 700 HOST_CXX="$HOST_CXX -m32" 701 else 702 echo "yes" 703 fi 704 export CC="$HOST_CC" 705 export CXX="$HOST_CXX" 706 } 707 708 compute_host_flags 709 710 # Return the value of a given named variable 711 # $1: variable name 712 # 713 # example: 714 # FOO=BAR 715 # BAR=ZOO 716 # echo `var_value $FOO` 717 # will print 'ZOO' 718 # 719 var_value () 720 { 721 eval echo \$$1 722 } 723 724 var_list_append () 725 { 726 local VARNAME=$1 727 local VARVAL=`var_value $VARNAME` 728 shift 729 if [ -z "$VARVAL" ] ; then 730 eval $VARNAME=\"$@\" 731 else 732 eval $VARNAME=\"$VARVAL $@\" 733 fi 734 } 735 736 var_list_prepend () 737 { 738 local VARNAME=$1 739 local VARVAL=`var_value $VARNAME` 740 shift 741 if [ -z "$VARVAL" ] ; then 742 eval $VARNAME=\"$@\" 743 else 744 eval $VARNAME=\"$@ $VARVAL\" 745 fi 746 } 747 748 _list_first () 749 { 750 echo $1 751 } 752 753 _list_rest () 754 { 755 shift 756 echo "$@" 757 } 758 759 var_list_pop_first () 760 { 761 local VARNAME=$1 762 local VARVAL=`var_value $VARNAME` 763 local FIRST=`_list_first $VARVAL` 764 eval $VARNAME=\"`_list_rest $VARVAL`\" 765 echo "$FIRST" 766 } 767 768 _list_first () 769 { 770 echo $1 771 } 772 773 _list_rest () 774 { 775 shift 776 echo "$@" 777 } 778 779 var_list_first () 780 { 781 local VAL=`var_value $1` 782 _list_first $VAL 783 } 784 785 var_list_rest () 786 { 787 local VAL=`var_value $1` 788 _list_rest $VAL 789 } 790 791 ALL_TASKS= 792 793 # Define a new task for this build script 794 # $1: Task name (e.g. build_stuff) 795 # $2: Task description 796 # $3: Optional: command name (will be cmd_$1 by default) 797 # 798 task_define () 799 { 800 local TASK="$1" 801 local DESCR="$2" 802 local COMMAND="${3:-cmd_$1}" 803 804 var_list_append ALL_TASKS $TASK 805 task_set $TASK name "$TASK" 806 task_set $TASK descr "$DESCR" 807 task_set $TASK cmd "$COMMAND" 808 task_set $TASK deps "" 809 } 810 811 # Variant of task define for dual tasks 812 # This really defines two tasks named '<task>_1' and '<task>_2" 813 # $1: Task base name 814 # $2: Task description 815 # $3: Optional: command name (will be cmd_$1 by default) 816 task2_define () 817 { 818 local TASK="$1" 819 local DESCR="$2" 820 local COMMAND="${3:-cmd_$1}" 821 822 task_define "${TASK}_1" "$DESCR 1/2" "phase_1 $COMMAND" 823 task_define "${TASK}_2" "$DESCR 2/2" "phase_2 $COMMAND" 824 } 825 826 task_set () 827 { 828 local TASK="$1" 829 local FIELD="$2" 830 shift; shift; 831 eval TASK_${TASK}__${FIELD}=\"$@\" 832 } 833 834 task_get () 835 { 836 var_value TASK_$1__$2 837 } 838 839 # return the list of dependencies for a given task 840 task_get_deps () 841 { 842 task_get $1 deps 843 } 844 845 task_get_cmd () 846 { 847 task_get $1 cmd 848 } 849 850 task_get_descr () 851 { 852 task_get $1 descr 853 } 854 855 # $1: task name 856 # $2+: other tasks this task depends on. 857 task_depends () 858 { 859 local TASK="$1" 860 shift; 861 var_list_append TASK_${TASK}__deps $@ 862 } 863 864 # $1: dual task name 865 # $2+: other non-dual tasks this dual task depends on 866 task2_depends1 () 867 { 868 local TASK="$1" 869 shift 870 var_list_append TASK_${TASK}_1__deps $@ 871 var_list_append TASK_${TASK}_2__deps $@ 872 } 873 874 # $1: dual task name 875 # $2+: other dual tasks this dual task depends on 876 task2_depends2 () 877 { 878 local TASK="$1" 879 local DEP 880 shift 881 for DEP; do 882 var_list_append TASK_${TASK}_1__deps ${DEP}_1 883 var_list_append TASK_${TASK}_2__deps ${DEP}_2 884 done 885 } 886 887 task_dump () 888 { 889 local TASK 890 for TASK in $ALL_TASKS; do 891 local DEPS="`task_get_deps $TASK`" 892 local CMD="`task_get_cmd $TASK`" 893 local DESCR="`task_get_descr $TASK`" 894 echo "TASK $TASK: $DESCR: $CMD" 895 echo "> $DEPS" 896 done 897 } 898 899 task_visit () 900 { 901 task_set $TASK visit 1 902 } 903 904 task_unvisit () 905 { 906 task_set $TASK visit 0 907 } 908 909 task_is_visited () 910 { 911 [ `task_get $TASK visit` = 1 ] 912 } 913 914 task_queue_reset () 915 { 916 TASK_QUEUE= 917 } 918 919 task_queue_push () 920 { 921 var_list_append TASK_QUEUE $1 922 } 923 924 task_queue_pop () 925 { 926 local FIRST=`var_list_first TASK_QUEUE` 927 TASK_QUEUE=`var_list_rest TASK_QUEUE` 928 } 929 930 do_all_tasks () 931 { 932 local TASK 933 local TASK_LIST= 934 task_queue_reset 935 # Clear visit flags 936 for TASK in $ALL_TASKS; do 937 task_unvisit $TASK 938 done 939 task_queue_push $1 940 while [ -n "$TASK_QUEUE" ] ; do 941 TASK=`task_queue_pop` 942 if task_is_visited $TASK; then 943 continue 944 fi 945 # Prepend the task to the list if its timestamp is not set 946 if [ ! -f $TIMESTAMPS_DIR/$TASK ]; then 947 var_list_prepend TASK_LIST $TASK 948 fi 949 # Add all dependencies to the work-queue 950 local SUBTASK 951 for SUBTASK in `task_get_deps $TASK`; do 952 task_queue_push $SUBTASK 953 done 954 task_visit $TASK 955 done 956 957 # Now, TASK_LIST contains the 958 } 959 960 do_task () 961 { 962 local TASK="$1" 963 local DEPS="`task_get_deps $TASK`" 964 local DESCR="`task_get_descr $TASK`" 965 local DEP 966 #echo ">> $TASK: $DEPS" 967 if [ -f "$TIMESTAMPS_DIR/$TASK" ] ; then 968 echo "Skipping $1: already done." 969 return 0 970 fi 971 972 # do_task for any dependents 973 for DEP in $DEPS; do 974 #echo " ? $DEP" 975 if [ ! -f "$TIMESTAMPS_DIR/$DEP" ] ; then 976 do_task $DEP 977 fi 978 done 979 980 echo "Running: $DESCR" 981 if [ "$VERBOSE" = "yes" ] ; then 982 (eval `task_get_cmd $TASK`) 983 else 984 (eval `task_get_cmd $TASK`) >> $TMPLOG 2>&1 985 fi 986 if [ $? != 0 ] ; then 987 echo "ERROR: Cannot $DESCR" 988 exit 1 989 fi 990 991 touch "$TIMESTAMPS_DIR/$TASK" 992 } 993 994 # This function is used to clone a source repository either from a given 995 # git base or a git reference. 996 # $1: project/subdir name 997 # $2: path to SOURCES file 998 toolchain_clone () 999 { 1000 local GITFLAGS 1001 GITFLAGS= 1002 if [ "$GIT_REFERENCE" ]; then 1003 GITFLAGS="$GITFLAGS --shared --reference $GIT_REFERENCE/$1" 1004 fi 1005 echo "cleaning up toolchain/$1" 1006 rm -rf $1 1007 fail_panic "Could not clean $(pwd)/$1" 1008 echo "downloading sources for toolchain/$1" 1009 if [ -d "$GIT_BASE/$1" ]; then 1010 log "cloning $GIT_BASE/$1" 1011 run $GIT_CMD clone $GITFLAGS $GIT_BASE/$1 $1 1012 else 1013 log "cloning $GITPREFIX/$1.git" 1014 run $GIT_CMD clone $GITFLAGS $GIT_BASE/$1.git $1 1015 fi 1016 fail_panic "Could not clone $GIT_BASE/$1.git ?" 1017 cd $1 1018 if [ "$GIT_BRANCH" != "master" ] ; then 1019 log "checking out $GIT_BRANCH branch of $1.git" 1020 run $GIT_CMD checkout -b $GIT_BRANCH origin/$GIT_BRANCH 1021 fail_panic "Could not checkout $1 ?" 1022 fi 1023 # If --git-date is used, or we have a default 1024 if [ -n "$GIT_DATE" ] ; then 1025 REVISION=`git rev-list -n 1 --until="$GIT_DATE" HEAD` 1026 echo "Using sources for date '$GIT_DATE': toolchain/$1 revision $REVISION" 1027 run $GIT_CMD checkout $REVISION 1028 fail_panic "Could not checkout $1 ?" 1029 fi 1030 (printf "%-32s " "toolchain/$1.git: " && git log -1 --format=oneline) >> $2 1031 cd .. 1032 } 1033 1034 task_define download_toolchain_sources "Download toolchain sources from $GIT_BASE " 1035 cmd_download_toolchain_sources () 1036 { 1037 local SUBDIRS="binutils build gcc gdb gmp gold mpfr" 1038 (mkdir -p $TOOLCHAIN_SRC_DIR && cd $TOOLCHAIN_SRC_DIR && 1039 # Create a temporary SOURCES file for the toolchain sources only 1040 # It's content will be copied to the final SOURCES file later. 1041 SOURCES_LIST=$TOOLCHAIN_SRC_DIR/SOURCES 1042 rm -f $SOURCES_LIST && touch $SOURCES_LIST 1043 for SUB in $SUBDIRS; do 1044 toolchain_clone $SUB $SOURCES_LIST 1045 done 1046 ) 1047 } 1048 1049 task_define download_ubuntu_packages_list "Download Ubuntu packages list" 1050 cmd_download_ubuntu_packages_list () 1051 { 1052 mkdir -p $DOWNLOAD_DIR 1053 get_ubuntu_packages_list "$UBUNTU_MIRROR" "$UBUNTU_RELEASE" 1054 fail_panic "Unable to download packages list, try --ubuntu-mirror=<url> to use another archive mirror" 1055 } 1056 1057 task_define download_packages "Download Ubuntu packages" 1058 task_depends download_packages download_ubuntu_packages_list 1059 cmd_download_packages () 1060 { 1061 local PACKAGE 1062 1063 rm -f $DOWNLOAD_DIR/SOURCES && touch $DOWNLOAD_DIR/SOURCES 1064 for PACKAGE in $UBUNTU_PACKAGES; do 1065 echo "Downloading $PACKAGE" 1066 local PKGURL=`get_ubuntu_package_deb_url $PACKAGE $UBUNTU_MIRROR` 1067 echo "URL: $PKGURL" 1068 download_file_to $PKGURL $DOWNLOAD_DIR 1069 fail_panic "Could not download $PACKAGE" 1070 done 1071 sha1sum $DOWNLOAD_DIR/*.deb | while read LINE; do 1072 PACKAGE=$(basename $(echo $LINE | awk '{ print $2;}')) 1073 SHA1=$(echo $LINE | awk '{ print $1; }') 1074 printf "%-64s %s\n" $PACKAGE $SHA1 >> $DOWNLOAD_DIR/SOURCES 1075 done 1076 } 1077 1078 task_define build_sysroot "Build sysroot" 1079 task_depends build_sysroot download_packages 1080 1081 cmd_build_sysroot () 1082 { 1083 local PACKAGE 1084 for PACKAGE in $UBUNTU_PACKAGES; do 1085 local PKGURL=`get_ubuntu_package_deb_url $PACKAGE $UBUNTU_MIRROR` 1086 local SRC_PKG=$DOWNLOAD_DIR/`basename $PKGURL` 1087 echo "Extracting $SRC_PKG" 1088 dpkg -x $SRC_PKG $ORG_SYSROOT_DIR/ 1089 done 1090 } 1091 1092 # Now, we need to patch libc.so which is actually a linker script 1093 # referencing /lib and /usr/lib. Do the same for libpthread.so 1094 patch_library () 1095 { 1096 echo "Patching $1" 1097 sed -i -e "s! /lib/! !g" -e "s! /usr/lib/! !g" $1 1098 } 1099 1100 # Used to setup phase 1 the run a command 1101 phase_1 () 1102 { 1103 PHASE=1 1104 $@ 1105 } 1106 1107 # Used to setup phase 2 then run a command 1108 phase_2 () 1109 { 1110 PHASE=1 1111 BINPREFIX=$(install_dir)/bin/${GCC_TARGET}- 1112 CC=${BINPREFIX}gcc 1113 CXX=${BINPREFIX}g++ 1114 LD=${BINPREFIX}ld 1115 AR=${BINPREFIX}ar 1116 AS=${BINPREFIX}as 1117 RANLIB=${BINPREFIX}ranlib 1118 STRIP=${BINPREFIX}strip 1119 export CC CXX LD AR AS RANLIB STRIP 1120 PHASE=2 1121 $@ 1122 } 1123 1124 task2_define copy_sysroot "Fix and copy sysroot" 1125 task2_depends1 copy_sysroot build_sysroot 1126 cmd_copy_sysroot () 1127 { 1128 local SL 1129 1130 # Copy the content of $BUILD_DIR/lib to $(sysroot_dir)/usr/lib 1131 copy_directory $ORG_SYSROOT_DIR/lib $(sysroot_dir)/usr/lib 1132 copy_directory $ORG_SYSROOT_DIR/usr/lib $(sysroot_dir)/usr/lib 1133 copy_directory $ORG_SYSROOT_DIR/usr/include $(sysroot_dir)/usr/include 1134 1135 # We need to fix the symlink like librt.so -> /lib/librt.so.1 1136 # in $(sysroot_dir)/usr/lib, they should point to librt.so.1 instead now. 1137 SYMLINKS=`ls -l $(sysroot_dir)/usr/lib | grep /lib/ | awk '{ print $10; }'` 1138 cd $(sysroot_dir)/usr/lib 1139 for SL in $SYMLINKS; do 1140 # convert /lib/libfoo.so.<n> into 'libfoo.so.<n>' for the target 1141 local DST=`echo $SL | sed -e 's!^/lib/!!g'` 1142 # convert libfoo.so.<n> into libfoo.so for the source 1143 local SRC=`echo $DST | sed -e 's!\.[0-9]*$!!g'` 1144 echo "Fixing symlink $SRC --> $DST" 1145 ln -sf $DST $SRC 1146 done 1147 1148 # Also deal with a few direct symlinks that don't use the /lib/ prefix 1149 # we simply copy them. Useful for libGL.so -> libGL.so.1 for example. 1150 SYMLINKS=`ls -l $(sysroot_dir)/usr/lib | grep -v /lib/ | awk '{ print $10; }'` 1151 cd $(sysroot_dir)/usr/lib 1152 for SL in $SYMLINKS; do 1153 # convert /lib/libfoo.so.<n> into 'libfoo.so.<n>' for the target 1154 local DST=`echo $SL` 1155 # convert libfoo.so.<n> into libfoo.so for the source 1156 local SRC=`echo $DST | sed -e 's!\.[0-9]*$!!g'` 1157 if [ "$DST" != "$SRC" ]; then 1158 echo "Copying symlink $SRC --> $DST" 1159 ln -sf $DST $SRC 1160 fi 1161 done 1162 1163 patch_library $(sysroot_dir)/usr/lib/libc.so 1164 patch_library $(sysroot_dir)/usr/lib/libpthread.so 1165 } 1166 1167 task_define prepare_toolchain_sources "Prepare toolchain sources." 1168 if [ -n "$GIT_BASE" -o -n "$GIT_REFERENCE" ]; then 1169 task_depends prepare_toolchain_sources download_toolchain_sources 1170 fi 1171 cmd_prepare_toolchain_sources () 1172 { 1173 return 1174 } 1175 1176 task2_define configure_binutils "Configure binutils-$BINUTILS_VERSION" 1177 task2_depends1 configure_binutils prepare_toolchain_sources 1178 task2_depends2 configure_binutils copy_sysroot 1179 cmd_configure_binutils () 1180 { 1181 OUT_DIR=$(build_binutils_dir) 1182 mkdir -p $OUT_DIR && cd $OUT_DIR && 1183 $TOOLCHAIN_SRC_DIR/binutils/binutils-$BINUTILS_VERSION/configure \ 1184 --prefix=$(install_dir) \ 1185 --with-sysroot=$(sysroot_dir) \ 1186 --target=$GCC_TARGET 1187 } 1188 1189 task2_define build_binutils "Build binutils-$BINUTILS_VERSION" 1190 task2_depends2 build_binutils configure_binutils 1191 cmd_build_binutils () 1192 { 1193 cd $(build_binutils_dir) && 1194 make $MAKE_FLAGS 1195 } 1196 1197 task2_define install_binutils "Install binutils-$BINUTILS_VERSION" 1198 task2_depends2 install_binutils build_binutils 1199 cmd_install_binutils () 1200 { 1201 cd $(build_binutils_dir) && 1202 make install 1203 } 1204 1205 task2_define extract_gmp "Extract sources for gmp-$GMP_VERSION" 1206 task2_depends1 extract_gmp prepare_toolchain_sources 1207 cmd_extract_gmp () 1208 { 1209 OUT_DIR=$(build_gmp_dir) 1210 mkdir -p $OUT_DIR && cd $OUT_DIR && 1211 tar xjf $TOOLCHAIN_SRC_DIR/gmp/gmp-$GMP_VERSION.tar.bz2 1212 } 1213 1214 task2_define configure_gmp "Configure gmp-$GMP_VERSION" 1215 task2_depends2 configure_gmp extract_gmp install_binutils 1216 cmd_configure_gmp () 1217 { 1218 export ABI=32 && 1219 cd $(build_gmp_dir) && mkdir -p build && cd build && 1220 ../gmp-$GMP_VERSION/configure --prefix=$(install_dir) --host=$GMP_TARGET --disable-shared 1221 } 1222 1223 task2_define build_gmp "Build gmp-$GMP_VERSION" 1224 task2_depends2 build_gmp configure_gmp 1225 cmd_build_gmp () 1226 { 1227 export ABI=32 && 1228 cd $(build_gmp_dir)/build && 1229 make $MAKE_FLAGS 1230 } 1231 1232 task2_define install_gmp "Install gmp-$GMP_VERSION" 1233 task2_depends2 install_gmp build_gmp 1234 cmd_install_gmp () 1235 { 1236 cd $(build_gmp_dir)/build && 1237 make install 1238 } 1239 1240 # Third, build mpfr 1241 task2_define extract_mpfr "Extract sources from mpfr-$MPFR_VERSION" 1242 task2_depends1 extract_mpfr prepare_toolchain_sources 1243 cmd_extract_mpfr () 1244 { 1245 OUT_DIR=$(build_mpfr_dir) 1246 mkdir -p $OUT_DIR && cd $OUT_DIR && 1247 tar xjf $TOOLCHAIN_SRC_DIR/mpfr/mpfr-$MPFR_VERSION.tar.bz2 1248 } 1249 1250 task2_define configure_mpfr "Configure mpfr-$MPFR_VERSION" 1251 task2_depends2 configure_mpfr extract_mpfr install_gmp 1252 cmd_configure_mpfr () 1253 { 1254 cd $(build_mpfr_dir) && mkdir -p build && cd build && 1255 ../mpfr-$MPFR_VERSION/configure \ 1256 --prefix=$(install_dir) \ 1257 --host=$GMP_TARGET \ 1258 --with-gmp=$(install_dir) \ 1259 --with-sysroot=$(sysroot_dir) \ 1260 --disable-shared 1261 } 1262 1263 task2_define build_mpfr "Build mpfr-$MPFR_VERSION" 1264 task2_depends2 build_mpfr configure_mpfr 1265 cmd_build_mpfr () 1266 { 1267 cd $(build_mpfr_dir)/build && 1268 make $MAKE_FLAGS 1269 } 1270 1271 task2_define install_mpfr "Install mpfr-$MPFR_VERSION" 1272 task2_depends2 install_mpfr build_mpfr 1273 cmd_install_mpfr () 1274 { 1275 cd $(build_mpfr_dir)/build && 1276 make install 1277 } 1278 1279 1280 # Fourth, the compiler itself 1281 task2_define configure_gcc "Configure gcc-$GCC_VERSION" 1282 task2_depends1 configure_gcc prepare_toolchain_sources 1283 task2_depends2 configure_gcc install_binutils install_gmp install_mpfr 1284 cmd_configure_gcc () 1285 { 1286 OUT_DIR=$(build_gcc_dir) 1287 mkdir -p $OUT_DIR && cd $OUT_DIR && 1288 export PATH=$(install_dir)/bin:$OLD_PATH && 1289 export CFLAGS="-m32" && 1290 export CC_FOR_TARGET="$HOST_CC" && 1291 export LD_LIBRARY_PATH=$(install_dir)/lib:$OLD_LD_LIBRARY_PATH && 1292 export LDFLAGS="-L$(install_dir)/lib" && 1293 $TOOLCHAIN_SRC_DIR/gcc/gcc-$GCC_VERSION/configure \ 1294 --prefix=$(install_dir) \ 1295 --with-sysroot=$(sysroot_dir) \ 1296 --disable-nls \ 1297 --with-gmp=$(install_dir) \ 1298 --with-mpfr=$(install_dir) \ 1299 --target=$GCC_TARGET \ 1300 --disable-plugin \ 1301 --disable-docs \ 1302 --enable-languages=c,c++ 1303 } 1304 1305 task2_define build_gcc "Build gcc-$GCC_VERSION" 1306 task2_depends2 build_gcc configure_gcc 1307 cmd_build_gcc () 1308 { 1309 export PATH=$(install_dir)/bin:$OLD_PATH && 1310 export LD_LIBRARY_PATH=$(install_dir)/lib:$OLD_LD_LIBRARY_PATH && 1311 cd $(build_gcc_dir) && 1312 make $MAKE_FLAGS 1313 } 1314 1315 task2_define install_gcc "Install gcc-$GCC_VERSION" 1316 task2_depends2 install_gcc build_gcc 1317 cmd_install_gcc () 1318 { 1319 export PATH=$(install_dir)/bin:$OLD_PATH && 1320 export LD_LIBRARY_PATH=$(install_dir)/lib:$OLD_LD_LIBRARY_PATH && 1321 cd $(build_gcc_dir) && 1322 make install 1323 } 1324 1325 task2_define cleanup_toolchain "Cleanup toolchain" 1326 task2_depends2 cleanup_toolchain install_gcc 1327 cmd_cleanup_toolchain () 1328 { 1329 # Remove un-needed directories and files 1330 rm -rf $(install_dir)/share 1331 rm -rf $(install_dir)/man 1332 rm -rf $(install_dir)/info 1333 rm -rf $(install_dir)/lib32 1334 rm -rf $(install_dir)/libexec/*/*/install-tools 1335 1336 (strip $(install_dir)/bin/*) 1337 true 1338 } 1339 1340 task2_define package_toolchain "Package final toolchain" 1341 task2_depends2 package_toolchain cleanup_toolchain 1342 cmd_package_toolchain () 1343 { 1344 # Copy this script to the install directory 1345 cp -f $0 $(install_dir) 1346 fail_panic "Could not copy build script to install directory" 1347 1348 # Copy the SOURCES file as well 1349 cp $DOWNLOAD_DIR/SOURCES $(install_dir)/PACKAGE_SOURCES && 1350 cp $TOOLCHAIN_SRC_DIR/SOURCES $(install_dir)/TOOLCHAIN_SOURCES 1351 fail_panic "Could not copy SOURCES files to install directory" 1352 1353 # Package everything 1354 pack_archive $TOOLCHAIN_ARCHIVE "`dirname $(install_dir)`" "`basename $(install_dir)`" 1355 } 1356 1357 task2_define install_toolchain "Install final toolchain" 1358 task2_depends2 install_toolchain cleanup_toolchain 1359 cmd_install_toolchain () 1360 { 1361 copy_directory "$(install_dir)" "$PREFIX_DIR/$TOOLCHAIN_NAME" 1362 cp -f $0 "$PREFIX_DIR/$TOOLCHAIN_NAME/" 1363 } 1364 1365 # Get sure that the second toolchain depends on the first one 1366 task_depends configure_binutils_2 install_gcc_1 1367 1368 if [ "$ONLY_SYSROOT" = "yes" ]; then 1369 do_task copy_sysroot 1370 echo "Done, see sysroot files in $(sysroot_dir)" 1371 elif [ -n "$PREFIX_DIR" ]; then 1372 if [ -z "$BOOTSTRAP" ]; then 1373 do_task install_toolchain_1 1374 else 1375 do_task install_toolchain_2 1376 fi 1377 echo "Done, see $PREFIX_DIR/$TOOLCHAIN_NAME" 1378 else 1379 if [ -z "$BOOTSTRAP" ]; then 1380 do_task package_toolchain_1 1381 else 1382 do_task package_toolchain_2 1383 fi 1384 echo "Done, see $TOOLCHAIN_ARCHIVE" 1385 fi 1386