scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Feb 17 22:08:06 2008 +0000 (2008-02-17)
changeset 431 8bde4c6ea47a
parent 412 e1cc03fb2794
child 439 dd62fca2d6fd
permissions -rw-r--r--
Robert P. J. DAY says:

apparently, the patchset for gcc 4.2.1 applies properly to the
source for gcc 4.2.2 and gcc 4.2.3. so, if you want, you can simply
add support for those last two just by augmenting menuconfig and
adding a couple symlinks for those two directories. seems like a
cheap way to add a couple new versions.
     1 # This file contains some usefull common functions
     2 # Copyright 2007 Yann E. MORIN
     3 # Licensed under the GPL v2. See COPYING in the root of this package
     4 
     5 # Prepare the fault handler
     6 CT_OnError() {
     7     ret=$?
     8     CT_DoLog ERROR "Build failed in step \"${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}\""
     9     for((step=(CT_STEP_COUNT-1); step>1; step--)); do
    10         CT_DoLog ERROR "      called in step \"${CT_STEP_MESSAGE[${step}]}\""
    11     done
    12     CT_DoLog ERROR "Error happened in \"${BASH_SOURCE[1]}\" in function \"${FUNCNAME[1]}\" (line unknown, sorry)"
    13     for((depth=2; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
    14         CT_DoLog ERROR "      called from \"${BASH_SOURCE[${depth}]}\" at line # ${BASH_LINENO[${depth}-1]} in function \"${FUNCNAME[${depth}]}\""
    15     done
    16     [ "${CT_LOG_TO_FILE}" = "y" ] && CT_DoLog ERROR "Look at \"${CT_LOG_FILE}\" for more info on this error."
    17     CT_STEP_COUNT=1
    18     CT_DoEnd ERROR
    19     exit $ret
    20 }
    21 
    22 # Install the fault handler
    23 trap CT_OnError ERR
    24 
    25 # Inherit the fault handler in subshells and functions
    26 set -E
    27 
    28 # Make pipes fail on the _first_ failed command
    29 # Not supported on bash < 3.x, but we need it, so drop the obsoleting bash-2.x
    30 set -o pipefail
    31 
    32 # Don't hash commands' locations, and search every time it is requested.
    33 # This is slow, but needed because of the static/shared core gcc which shall
    34 # always match to shared if it exists, and only fallback to static if the
    35 # shared is not found
    36 set +o hashall
    37 
    38 # Log policy:
    39 #  - first of all, save stdout so we can see the live logs: fd #6
    40 exec 6>&1
    41 #  - then point stdout to the log file (temporary for now)
    42 tmp_log_file="${CT_TOP_DIR}/log.$$"
    43 exec >>"${tmp_log_file}"
    44 
    45 # The different log levels:
    46 CT_LOG_LEVEL_ERROR=0
    47 CT_LOG_LEVEL_WARN=1
    48 CT_LOG_LEVEL_INFO=2
    49 CT_LOG_LEVEL_EXTRA=3
    50 CT_LOG_LEVEL_DEBUG=4
    51 CT_LOG_LEVEL_ALL=5
    52 
    53 # A function to log what is happening
    54 # Different log level are available:
    55 #   - ERROR:   A serious, fatal error occurred
    56 #   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
    57 #   - INFO:    Informational messages
    58 #   - EXTRA:   Extra informational messages
    59 #   - DEBUG:   Debug messages
    60 #   - ALL:     Component's build messages
    61 # Usage: CT_DoLog <level> [message]
    62 # If message is empty, then stdin will be logged.
    63 CT_DoLog() {
    64     local max_level LEVEL level cur_l cur_L
    65     local l
    66     eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
    67     # Set the maximum log level to DEBUG if we have none
    68     [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
    69 
    70     LEVEL="$1"; shift
    71     eval level="\${CT_LOG_LEVEL_${LEVEL}}"
    72 
    73     if [ $# -eq 0 ]; then
    74         cat -
    75     else
    76         echo "${1}"
    77     fi |( IFS="\n" # We want the full lines, even leading spaces
    78           CT_PROG_BAR_CPT=0
    79           indent=$((2*CT_STEP_COUNT))
    80           while read line; do
    81               case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
    82                 y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
    83                 y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
    84                 *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
    85                 *"make["?*"]:"*"Stop.") cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
    86                 *)                      cur_L="${LEVEL}"; cur_l="${level}";;
    87               esac
    88               l="`printf \"[%-5s]%*s%s%s\" \"${cur_L}\" \"${indent}\" \" \" \"${line}\"`"
    89               # There will always be a log file, be it /dev/null
    90               echo -e "${l}"
    91               if [ ${cur_l} -le ${max_level} ]; then
    92                   echo -e "\r${l}" >&6
    93               fi
    94               if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
    95                   [ ${CT_PROG_BAR_CPT} -eq 0  ] && bar="/"
    96                   [ ${CT_PROG_BAR_CPT} -eq 10 ] && bar="-"
    97                   [ ${CT_PROG_BAR_CPT} -eq 20 ] && bar="\\"
    98                   [ ${CT_PROG_BAR_CPT} -eq 30 ] && bar="|"
    99                   printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${bar}" >&6
   100                   CT_PROG_BAR_CPT=$(((CT_PROG_BAR_CPT+1)%40))
   101               fi
   102           done
   103         )
   104 
   105     return 0
   106 }
   107 
   108 # Tail message to be logged whatever happens
   109 # Usage: CT_DoEnd <level>
   110 CT_DoEnd()
   111 {
   112     local level="$1"
   113     CT_STOP_DATE=`CT_DoDate +%s%N`
   114     CT_STOP_DATE_HUMAN=`CT_DoDate +%Y%m%d.%H%M%S`
   115     CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
   116     elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
   117     elapsed_min=$((elapsed/(60*1000*1000*1000)))
   118     elapsed_sec=`printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000)))`
   119     elapsed_csec=`printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000)))`
   120     CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
   121 }
   122 
   123 # Abort the execution with an error message
   124 # Usage: CT_Abort <message>
   125 CT_Abort() {
   126     CT_DoLog ERROR "$1"
   127     exit 1
   128 }
   129 
   130 # Test a condition, and print a message if satisfied
   131 # Usage: CT_Test <message> <tests>
   132 CT_Test() {
   133     local ret
   134     local m="$1"
   135     shift
   136     test "$@" && CT_DoLog WARN "$m"
   137     return 0
   138 }
   139 
   140 # Test a condition, and abort with an error message if satisfied
   141 # Usage: CT_TestAndAbort <message> <tests>
   142 CT_TestAndAbort() {
   143     local m="$1"
   144     shift
   145     test "$@" && CT_Abort "$m"
   146     return 0
   147 }
   148 
   149 # Test a condition, and abort with an error message if not satisfied
   150 # Usage: CT_TestAndAbort <message> <tests>
   151 CT_TestOrAbort() {
   152     local m="$1"
   153     shift
   154     test "$@" || CT_Abort "$m"
   155     return 0
   156 }
   157 
   158 # Test the presence of a tool, or abort if not found
   159 # Usage: CT_HasOrAbort <tool>
   160 CT_HasOrAbort() {
   161     CT_TestAndAbort "\"${1}\" not found and needed for successful toolchain build." -z "`CT_Which \"${1}\"`"
   162     return 0
   163 }
   164 
   165 # Search a program: wrap "which" for those system where
   166 # "which" verbosely says there is no match (Mdk are such
   167 # suckers...)
   168 # Usage: CT_Which <filename>
   169 CT_Which() {
   170   which "$1" 2>/dev/null || true
   171 }
   172 
   173 # Get current date with nanosecond precision
   174 # On those system not supporting nanosecond precision, faked with rounding down
   175 # to the highest entire second
   176 # Usage: CT_DoDate <fmt>
   177 CT_DoDate() {
   178     date "$1" |sed -r -e 's/%N$/000000000/;'
   179 }
   180 
   181 CT_STEP_COUNT=1
   182 CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
   183 # Memorise a step being done so that any error is caught
   184 # Usage: CT_DoStep <loglevel> <message>
   185 CT_DoStep() {
   186     local start=`CT_DoDate +%s%N`
   187     CT_DoLog "$1" "================================================================="
   188     CT_DoLog "$1" "$2"
   189     CT_STEP_COUNT=$((CT_STEP_COUNT+1))
   190     CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
   191     CT_STEP_START[${CT_STEP_COUNT}]="${start}"
   192     CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
   193     return 0
   194 }
   195 
   196 # End the step just being done
   197 # Usage: CT_EndStep
   198 CT_EndStep() {
   199     local stop=`CT_DoDate +%s%N`
   200     local duration=`printf "%032d" $((stop-${CT_STEP_START[${CT_STEP_COUNT}]})) |sed -r -e 's/([[:digit:]]{2})[[:digit:]]{7}$/\.\1/; s/^0+//; s/^\./0\./;'`
   201     local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
   202     local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
   203     CT_STEP_COUNT=$((CT_STEP_COUNT-1))
   204     CT_DoLog "${level}" "${message}: done in ${duration}s"
   205     return 0
   206 }
   207 
   208 # Pushes into a directory, and pops back
   209 CT_Pushd() {
   210     pushd "$1" >/dev/null 2>&1
   211 }
   212 CT_Popd() {
   213     popd >/dev/null 2>&1
   214 }
   215 
   216 # Makes a path absolute
   217 # Usage: CT_MakeAbsolutePath path
   218 CT_MakeAbsolutePath() {
   219     # Try to cd in that directory
   220     if [ -d "$1" ]; then
   221         CT_Pushd "$1"
   222         pwd
   223         CT_Popd
   224     else
   225         # No such directory, fail back to guessing
   226         case "$1" in
   227             /*)  echo "$1";;
   228             *)   echo "`pwd`/$1";;
   229         esac
   230     fi
   231     
   232     return 0
   233 }
   234 
   235 # Creates a temporary directory
   236 # $1: variable to assign to
   237 # Usage: CT_MktempDir foo
   238 CT_MktempDir() {
   239     # Some mktemp do not allow more than 6 Xs
   240     eval "$1"="`mktemp -q -d \"${CT_BUILD_DIR}/.XXXXXX\"`"
   241     CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
   242 }
   243 
   244 # Echoes the specified string on stdout until the pipe breaks.
   245 # Doesn't fail
   246 # $1: string to echo
   247 # Usage: CT_DoYes "" |make oldconfig
   248 CT_DoYes() {
   249     yes "$1" || true
   250 }
   251 
   252 # Get the file name extension of a component
   253 # Usage: CT_GetFileExtension <component_name-component_version>
   254 # If found, echoes the extension to stdout
   255 # If not found, echoes nothing on stdout.
   256 CT_GetFileExtension() {
   257     local ext
   258     local file="$1"
   259 
   260     CT_Pushd "${CT_TARBALLS_DIR}"
   261     # we need to also check for an empty extension for those very
   262     # peculiar components that don't have one (such as sstrip from
   263     # buildroot).
   264     for ext in .tar.gz .tar.bz2 .tgz .tar ''; do
   265         if [ -f "${file}${ext}" ]; then
   266             echo "${ext}"
   267             break
   268         fi
   269     done
   270     CT_Popd
   271 
   272     return 0
   273 }
   274 
   275 # Download an URL using wget
   276 # Usage: CT_DoGetFileWget <URL>
   277 CT_DoGetFileWget() {
   278     # Need to return true because it is legitimate to not find the tarball at
   279     # some of the provided URLs (think about snapshots, different layouts for
   280     # different gcc versions, etc...)
   281     # Some (very old!) FTP server might not support the passive mode, thus
   282     # retry without
   283     # With automated download as we are doing, it can be very dangerous to use
   284     # -c to continue the downloads. It's far better to simply overwrite the
   285     # destination file
   286     wget -nc --progress=dot:binary --tries=3 --passive-ftp "$1" || wget -nc --progress=dot:binary --tries=3 "$1" || true
   287 }
   288 
   289 # Download an URL using curl
   290 # Usage: CT_DoGetFileCurl <URL>
   291 CT_DoGetFileCurl() {
   292 	# Note: comments about wget method are also valid here
   293 	# Plus: no good progreess indicator is available with curl,
   294 	#       so output is consigned to oblivion
   295 	curl --ftp-pasv -O --retry 3 "$1" >/dev/null || curl -O --retry 3 "$1" >/dev/null || true
   296 }
   297 
   298 _wget=`CT_Which wget`
   299 _curl=`CT_Which curl`
   300 # Wrapper function to call one of curl or wget
   301 # Usage: CT_DoGetFile <URL>
   302 CT_DoGetFile() {
   303     case "${_wget},${_curl}" in
   304         ,)  CT_DoError "Could find neither wget nor curl";;
   305         ,*) CT_DoGetFileCurl "$1" 2>&1 |CT_DoLog ALL;;
   306         *)  CT_DoGetFileWget "$1" 2>&1 |CT_DoLog ALL;;
   307     esac
   308 }
   309 
   310 # Download the file from one of the URLs passed as argument
   311 # Usage: CT_GetFile <filename> [extension] <url> [url ...]
   312 CT_GetFile() {
   313     local ext
   314     local url
   315     local file="$1"
   316     local first_ext=""
   317     shift
   318     case "$1" in
   319         .tar.bz2|.tar.gz|.tgz|.tar)
   320             first_ext="$1"
   321             shift
   322             ;;
   323     esac
   324 
   325     # Do we already have it?
   326     ext=`CT_GetFileExtension "${file}"`
   327     if [ -n "${ext}" ]; then
   328         CT_DoLog DEBUG "Already have \"${file}\""
   329         return 0
   330     fi
   331 
   332     CT_Pushd "${CT_TARBALLS_DIR}"
   333     # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
   334     # or, as a failover, a file without extension.
   335     # Try local copy first, if it exists
   336     for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
   337         CT_DoLog DEBUG "Trying \"${CT_LOCAL_TARBALLS_DIR}/${file}${ext}\""
   338         if [ -r "${CT_LOCAL_TARBALLS_DIR}/${file}${ext}" -a \
   339              "${CT_FORCE_DOWNLOAD}" != "y" ]; then
   340             CT_DoLog EXTRA "Using \"${file}\" from local storage"
   341             ln -sv "${CT_LOCAL_TARBALLS_DIR}/${file}${ext}" "${file}${ext}" |CT_DoLog ALL
   342             return 0
   343         fi
   344     done
   345     # Try to download it
   346     CT_DoLog EXTRA "Retrieving \"${file}\" from network"
   347     for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
   348         # Try all urls in turn
   349         for url in "$@"; do
   350             CT_DoLog DEBUG "Trying \"${url}/${file}${ext}\""
   351             CT_DoGetFile "${url}/${file}${ext}"
   352             if [ -f "${file}${ext}" ]; then
   353                 # No need to test if the file already exists because
   354                 # it does NOT. If it did exist, we'd have been stopped
   355                 # above, when looking for local copies.
   356                 if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
   357                     CT_DoLog EXTRA "Saving \"${file}\" to local storage"
   358                     mv "${file}${ext}" "${CT_LOCAL_TARBALLS_DIR}" |CT_DoLog ALL
   359                     ln -sv "${CT_LOCAL_TARBALLS_DIR}/${file}${ext}" "${file}${ext}" |CT_DoLog ALL
   360                 fi
   361                 return 0
   362             fi
   363         done
   364     done
   365     CT_Popd
   366 
   367     CT_Abort "Could not download \"${file}\", and not present in \"${CT_LOCAL_TARBALLS_DIR}\""
   368 }
   369 
   370 # Extract a tarball and patch the resulting sources if necessary.
   371 # Some tarballs need to be extracted in specific places. Eg.: glibc addons
   372 # must be extracted in the glibc directory; uCLibc locales must be extracted
   373 # in the extra/locale sub-directory of uClibc.
   374 CT_ExtractAndPatch() {
   375     local file="$1"
   376     local base_file=`echo "${file}" |cut -d - -f 1`
   377     local ver_file=`echo "${file}" |cut -d - -f 2-`
   378     local official_patch_dir
   379     local custom_patch_dir
   380     local libc_addon
   381     local ext=`CT_GetFileExtension "${file}"`
   382     CT_TestAndAbort "\"${file}\" not found in \"${CT_TARBALLS_DIR}\"" -z "${ext}"
   383     local full_file="${CT_TARBALLS_DIR}/${file}${ext}"
   384 
   385     CT_Pushd "${CT_SRC_DIR}"
   386 
   387     # Add-ons need a little love, really.
   388     case "${file}" in
   389         glibc-[a-z]*-*)
   390             CT_TestAndAbort "Trying to extract the C-library addon/locales \"${file}\" when C-library not yet extracted" ! -d "${CT_LIBC_FILE}"
   391             cd "${CT_LIBC_FILE}"
   392             libc_addon=y
   393             [ -f ".${file}.extracted" ] && return 0
   394             touch ".${file}.extracted"
   395             ;;
   396         uClibc-locale-*)
   397             CT_TestAndAbort "Trying to extract the C-library addon/locales \"${file}\" when C-library not yet extracted" ! -d "${CT_LIBC_FILE}"
   398             cd "${CT_LIBC_FILE}/extra/locale"
   399             libc_addon=y
   400             [ -f ".${file}.extracted" ] && return 0
   401             touch ".${file}.extracted"
   402             ;;
   403     esac
   404 
   405     # If the directory exists, then consider extraction and patching done
   406     if [ -d "${file}" ]; then
   407         CT_DoLog DEBUG "Already extracted \"${file}\""
   408         return 0
   409     fi
   410 
   411     CT_DoLog EXTRA "Extracting \"${file}\""
   412     case "${ext}" in
   413         .tar.bz2)     tar xvjf "${full_file}" |CT_DoLog ALL;;
   414         .tar.gz|.tgz) tar xvzf "${full_file}" |CT_DoLog ALL;;
   415         .tar)         tar xvf  "${full_file}" |CT_DoLog ALL;;
   416         *)            CT_Abort "Don't know how to handle \"${file}\": unknown extension" ;;
   417     esac
   418 
   419     # Snapshots might not have the version number in the extracted directory
   420     # name. This is also the case for some (odd) packages, such as D.U.M.A.
   421     # Overcome this issue by symlink'ing the directory.
   422     if [ ! -d "${file}" -a "${libc_addon}" != "y" ]; then
   423         case "${ext}" in
   424             .tar.bz2)     base=`tar tjf "${full_file}" |head -n 1 |cut -d / -f 1 || true`;;
   425             .tar.gz|.tgz) base=`tar tzf "${full_file}" |head -n 1 |cut -d / -f 1 || true`;;
   426             .tar)         base=`tar tf  "${full_file}" |head -n 1 |cut -d / -f 1 || true`;;
   427         esac
   428         CT_TestOrAbort "There was a problem when extracting \"${file}\"" -d "${base}" -o "${base}" != "${file}"
   429         ln -s "${base}" "${file}"
   430     fi
   431 
   432     # Kludge: outside this function, we wouldn't know if we had just extracted
   433     # a libc addon, or a plain package. Apply patches now.
   434     CT_DoLog EXTRA "Patching \"${file}\""
   435 
   436     if [ "${libc_addon}" = "y" ]; then
   437         # Some addons tarball directly contian the correct addon directory,
   438         # while others have the addon directory named ofter the tarball.
   439         # Fix that by always using the short name (eg: linuxthreads, ports, etc...)
   440         addon_short_name=`echo "${file}" |sed -r -e 's/^[^-]+-//; s/-[^-]+$//;'`
   441         [ -d "${addon_short_name}" ] || ln -s "${file}" "${addon_short_name}"
   442         # If libc addon, we're already in the correct place
   443     else
   444         cd "${file}"
   445     fi
   446 
   447     official_patch_dir=
   448     custom_patch_dir=
   449     [ "${CUSTOM_PATCH_ONLY}" = "y" ] || official_patch_dir="${CT_LIB_DIR}/patches/${base_file}/${ver_file}"
   450     [ "${CT_CUSTOM_PATCH}" = "y" ] && custom_patch_dir="${CT_CUSTOM_PATCH_DIR}/${base_file}/${ver_file}"
   451     for patch_dir in "${official_patch_dir}" "${custom_patch_dir}"; do
   452         if [ -n "${patch_dir}" -a -d "${patch_dir}" ]; then
   453             for p in "${patch_dir}"/*.patch; do
   454                 if [ -f "${p}" ]; then
   455                     CT_DoLog DEBUG "Applying patch \"${p}\""
   456                     patch -g0 -F1 -p1 -f <"${p}" |CT_DoLog ALL
   457                     CT_TestAndAbort "Failed while applying patch file \"${p}\"" ${PIPESTATUS[0]} -ne 0
   458                 fi
   459             done
   460         fi
   461     done
   462 
   463     CT_Popd
   464 }
   465 
   466 # Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
   467 # Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
   468 CT_DoConfigGuess() {
   469     if [ -x "${CT_TOP_DIR}/tools/config.guess" ]; then
   470         "${CT_TOP_DIR}/tools/config.guess"
   471     else
   472         "${CT_LIB_DIR}/tools/config.guess"
   473     fi
   474 }
   475 
   476 CT_DoConfigSub() {
   477     if [ -x "${CT_TOP_DIR}/tools/config.sub" ]; then
   478         "${CT_TOP_DIR}/tools/config.sub" "$@"
   479     else
   480         "${CT_LIB_DIR}/tools/config.sub" "$@"
   481     fi
   482 }
   483 
   484 # Compute the target tuple from what is provided by the user
   485 # Usage: CT_DoBuildTargetTuple
   486 # In fact this function takes the environment variables to build the target
   487 # tuple. It is needed both by the normal build sequence, as well as the
   488 # sample saving sequence.
   489 CT_DoBuildTargetTuple() {
   490     # Set the endianness suffix, and the default endianness gcc option
   491     case "${CT_ARCH_BE},${CT_ARCH_LE}" in
   492         y,) target_endian_eb=eb
   493             target_endian_el=
   494             CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
   495             ;;
   496         ,y) target_endian_eb=
   497             target_endian_el=el
   498             CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
   499             ;;
   500     esac
   501 
   502     # Set defaults for the system part of the tuple. Can be overriden
   503     # by architecture-specific values.
   504     case "${CT_LIBC}" in
   505         glibc)  CT_TARGET_SYS=gnu;;
   506         uClibc) CT_TARGET_SYS=uclibc;;
   507     esac
   508 
   509     # Transform the ARCH into a kernel-understandable ARCH
   510     CT_KERNEL_ARCH="${CT_ARCH}"
   511 
   512     # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
   513     unset CT_ARCH_ARCH_CFLAG CT_ARCH_ABI_CFLAG CT_ARCH_CPU_CFLAG CT_ARCH_TUNE_CFLAG CT_ARCH_FPU_CFLAG
   514     unset CT_ARCH_WITH_ARCH CT_ARCH_WITH_ABI CT_ARCH_WITH_CPU CT_ARCH_WITH_TUNE CT_ARCH_WITH_FPU
   515     [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
   516     [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
   517     [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
   518     [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
   519     [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
   520     [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float";           CT_ARCH_WITH_FLOAT="--with-float=soft";          }
   521 
   522     # Call the architecture specific settings
   523     CT_DoArchValues
   524 
   525     # Finish the target tuple construction
   526     case "${CT_KERNEL}" in
   527         linux*)  CT_TARGET_KERNEL=linux;;
   528     esac
   529     CT_TARGET=`CT_DoConfigSub "${CT_TARGET_ARCH}-${CT_TARGET_VENDOR:-unknown}-${CT_TARGET_KERNEL}-${CT_TARGET_SYS}"`
   530 
   531     # Prepare the target CFLAGS
   532     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_ARCH_CFLAG}"
   533     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
   534     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
   535     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
   536     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
   537     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
   538 }
   539 
   540 # This function does pause the build until the user strikes "Return"
   541 # Usage: CT_DoPause [optional_message]
   542 CT_DoPause() {
   543     local foo
   544     local message="${1:-Pausing for your pleasure}"
   545     CT_DoLog INFO "${message}"
   546     read -p "Press \"Enter\" to continue, or Ctrl-C to stop..." foo >&6
   547     return 0
   548 }
   549 
   550 # This function saves the state of the toolchain to be able to restart
   551 # at any one point
   552 # Usage: CT_DoSaveState <next_step_name>
   553 CT_DoSaveState() {
   554 	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
   555     local state_name="$1"
   556     local state_dir="${CT_STATE_DIR}/${state_name}"
   557 
   558     CT_DoLog DEBUG "Saving state to restart at step \"${state_name}\"..."
   559     rm -rf "${state_dir}"
   560     mkdir -p "${state_dir}"
   561 
   562     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   563         y)  tar_opt=z; tar_ext=.gz;;
   564         *)  tar_opt=;  tar_ext=;;
   565     esac
   566 
   567     CT_DoLog DEBUG "  Saving environment and aliases"
   568     # We must omit shell functions
   569     set |awk '
   570          BEGIN { _p = 1; }
   571          $0~/^[^ ]+ \(\)/ { _p = 0; }
   572          _p == 1
   573          $0 == "}" { _p = 1; }
   574          ' >"${state_dir}/env.sh"
   575 
   576     CT_DoLog DEBUG "  Saving CT_CC_CORE_STATIC_PREFIX_DIR=\"${CT_CC_CORE_STATIC_PREFIX_DIR}\""
   577     CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   578     tar cv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" . |CT_DoLog DEBUG
   579     CT_Popd
   580 
   581     CT_DoLog DEBUG "  Saving CT_CC_CORE_SHARED_PREFIX_DIR=\"${CT_CC_CORE_SHARED_PREFIX_DIR}\""
   582     CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
   583     tar cv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" . |CT_DoLog DEBUG
   584     CT_Popd
   585 
   586     CT_DoLog DEBUG "  Saving CT_PREFIX_DIR=\"${CT_PREFIX_DIR}\""
   587     CT_Pushd "${CT_PREFIX_DIR}"
   588     tar cv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" --exclude '*.log' . |CT_DoLog DEBUG
   589     CT_Popd
   590 
   591     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
   592         CT_DoLog DEBUG "  Saving log file"
   593         exec >/dev/null
   594         case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   595             y)  gzip -3 -c "${CT_LOG_FILE}"  >"${state_dir}/log.gz";;
   596             *)  cat "${CT_LOG_FILE}" >"${state_dir}/log";;
   597         esac
   598         exec >>"${CT_LOG_FILE}"
   599     fi
   600 }
   601 
   602 # This function restores a previously saved state
   603 # Usage: CT_DoLoadState <state_name>
   604 CT_DoLoadState(){
   605     local state_name="$1"
   606     local state_dir="${CT_STATE_DIR}/${state_name}"
   607     local old_RESTART="${CT_RESTART}"
   608     local old_STOP="${CT_STOP}"
   609 
   610     CT_TestOrAbort "The previous build did not reach the point where it could be restarted at \"${CT_RESTART}\"" -d "${state_dir}"
   611 
   612     # We need to do something special with the log file!
   613     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
   614         exec >"${state_dir}/tail.log"
   615     fi
   616     CT_DoLog INFO "Restoring state at step \"${state_name}\", as requested."
   617 
   618     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   619         y)  tar_opt=z; tar_ext=.gz;;
   620         *)  tar_opt=;  tar_ext=;;
   621     esac
   622 
   623     CT_DoLog DEBUG "  Removing previous build directories"
   624     chmod -R u+rwX "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   625     rm -rf         "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   626     mkdir -p       "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   627 
   628     CT_DoLog DEBUG "  Restoring CT_PREFIX_DIR=\"${CT_PREFIX_DIR}\""
   629     CT_Pushd "${CT_PREFIX_DIR}"
   630     tar xv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
   631     CT_Popd
   632 
   633     CT_DoLog DEBUG "  Restoring CT_CC_CORE_SHARED_PREFIX_DIR=\"${CT_CC_CORE_SHARED_PREFIX_DIR}\""
   634     CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
   635     tar xv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
   636     CT_Popd
   637 
   638     CT_DoLog DEBUG "  Restoring CT_CC_CORE_STATIC_PREFIX_DIR=\"${CT_CC_CORE_STATIC_PREFIX_DIR}\""
   639     CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   640     tar xv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
   641     CT_Popd
   642 
   643     # Restore the environment, discarding any error message
   644     # (for example, read-only bash internals)
   645     CT_DoLog DEBUG "  Restoring environment"
   646     . "${state_dir}/env.sh" >/dev/null 2>&1 || true
   647 
   648     # Restore the new RESTART and STOP steps
   649     CT_RESTART="${old_RESTART}"
   650     CT_STOP="${old_STOP}"
   651     unset old_stop old_restart
   652 
   653     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
   654         CT_DoLog DEBUG "  Restoring log file"
   655         exec >/dev/null
   656         case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   657             y)  zcat "${state_dir}/log.gz" >"${CT_LOG_FILE}";;
   658             *)  cat "${state_dir}/log" >"${CT_LOG_FILE}";;
   659         esac
   660         cat "${state_dir}/tail.log" >>"${CT_LOG_FILE}"
   661         exec >>"${CT_LOG_FILE}"
   662         rm -f "${state_dir}/tail.log"
   663     fi
   664 }