scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Jul 17 17:56:22 2011 +0200 (2011-07-17)
changeset 2889 f3b2199620f1
parent 2807 4193d6e6a174
child 2898 7e0af0188fc3
permissions -rw-r--r--
cc/gcc: pass the install prefix to the core passes

Currently, the discrimination on the core compilers prefixes depends on
the type of core compiler to build.

This is not correct, and the caller of the core backend should specify
the prefix.

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
     1 # This file contains some usefull common functions -*- sh -*-
     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     local ret=$?
     8     local intro
     9     local file line func
    10     local step step_depth
    11 
    12     # To avoid printing the backtace for each sub-shell
    13     # up to the top-level, just remember we've dumped it
    14     if [ ! -f "${CT_BUILD_DIR}/backtrace" ]; then
    15         touch "${CT_BUILD_DIR}/backtrace"
    16 
    17         # Print steps backtrace
    18         step_depth=${CT_STEP_COUNT}
    19         CT_STEP_COUNT=1     # To have a zero-indentation
    20         CT_DoLog ERROR ""
    21         CT_DoLog ERROR ">>"
    22         intro="Build failed"
    23         for((step=step_depth; step>0; step--)); do
    24             CT_DoLog ERROR ">>  ${intro} in step '${CT_STEP_MESSAGE[${step}]}'"
    25             intro="      called"
    26         done
    27 
    28         # Print functions backtrace
    29         intro="Error happened in"
    30         CT_DoLog ERROR ">>"
    31         for((depth=1; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
    32             file="${BASH_SOURCE[${depth}]#${CT_LIB_DIR}/}"
    33             func="${FUNCNAME[${depth}]}"
    34             line="@${BASH_LINENO[${depth}-1]:-?}"
    35             CT_DoLog ERROR ">>  ${intro}: ${func}[${file}${line}]"
    36             intro="      called from"
    37         done
    38     fi
    39 
    40     # And finally, in top-level shell, print some hints
    41     if [ ${BASH_SUBSHELL} -eq 0 ]; then
    42         # Help diagnose the error
    43         CT_STEP_COUNT=1     # To have a zero-indentation
    44         CT_DoLog ERROR ">>"
    45         if [ "${CT_LOG_TO_FILE}" = "y" ]; then
    46             CT_DoLog ERROR ">>  For more info on this error, look at the file: '${tmp_log_file#${CT_TOP_DIR}/}'"
    47         fi
    48         CT_DoLog ERROR ">>  There is a list of known issues, some with workarounds, in:"
    49         CT_DoLog ERROR ">>      '${CT_DOC_DIR#${CT_TOP_DIR}/}/B - Known issues.txt'"
    50 
    51         CT_DoLog ERROR ""
    52         CT_DoEnd ERROR
    53         rm -f "${CT_BUILD_DIR}/backtrace"
    54     fi
    55     exit $ret
    56 }
    57 
    58 # Install the fault handler
    59 trap CT_OnError ERR
    60 
    61 # Inherit the fault handler in subshells and functions
    62 set -E
    63 
    64 # Make pipes fail on the _first_ failed command
    65 # Not supported on bash < 3.x, but we need it, so drop the obsoleting bash-2.x
    66 set -o pipefail
    67 
    68 # Don't hash commands' locations, and search every time it is requested.
    69 # This is slow, but needed because of the static/shared core gcc which shall
    70 # always match to shared if it exists, and only fallback to static if the
    71 # shared is not found
    72 set +o hashall
    73 
    74 # Log policy:
    75 #  - first of all, save stdout so we can see the live logs: fd #6
    76 exec 6>&1
    77 #  - then point stdout to the log file
    78 tmp_log_file="${CT_TOP_DIR}/build.log"
    79 rm -f "${tmp_log_file}"
    80 exec >>"${tmp_log_file}"
    81 
    82 # The different log levels:
    83 CT_LOG_LEVEL_ERROR=0
    84 CT_LOG_LEVEL_WARN=1
    85 CT_LOG_LEVEL_INFO=2
    86 CT_LOG_LEVEL_EXTRA=3
    87 CT_LOG_LEVEL_CFG=4
    88 CT_LOG_LEVEL_FILE=5
    89 CT_LOG_LEVEL_STATE=6
    90 CT_LOG_LEVEL_ALL=7
    91 CT_LOG_LEVEL_DEBUG=8
    92 
    93 # Make it easy to use \n and !
    94 CR=$(printf "\n")
    95 BANG='!'
    96 
    97 # A function to log what is happening
    98 # Different log level are available:
    99 #   - ERROR:   A serious, fatal error occurred
   100 #   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
   101 #   - INFO:    Informational messages
   102 #   - EXTRA:   Extra informational messages
   103 #   - CFG:     Output of various "./configure"-type scripts
   104 #   - FILE:    File / archive unpacking.
   105 #   - STATE:   State save & restore
   106 #   - ALL:     Component's build messages
   107 #   - DEBUG:   Internal debug messages
   108 # Usage: CT_DoLog <level> [message]
   109 # If message is empty, then stdin will be logged.
   110 CT_DoLog() {
   111     local max_level LEVEL level cur_l cur_L
   112     local l
   113     eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
   114     # Set the maximum log level to DEBUG if we have none
   115     [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
   116 
   117     LEVEL="$1"; shift
   118     eval level="\${CT_LOG_LEVEL_${LEVEL}}"
   119 
   120     if [ $# -eq 0 ]; then
   121         cat -
   122     else
   123         printf "%s\n" "${*}"
   124     fi |( IFS="${CR}" # We want the full lines, even leading spaces
   125           _prog_bar_cpt=0
   126           _prog_bar[0]='/'
   127           _prog_bar[1]='-'
   128           _prog_bar[2]='\'
   129           _prog_bar[3]='|'
   130           indent=$((2*CT_STEP_COUNT))
   131           while read line; do
   132               case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
   133                 y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
   134                 y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
   135                 *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
   136                 *"make["*"]: *** ["*)   cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
   137                 *)                      cur_L="${LEVEL}"; cur_l="${level}";;
   138               esac
   139               # There will always be a log file (stdout, fd #1), be it /dev/null
   140               printf "[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}"
   141               if [ ${cur_l} -le ${max_level} ]; then
   142                   # Only print to console (fd #6) if log level is high enough.
   143                   printf "${CT_LOG_PROGRESS_BAR:+\r}[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}" >&6
   144               fi
   145               if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
   146                   printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${_prog_bar[$((_prog_bar_cpt/10))]}" >&6
   147                   _prog_bar_cpt=$(((_prog_bar_cpt+1)%40))
   148               fi
   149           done
   150         )
   151 
   152     return 0
   153 }
   154 
   155 # Execute an action, and log its messages
   156 # It is possible to even log local variable assignments (a-la: var=val ./cmd opts)
   157 # Usage: CT_DoExecLog <level> [VAR=val...] <command> [parameters...]
   158 CT_DoExecLog() {
   159     local level="$1"
   160     shift
   161     (
   162     for i in "$@"; do
   163         tmp_log+="'${i}' "
   164     done
   165     while true; do
   166         case "${1}" in
   167             *=*)    eval export "'${1}'"; shift;;
   168             *)      break;;
   169         esac
   170     done
   171     CT_DoLog DEBUG "==> Executing: ${tmp_log}"
   172     "${@}" 2>&1 |CT_DoLog "${level}"
   173     )
   174     # Catch failure of the sub-shell
   175     [ $? -eq 0 ]
   176 }
   177 
   178 # Tail message to be logged whatever happens
   179 # Usage: CT_DoEnd <level>
   180 CT_DoEnd()
   181 {
   182     local level="$1"
   183     CT_STOP_DATE=$(CT_DoDate +%s%N)
   184     CT_STOP_DATE_HUMAN=$(CT_DoDate +%Y%m%d.%H%M%S)
   185     if [ "${level}" != "ERROR" ]; then
   186         CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
   187     fi
   188     elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
   189     elapsed_min=$((elapsed/(60*1000*1000*1000)))
   190     elapsed_sec=$(printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000))))
   191     elapsed_csec=$(printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000))))
   192     CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
   193 }
   194 
   195 # Remove entries referring to . and other relative paths
   196 # Usage: CT_SanitizePath
   197 CT_SanitizePath() {
   198     local new
   199     local p
   200     local IFS=:
   201     for p in $PATH; do
   202         # Only accept absolute paths;
   203         # Note: as a special case the empty string in PATH is equivalent to .
   204         if [ -n "${p}" -a -z "${p%%/*}" ]; then
   205             new="${new}${new:+:}${p}"
   206         fi
   207     done
   208     PATH="${new}"
   209 }
   210 
   211 # Sanitise the directory name contained in the variable passed as argument:
   212 # - remove duplicate /
   213 # Usage: CT_SanitiseVarDir CT_PREFIX_DIR
   214 CT_SanitiseVarDir() {
   215     local var
   216     local old_dir
   217     local new_dir
   218 
   219     for var in "$@"; do
   220         eval "old_dir=\"\${${var}}\""
   221         new_dir="$( printf "${old_dir}"     \
   222                     |sed -r -e 's:/+:/:g;'  \
   223                   )"
   224         eval "${var}=\"${new_dir}\""
   225         CT_DoLog DEBUG "Sanitised '${var}': '${old_dir}' -> '${new_dir}'"
   226     done
   227 }
   228 
   229 # Abort the execution with an error message
   230 # Usage: CT_Abort <message>
   231 CT_Abort() {
   232     CT_DoLog ERROR "$1"
   233     exit 1
   234 }
   235 
   236 # Test a condition, and print a message if satisfied
   237 # Usage: CT_Test <message> <tests>
   238 CT_Test() {
   239     local ret
   240     local m="$1"
   241     shift
   242     CT_DoLog DEBUG "Testing '! ( $* )'"
   243     test "$@" && CT_DoLog WARN "$m"
   244     return 0
   245 }
   246 
   247 # Test a condition, and abort with an error message if satisfied
   248 # Usage: CT_TestAndAbort <message> <tests>
   249 CT_TestAndAbort() {
   250     local m="$1"
   251     shift
   252     CT_DoLog DEBUG "Testing '! ( $* )'"
   253     test "$@" && CT_Abort "$m"
   254     return 0
   255 }
   256 
   257 # Test a condition, and abort with an error message if not satisfied
   258 # Usage: CT_TestAndAbort <message> <tests>
   259 CT_TestOrAbort() {
   260     local m="$1"
   261     shift
   262     CT_DoLog DEBUG "Testing '$*'"
   263     test "$@" || CT_Abort "$m"
   264     return 0
   265 }
   266 
   267 # Test the presence of a tool, or abort if not found
   268 # Usage: CT_HasOrAbort <tool>
   269 CT_HasOrAbort() {
   270     CT_TestAndAbort "'${1}' not found and needed for successful toolchain build." -z "$(CT_Which "${1}")"
   271     return 0
   272 }
   273 
   274 # Search a program: wrap "which" for those system where
   275 # "which" verbosely says there is no match (Mandriva is
   276 # such a sucker...)
   277 # Usage: CT_Which <filename>
   278 CT_Which() {
   279   which "$1" 2>/dev/null || true
   280 }
   281 
   282 # Get current date with nanosecond precision
   283 # On those system not supporting nanosecond precision, faked with rounding down
   284 # to the highest entire second
   285 # Usage: CT_DoDate <fmt>
   286 CT_DoDate() {
   287     date "$1" |sed -r -e 's/%?N$/000000000/;'
   288 }
   289 
   290 CT_STEP_COUNT=1
   291 CT_STEP_MESSAGE[${CT_STEP_COUNT}]="(top-level)"
   292 # Memorise a step being done so that any error is caught
   293 # Usage: CT_DoStep <loglevel> <message>
   294 CT_DoStep() {
   295     local start=$(CT_DoDate +%s%N)
   296     CT_DoLog "$1" "================================================================="
   297     CT_DoLog "$1" "$2"
   298     CT_STEP_COUNT=$((CT_STEP_COUNT+1))
   299     CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
   300     CT_STEP_START[${CT_STEP_COUNT}]="${start}"
   301     CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
   302     return 0
   303 }
   304 
   305 # End the step just being done
   306 # Usage: CT_EndStep
   307 CT_EndStep() {
   308     local stop=$(CT_DoDate +%s%N)
   309     local duration=$(printf "%032d" $((stop-${CT_STEP_START[${CT_STEP_COUNT}]})) |sed -r -e 's/([[:digit:]]{2})[[:digit:]]{7}$/\.\1/; s/^0+//; s/^\./0\./;')
   310     local elapsed=$(printf "%02d:%02d" $((SECONDS/60)) $((SECONDS%60)))
   311     local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
   312     local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
   313     CT_STEP_COUNT=$((CT_STEP_COUNT-1))
   314     CT_DoLog "${level}" "${message}: done in ${duration}s (at ${elapsed})"
   315     return 0
   316 }
   317 
   318 # Pushes into a directory, and pops back
   319 CT_Pushd() {
   320     pushd "$1" >/dev/null 2>&1
   321 }
   322 CT_Popd() {
   323     popd >/dev/null 2>&1
   324 }
   325 
   326 # Creates a temporary directory
   327 # $1: variable to assign to
   328 # Usage: CT_MktempDir foo
   329 CT_MktempDir() {
   330     # Some mktemp do not allow more than 6 Xs
   331     eval "$1"=$(mktemp -q -d "${CT_BUILD_DIR}/tmp.XXXXXX")
   332     CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
   333     CT_DoLog DEBUG "Made temporary directory '${!1}'"
   334     return 0
   335 }
   336 
   337 # Removes one or more directories, even if it is read-only, or its parent is
   338 # Usage: CT_DoForceRmdir dir [...]
   339 CT_DoForceRmdir() {
   340     local dir
   341     local mode
   342     for dir in "${@}"; do
   343         [ -d "${dir}" ] || continue
   344         case "$CT_SYS_OS" in
   345             Linux|CYGWIN*)
   346                 mode="$(stat -c '%a' "$(dirname "${dir}")")"
   347                 ;;
   348             Darwin|*BSD)
   349                 mode="$(stat -f '%Lp' "$(dirname "${dir}")")"
   350                 ;;
   351             *)
   352                 CT_Abort "Unhandled host OS $CT_SYS_OS"
   353                 ;;
   354         esac
   355         CT_DoExecLog ALL chmod u+w "$(dirname "${dir}")"
   356         CT_DoExecLog ALL chmod -R u+w "${dir}"
   357         CT_DoExecLog ALL rm -rf "${dir}"
   358         CT_DoExecLog ALL chmod ${mode} "$(dirname "${dir}")"
   359     done
   360 }
   361 
   362 # Echoes the specified string on stdout until the pipe breaks.
   363 # Doesn't fail
   364 # $1: string to echo
   365 # Usage: CT_DoYes "" |make oldconfig
   366 CT_DoYes() {
   367     yes "$1" || true
   368 }
   369 
   370 # Add the specified directory to LD_LIBRARY_PATH, and export it
   371 # If the specified patch is already present, just export
   372 # $1: path to add
   373 # $2: add as 'first' or 'last' path, 'first' is assumed if $2 is empty
   374 # Usage CT_SetLibPath /some/where/lib [first|last]
   375 CT_SetLibPath() {
   376     local path="$1"
   377     local pos="$2"
   378 
   379     case ":${LD_LIBRARY_PATH}:" in
   380         *:"${path}":*)  ;;
   381         *)  case "${pos}" in
   382                 last)
   383                     CT_DoLog DEBUG "Adding '${path}' at end of LD_LIBRARY_PATH"
   384                     LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${path}"
   385                     ;;
   386                 first|"")
   387                     CT_DoLog DEBUG "Adding '${path}' at start of LD_LIBRARY_PATH"
   388                     LD_LIBRARY_PATH="${path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
   389                     ;;
   390                 *)
   391                     CT_Abort "Incorrect position '${pos}' to add '${path}' to LD_LIBRARY_PATH"
   392                     ;;
   393             esac
   394             ;;
   395     esac
   396     CT_DoLog DEBUG "==> LD_LIBRARY_PATH='${LD_LIBRARY_PATH}'"
   397     export LD_LIBRARY_PATH
   398 }
   399 
   400 # Build up the list of allowed tarball extensions
   401 # Add them in the prefered order; most preferred comes first
   402 CT_DoListTarballExt() {
   403     if [ "${CT_CONFIGURE_has_xz}" = "y" ]; then
   404         printf ".tar.xz\n"
   405     fi
   406     if [    "${CT_CONFIGURE_has_lzma}" = "y"    \
   407          -o "${CT_CONFIGURE_has_xz}" = "y" ]; then
   408         printf ".tar.lzma\n"
   409     fi
   410     printf ".tar.bz2\n"
   411     printf ".tar.gz\n.tgz\n"
   412     printf ".tar\n"
   413 }
   414 
   415 # Get the file name extension of a component
   416 # Usage: CT_GetFileExtension <component_name-component_version> [extension]
   417 # If found, echoes the extension to stdout, and return 0
   418 # If not found, echoes nothing on stdout, and return !0.
   419 CT_GetFileExtension() {
   420     local ext
   421     local file="$1"
   422     shift
   423     local first_ext="$1"
   424 
   425     # we need to also check for an empty extension for those very
   426     # peculiar components that don't have one (such as sstrip from
   427     # buildroot).
   428     for ext in ${first_ext} $(CT_DoListTarballExt) /.git ''; do
   429         if [ -e "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
   430             echo "${ext}"
   431             exit 0
   432         fi
   433     done
   434 
   435     exit 1
   436 }
   437 
   438 # Try to retrieve the specified URL (HTTP or FTP)
   439 # Usage: CT_DoGetFile <URL>
   440 # This functions always returns true (0), as it can be legitimate not
   441 # to find the requested URL (think about snapshots, different layouts
   442 # for different gcc versions, etc...).
   443 CT_DoGetFile() {
   444     local url="${1}"
   445     local dest="${CT_TARBALLS_DIR}/${url##*/}"
   446     local tmp="${dest}.tmp-dl"
   447 
   448     # Remove potential left-over from a previous run
   449     rm -f "${tmp}"
   450 
   451     # We also retry a few times, in case there is a transient error (eg. behind
   452     # a dynamic IP that changes during the transfer...)
   453     # With automated download as we are doing, it can be very dangerous to
   454     # continue the downloads. It's far better to simply overwrite the
   455     # destination file.
   456     # Some company networks have firewalls to connect to the internet, but it's
   457     # not easy to detect them, so force a global ${CT_CONNECT_TIMEOUT}-second
   458     # timeout.
   459     # For curl, no good progress indicator is available. So, be silent.
   460     if CT_DoExecLog ALL wget --passive-ftp --tries=3 -nc    \
   461                              --progress=dot:binary          \
   462                              -T ${CT_CONNECT_TIMEOUT}       \
   463                              -O "${tmp}"                    \
   464                              "${url}"
   465     then
   466         # Success, we got it, good!
   467         mv "${tmp}" "${dest}"
   468     else
   469         # Woops...
   470         rm -f "${tmp}"
   471     fi
   472 }
   473 
   474 # This function tries to retrieve a tarball form a local directory
   475 # Usage: CT_GetLocal <basename> [.extension]
   476 CT_GetLocal() {
   477     local basename="$1"
   478     local first_ext="$2"
   479     local ext
   480 
   481     # Do we already have it in *our* tarballs dir?
   482     if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
   483         CT_DoLog DEBUG "Already have '${basename}'"
   484         return 0
   485     fi
   486 
   487     if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
   488         CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
   489         # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
   490         # or, as a failover, a file without extension.
   491         for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
   492             CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
   493             if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
   494                  "${CT_FORCE_DOWNLOAD}" != "y" ]; then
   495                 CT_DoLog DEBUG "Got '${basename}' from local storage"
   496                 CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
   497                 return 0
   498             fi
   499         done
   500     fi
   501     return 1
   502 }
   503 
   504 # This function saves the specified to local storage if possible,
   505 # and if so, symlinks it for later usage
   506 # Usage: CT_SaveLocal </full/path/file.name>
   507 CT_SaveLocal() {
   508     local file="$1"
   509     local basename="${file##*/}"
   510 
   511     if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
   512         CT_DoLog EXTRA "Saving '${basename}' to local storage"
   513         # The file may already exist if downloads are forced: remove it first
   514         CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
   515         CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
   516         CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
   517     fi
   518 }
   519 
   520 # Download the file from one of the URLs passed as argument
   521 # Usage: CT_GetFile <basename> [.extension] <url> [url ...]
   522 CT_GetFile() {
   523     local ext
   524     local -a URLS
   525     local url
   526     local file="$1"
   527     local first_ext
   528     shift
   529     # If next argument starts with a dot, then this is not an URL,
   530     # and we can consider that it is a preferred extension.
   531     case "$1" in
   532         .*) first_ext="$1"
   533             shift
   534             ;;
   535     esac
   536 
   537     # Does it exist localy?
   538     if CT_GetLocal "${file}" ${first_ext}; then
   539         return 0
   540     fi
   541     # No, it does not...
   542 
   543     # Try to retrieve the file
   544     CT_DoLog EXTRA "Retrieving '${file}'"
   545 
   546     # Add URLs on the LAN mirror
   547     if [ "${CT_USE_MIRROR}" = "y" ]; then
   548         CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
   549         URLS+=( "${CT_MIRROR_BASE_URL}/${file%-*}" )
   550         URLS+=( "${CT_MIRROR_BASE_URL}" )
   551     fi
   552 
   553     if [ "${CT_FORBID_DOWNLOAD}" != "y" ]; then
   554         URLS+=( "${@}" )
   555     fi
   556 
   557     # Scan all URLs in turn, and try to grab a tarball from there
   558     # Do *not* try git trees (ext=/.git), this is handled in a specific
   559     # wrapper, below
   560     for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
   561         # Try all urls in turn
   562         for url in "${URLS[@]}"; do
   563             [ -n "${url}" ] || continue
   564             CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
   565             CT_DoGetFile "${url}/${file}${ext}"
   566             if [ -f "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
   567                 CT_DoLog DEBUG "Got '${file}' from the Internet"
   568                 CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
   569                 return 0
   570             fi
   571         done
   572     done
   573 
   574     # Just return error, someone may want to catch and handle the error
   575     # (eg. glibc/eglibc add-ons can be missing).
   576     return 1
   577 }
   578 
   579 # Checkout from CVS, and build the associated tarball
   580 # The tarball will be called ${basename}.tar.bz2
   581 # Prerequisite: either the server does not require password,
   582 # or the user must already be logged in.
   583 # 'tag' is the tag to retrieve. Must be specified, but can be empty.
   584 # If dirname is specified, then module will be renamed to dirname
   585 # prior to building the tarball.
   586 # Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
   587 # Note: if '=subdir' is given, then it is used instead of 'module'.
   588 CT_GetCVS() {
   589     local basename="$1"
   590     local uri="$2"
   591     local module="$3"
   592     local tag="${4:+-r ${4}}"
   593     local dirname="$5"
   594     local tmp_dir
   595 
   596     # First try locally, then the mirror
   597     if CT_GetFile "${basename}"; then
   598         # Got it! Return early! :-)
   599         return 0
   600     fi
   601 
   602     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   603         CT_DoLog WARN "Downloads forbidden, not trying cvs retrieval"
   604         return 1
   605     fi
   606 
   607     CT_MktempDir tmp_dir
   608     CT_Pushd "${tmp_dir}"
   609 
   610     CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
   611     if [ -n "${dirname}" ]; then
   612         case "${dirname}" in
   613             *=*)
   614                 CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
   615                 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
   616                 ;;
   617             *)
   618                 CT_DoExecLog ALL mv "${module}" "${dirname}"
   619                 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
   620                 ;;
   621         esac
   622     fi
   623     CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
   624 
   625     CT_Popd
   626     CT_DoExecLog ALL rm -rf "${tmp_dir}"
   627 }
   628 
   629 # Check out from SVN, and build the associated tarball
   630 # The tarball will be called ${basename}.tar.bz2
   631 # Prerequisite: either the server does not require password,
   632 # or the user must already be logged in.
   633 # 'rev' is the revision to retrieve
   634 # Usage: CT_GetSVN <basename> <url> [rev]
   635 CT_GetSVN() {
   636     local basename="$1"
   637     local uri="$2"
   638     local rev="$3"
   639 
   640     # First try locally, then the mirror
   641     if CT_GetFile "${basename}"; then
   642         # Got it! Return early! :-)
   643         return 0
   644     fi
   645 
   646     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   647         CT_DoLog WARN "Downloads forbidden, not trying svn retrieval"
   648         return 1
   649     fi
   650 
   651     CT_MktempDir tmp_dir
   652     CT_Pushd "${tmp_dir}"
   653 
   654     if ! CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"; then
   655         CT_DoLog WARN "Could not retrieve '${basename}'"
   656         return 1
   657     fi
   658     CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
   659     CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
   660 
   661     CT_Popd
   662     CT_DoExecLog ALL rm -rf "${tmp_dir}"
   663 }
   664 
   665 # Clone a git tree
   666 # Tries the given URLs in turn until one can get cloned. No tarball will be created.
   667 # Prerequisites: either the server does not require password,
   668 # or the user has already taken any action to authenticate to the server.
   669 # The cloned tree will *not* be stored in the local tarballs dir!
   670 # Usage: CT_GetGit <basename> <url [url ...]>
   671 CT_GetGit() {
   672     local basename="$1"; shift
   673     local url
   674     local cloned=0
   675 
   676     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   677         CT_DoLog WARN "Downloads forbidden, not trying git retrieval"
   678         return 1
   679     fi
   680 
   681     # Do we have it in our tarballs dir?
   682     if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
   683         CT_DoLog EXTRA "Updating git tree '${basename}'"
   684         CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
   685         CT_DoExecLog ALL git pull
   686         CT_Popd
   687     else
   688         CT_DoLog EXTRA "Retrieving git tree '${basename}'"
   689         for url in "${@}"; do
   690             CT_DoLog ALL "Trying to clone from '${url}'"
   691             CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
   692             if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
   693                 cloned=1
   694                 break
   695             fi
   696         done
   697         CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
   698     fi
   699 }
   700 
   701 # Extract a tarball
   702 # Some tarballs need to be extracted in specific places. Eg.: glibc addons
   703 # must be extracted in the glibc directory; uCLibc locales must be extracted
   704 # in the extra/locale sub-directory of uClibc. This is taken into account
   705 # by the caller, that did a 'cd' into the correct path before calling us
   706 # and sets nochdir to 'nochdir'.
   707 # Note also that this function handles the git trees!
   708 # Usage: CT_Extract <basename> [nochdir] [options]
   709 # where 'options' are dependent on the source (eg. git branch/tag...)
   710 CT_Extract() {
   711     local nochdir="$1"
   712     local basename
   713     local ext
   714     local lzma_prog
   715     local -a tar_opts
   716 
   717     if [ "${nochdir}" = "nochdir" ]; then
   718         shift
   719         nochdir="$(pwd)"
   720     else
   721         nochdir="${CT_SRC_DIR}"
   722     fi
   723 
   724     basename="$1"
   725     shift
   726 
   727     if ! ext="$(CT_GetFileExtension "${basename}")"; then
   728         CT_DoLog WARN "'${basename}' not found in '${CT_TARBALLS_DIR}'"
   729         return 1
   730     fi
   731     local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
   732 
   733     # Check if already extracted
   734     if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
   735         CT_DoLog DEBUG "Already extracted '${basename}'"
   736         return 0
   737     fi
   738 
   739     # Check if previously partially extracted
   740     if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
   741         CT_DoLog ERROR "The '${basename}' sources were partially extracted."
   742         CT_DoLog ERROR "Please remove first:"
   743         CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
   744         CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
   745         CT_Abort "I'll stop now to avoid any carnage..."
   746     fi
   747     CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
   748 
   749     CT_Pushd "${nochdir}"
   750 
   751     CT_DoLog EXTRA "Extracting '${basename}'"
   752     CT_DoExecLog FILE mkdir -p "${basename}"
   753     tar_opts=( "--strip-components=1" )
   754     tar_opts+=( "-C" "${basename}" )
   755     tar_opts+=( "-xv" )
   756 
   757     # One note here:
   758     # - lzma can be handled either with 'xz' or 'lzma'
   759     # - we get lzma tarball only if either or both are available
   760     # - so, if we get an lzma tarball, and either 'xz' or 'lzma' is
   761     #   missing, we can assume the other is available
   762     if [ "${CT_CONFIGURE_has_lzma}" = "y" ]; then
   763         lzma_prog="lzma -fdc"
   764     else
   765         lzma_prog="xz -fdc"
   766     fi
   767     case "${ext}" in
   768         .tar.xz)      xz -fdc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   769         .tar.lzma)    ${lzma_prog} "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   770         .tar.bz2)     bzip2 -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   771         .tar.gz|.tgz) gzip -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   772         .tar)         CT_DoExecLog FILE tar "${tar_opts[@]}" -f "${full_file}";;
   773         /.git)        CT_ExtractGit "${basename}" "${@}";;
   774         *)            CT_DoLog WARN "Don't know how to handle '${basename}${ext}': unknown extension"
   775                       return 1
   776                       ;;
   777     esac
   778 
   779     # Don't mark as being extracted for git
   780     case "${ext}" in
   781         /.git)  ;;
   782         *)      CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
   783     esac
   784     CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
   785 
   786     CT_Popd
   787 }
   788 
   789 # Create a working git clone of a local git repository
   790 # Usage: CT_ExtractGit <basename> [ref]
   791 # where 'ref' is the reference to use:
   792 #   the full name of a branch, like "remotes/origin/branch_name"
   793 #   a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
   794 #   a tag name
   795 # If 'ref' is not given, the current repository HEAD will be used
   796 CT_ExtractGit() {
   797     local basename="${1}"
   798     local ref="${2}"
   799     local repo
   800     local ref_type
   801 
   802     # pushd now to be able to get git revlist in case ref is a date
   803     repo="${CT_TARBALLS_DIR}/${basename}"
   804     CT_Pushd "${repo}"
   805 
   806     # What kind of reference is ${ref} ?
   807     if [ -z "${ref}" ]; then
   808         ref_type=head
   809         ref=$(git rev-list -n1 HEAD)
   810     elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
   811         ref_type=tag
   812     elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
   813         ref_type=branch
   814     elif date -d "${ref}" >/dev/null 2>&1; then
   815         ref_type=date
   816         ref=$(git rev-list -n1 --before="${ref}")
   817     else
   818         CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
   819     fi
   820 
   821     CT_Popd
   822 
   823     CT_DoExecLog FILE rmdir "${basename}"
   824     case "${ref_type}" in
   825         branch) CT_DoExecLog FILE git clone -b "${ref}" "${repo}" "${basename}" ;;
   826         *)      CT_DoExecLog FILE git clone "${repo}" "${basename}"
   827                 CT_Pushd "${basename}"
   828                 CT_DoExecLog FILE git checkout "${ref}"
   829                 CT_Popd
   830                 ;;
   831     esac
   832 }
   833 
   834 # Patches the specified component
   835 # See CT_Extract, above, for explanations on 'nochdir'
   836 # Usage: CT_Patch [nochdir] <packagename> <packageversion>
   837 # If the package directory is *not* packagename-packageversion, then
   838 # the caller must cd into the proper directory first, and call us
   839 # with nochdir
   840 CT_Patch() {
   841     local nochdir="$1"
   842     local pkgname
   843     local version
   844     local pkgdir
   845     local base_file
   846     local ver_file
   847     local d
   848     local -a patch_dirs
   849     local bundled_patch_dir
   850     local local_patch_dir
   851 
   852     if [ "${nochdir}" = "nochdir" ]; then
   853         shift
   854         pkgname="$1"
   855         version="$2"
   856         pkgdir="${pkgname}-${version}"
   857         nochdir="$(pwd)"
   858     else
   859         pkgname="$1"
   860         version="$2"
   861         pkgdir="${pkgname}-${version}"
   862         nochdir="${CT_SRC_DIR}/${pkgdir}"
   863     fi
   864 
   865     # Check if already patched
   866     if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
   867         CT_DoLog DEBUG "Already patched '${pkgdir}'"
   868         return 0
   869     fi
   870 
   871     # Check if already partially patched
   872     if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
   873         CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
   874         CT_DoLog ERROR "Please remove first:"
   875         CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
   876         CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
   877         CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
   878         CT_Abort "I'll stop now to avoid any carnage..."
   879     fi
   880     touch "${CT_SRC_DIR}/.${pkgdir}.patching"
   881 
   882     CT_Pushd "${nochdir}"
   883 
   884     CT_DoLog EXTRA "Patching '${pkgdir}'"
   885 
   886     bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
   887     local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
   888 
   889     case "${CT_PATCH_ORDER}" in
   890         bundled)        patch_dirs=("${bundled_patch_dir}");;
   891         local)          patch_dirs=("${local_patch_dir}");;
   892         bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
   893         local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
   894         none)           patch_dirs=;;
   895     esac
   896 
   897     for d in "${patch_dirs[@]}"; do
   898         CT_DoLog DEBUG "Looking for patches in '${d}'..."
   899         if [ -n "${d}" -a -d "${d}" ]; then
   900             for p in "${d}"/*.patch; do
   901                 if [ -f "${p}" ]; then
   902                     CT_DoLog DEBUG "Applying patch '${p}'"
   903                     CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f <"${p}"
   904                 fi
   905             done
   906             if [ "${CT_PATCH_SINGLE}" = "y" ]; then
   907                 break
   908             fi
   909         fi
   910     done
   911 
   912     if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
   913         CT_DoLog ALL "Overiding config.guess and config.sub"
   914         for cfg in config_guess config_sub; do
   915             eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
   916             [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
   917             # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
   918             find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
   919         done
   920     fi
   921 
   922     CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
   923     CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
   924 
   925     CT_Popd
   926 }
   927 
   928 # Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
   929 # Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
   930 CT_DoConfigGuess() {
   931     if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
   932         "${CT_TOP_DIR}/scripts/config.guess"
   933     else
   934         "${CT_LIB_DIR}/scripts/config.guess"
   935     fi
   936 }
   937 
   938 CT_DoConfigSub() {
   939     if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
   940         "${CT_TOP_DIR}/scripts/config.sub" "$@"
   941     else
   942         "${CT_LIB_DIR}/scripts/config.sub" "$@"
   943     fi
   944 }
   945 
   946 # Compute the target tuple from what is provided by the user
   947 # Usage: CT_DoBuildTargetTuple
   948 # In fact this function takes the environment variables to build the target
   949 # tuple. It is needed both by the normal build sequence, as well as the
   950 # sample saving sequence.
   951 CT_DoBuildTargetTuple() {
   952     # Set the endianness suffix, and the default endianness gcc option
   953     case "${CT_ARCH_ENDIAN}" in
   954         big)
   955             target_endian_eb=eb
   956             target_endian_el=
   957             CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
   958             CT_ARCH_ENDIAN_LDFLAG="-EB"
   959             ;;
   960         little)
   961             target_endian_eb=
   962             target_endian_el=el
   963             CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
   964             CT_ARCH_ENDIAN_LDFLAG="-EL"
   965             ;;
   966     esac
   967 
   968     # Build the default architecture tuple part
   969     CT_TARGET_ARCH="${CT_ARCH}"
   970 
   971     # Set defaults for the system part of the tuple. Can be overriden
   972     # by architecture-specific values.
   973     case "${CT_LIBC}" in
   974         *glibc) CT_TARGET_SYS=gnu;;
   975         uClibc) CT_TARGET_SYS=uclibc;;
   976         *)      CT_TARGET_SYS=elf;;
   977     esac
   978 
   979     # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
   980     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
   981     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
   982     [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
   983     [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
   984     [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
   985     [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
   986     [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
   987 
   988     case "${CT_ARCH_FLOAT}" in
   989         hard)
   990             CT_ARCH_FLOAT_CFLAG="-mhard-float"
   991             CT_ARCH_WITH_FLOAT="--with-float=hard"
   992             ;;
   993         soft)
   994             CT_ARCH_FLOAT_CFLAG="-msoft-float"
   995             CT_ARCH_WITH_FLOAT="--with-float=soft"
   996             ;;
   997         softfp)
   998             CT_ARCH_FLOAT_CFLAG="-mfloat-abi=softfp"
   999             CT_ARCH_WITH_FLOAT="--with-float=softfp"
  1000             ;;
  1001     esac
  1002 
  1003     # Build the default kernel tuple part
  1004     CT_TARGET_KERNEL="${CT_KERNEL}"
  1005 
  1006     # Overide the default values with the components specific settings
  1007     CT_DoArchTupleValues
  1008     CT_DoKernelTupleValues
  1009 
  1010     # Finish the target tuple construction
  1011     CT_TARGET="${CT_TARGET_ARCH}"
  1012     CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
  1013     CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
  1014     CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
  1015 
  1016     # Sanity checks
  1017     __sed_alias=""
  1018     if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
  1019         __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
  1020     fi
  1021     case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
  1022       :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
  1023       :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
  1024       :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
  1025       :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
  1026     esac
  1027 
  1028     # Canonicalise it
  1029     CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
  1030     # Prepare the target CFLAGS
  1031     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
  1032     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
  1033     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
  1034     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
  1035     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
  1036     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
  1037     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
  1038 
  1039     # Now on for the target LDFLAGS
  1040     CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
  1041 }
  1042 
  1043 # This function does pause the build until the user strikes "Return"
  1044 # Usage: CT_DoPause [optional_message]
  1045 CT_DoPause() {
  1046     local foo
  1047     local message="${1:-Pausing for your pleasure}"
  1048     CT_DoLog INFO "${message}"
  1049     read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
  1050     return 0
  1051 }
  1052 
  1053 # This function creates a tarball of the specified directory, but
  1054 # only if it exists
  1055 # Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
  1056 CT_DoTarballIfExists() {
  1057     local dir="$1"
  1058     local tarball="$2"
  1059     shift 2
  1060     local -a extra_tar_opts=( "$@" )
  1061     local -a compress
  1062 
  1063     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1064         y)  compress=( gzip -c -3 - ); tar_ext=.gz;;
  1065         *)  compress=( cat - );        tar_ext=;;
  1066     esac
  1067 
  1068     if [ -d "${dir}" ]; then
  1069         CT_DoLog DEBUG "  Saving '${dir}'"
  1070         { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" .    \
  1071           |"${compress[@]}" >"${tarball}.tar${tar_ext}"         ;
  1072         } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
  1073     else
  1074         CT_DoLog STATE "  Not saving '${dir}': does not exist"
  1075     fi
  1076 }
  1077 
  1078 # This function extracts a tarball to the specified directory, but
  1079 # only if the tarball exists
  1080 # Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
  1081 CT_DoExtractTarballIfExists() {
  1082     local tarball="$1"
  1083     local dir="$2"
  1084     shift 2
  1085     local -a extra_tar_opts=( "$@" )
  1086     local -a uncompress
  1087 
  1088     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1089         y)  uncompress=( gzip -c -d ); tar_ext=.gz;;
  1090         *)  uncompress=( cat );        tar_ext=;;
  1091     esac
  1092 
  1093     if [ -f "${tarball}.tar${tar_ext}" ]; then
  1094         CT_DoLog DEBUG "  Restoring '${dir}'"
  1095         CT_DoForceRmdir "${dir}"
  1096         CT_DoExecLog DEBUG mkdir -p "${dir}"
  1097         { "${uncompress[@]}" "${tarball}.tar${tar_ext}"     \
  1098           |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
  1099         } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
  1100     else
  1101         CT_DoLog STATE "  Not restoring '${dir}': does not exist"
  1102     fi
  1103 }
  1104 
  1105 # This function saves the state of the toolchain to be able to restart
  1106 # at any one point
  1107 # Usage: CT_DoSaveState <next_step_name>
  1108 CT_DoSaveState() {
  1109 	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
  1110     local state_name="$1"
  1111     local state_dir="${CT_STATE_DIR}/${state_name}"
  1112 
  1113     # Log this to the log level required by the user
  1114     CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
  1115 
  1116     rm -rf "${state_dir}"
  1117     mkdir -p "${state_dir}"
  1118 
  1119     CT_DoLog STATE "  Saving environment and aliases"
  1120     # We must omit shell functions, and some specific bash variables
  1121     # that break when restoring the environment, later. We could do
  1122     # all the processing in the awk script, but a sed is easier...
  1123     set |awk '
  1124               BEGIN { _p = 1; }
  1125               $0~/^[^ ]+ \(\)/ { _p = 0; }
  1126               _p == 1
  1127               $0 == "}" { _p = 1; }
  1128               ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
  1129                            /^(UID|EUID)=/d;
  1130                            /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
  1131 
  1132     CT_DoTarballIfExists "${CT_BUILDTOOLS_PREFIX_DIR}" "${state_dir}/buildtools_dir"
  1133     CT_DoTarballIfExists "${CT_COMPLIBS_DIR}" "${state_dir}/complibs_dir"
  1134     CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
  1135     CT_DoTarballIfExists "${CT_CC_CORE_STATIC_PREFIX_DIR}" "${state_dir}/cc_core_static_prefix_dir"
  1136     CT_DoTarballIfExists "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${state_dir}/cc_core_shared_prefix_dir"
  1137     CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
  1138 
  1139     CT_DoLog STATE "  Saving log file"
  1140     exec >/dev/null
  1141     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1142         y)  gzip -3 -c "${tmp_log_file}"  >"${state_dir}/log.gz";;
  1143         *)  cat "${tmp_log_file}" >"${state_dir}/log";;
  1144     esac
  1145     exec >>"${tmp_log_file}"
  1146 }
  1147 
  1148 # This function restores a previously saved state
  1149 # Usage: CT_DoLoadState <state_name>
  1150 CT_DoLoadState(){
  1151     local state_name="$1"
  1152     local state_dir="${CT_STATE_DIR}/${state_name}"
  1153     local old_RESTART="${CT_RESTART}"
  1154     local old_STOP="${CT_STOP}"
  1155 
  1156     CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
  1157 
  1158     # We need to do something special with the log file!
  1159     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
  1160         exec >"${state_dir}/tail.log"
  1161     fi
  1162 
  1163     # Log this to the log level required by the user
  1164     CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
  1165 
  1166     CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
  1167     CT_DoExtractTarballIfExists "${state_dir}/cc_core_shared_prefix_dir" "${CT_CC_CORE_SHARED_PREFIX_DIR}"
  1168     CT_DoExtractTarballIfExists "${state_dir}/cc_core_static_prefix_dir" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
  1169     CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
  1170     CT_DoExtractTarballIfExists "${state_dir}/complibs_dir" "${CT_COMPLIBS_DIR}"
  1171     CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_PREFIX_DIR}"
  1172 
  1173     # Restore the environment, discarding any error message
  1174     # (for example, read-only bash internals)
  1175     CT_DoLog STATE "  Restoring environment"
  1176     . "${state_dir}/env.sh" >/dev/null 2>&1 || true
  1177 
  1178     # Restore the new RESTART and STOP steps
  1179     CT_RESTART="${old_RESTART}"
  1180     CT_STOP="${old_STOP}"
  1181     unset old_stop old_restart
  1182 
  1183     CT_DoLog STATE "  Restoring log file"
  1184     exec >/dev/null
  1185     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1186         y)  zcat "${state_dir}/log.gz" >"${tmp_log_file}";;
  1187         *)  cat "${state_dir}/log" >"${tmp_log_file}";;
  1188     esac
  1189     cat "${state_dir}/tail.log" >>"${tmp_log_file}"
  1190     exec >>"${tmp_log_file}"
  1191     rm -f "${state_dir}/tail.log"
  1192 }