scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Jul 13 10:32:38 2008 +0000 (2008-07-13)
changeset 645 8e58024f8e37
parent 582 522e4fe1ca75
child 646 e0cc6a00953e
permissions -rw-r--r--
Ioannis E. VENETIS <venetis@mail.capsl.udel.edu> pointed out that GMP and MPFR were not used by gcc.
Turned out that none could use GMP and MPFR as the config option changed its name, but the change was not propagated to all users.

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