scripts/functions
author "Benoît Thébaudeau" <benoit.thebaudeau@advansee.com>
Mon Apr 16 15:25:36 2012 +0200 (2012-04-16)
changeset 2941 13e40098fffc
parent 2924 0eab838768b1
child 2967 04092e6b82ca
permissions -rw-r--r--
cc/gcc: update Linaro GCC revisions to 2012.04

Update Linaro GCC with the latest available revisions.

The 4.7 revision is also released, but the infrastructure is not yet ready for
it in CT-NG.

Signed-off-by: "Benoît Thébaudeau" <benoit.thebaudeau@advansee.com>
     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 # Create a dir and cd or pushd into it
   327 # Usage: CT_mkdir_cd <dir/to/create>
   328 #        CT_mkdir_pushd <dir/to/create>
   329 CT_mkdir_cd() {
   330     local dir="${1}"
   331 
   332     mkdir -p "${dir}"
   333     cd "${dir}"
   334 }
   335 CT_mkdir_pushd() {
   336     local dir="${1}"
   337 
   338     mkdir -p "${dir}"
   339     CT_Pushd "${dir}"
   340 }
   341 
   342 # Creates a temporary directory
   343 # $1: variable to assign to
   344 # Usage: CT_MktempDir foo
   345 CT_MktempDir() {
   346     # Some mktemp do not allow more than 6 Xs
   347     eval "$1"=$(mktemp -q -d "${CT_BUILD_DIR}/tmp.XXXXXX")
   348     CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
   349     CT_DoLog DEBUG "Made temporary directory '${!1}'"
   350     return 0
   351 }
   352 
   353 # Removes one or more directories, even if it is read-only, or its parent is
   354 # Usage: CT_DoForceRmdir dir [...]
   355 CT_DoForceRmdir() {
   356     local dir
   357     local mode
   358     for dir in "${@}"; do
   359         [ -d "${dir}" ] || continue
   360         case "$CT_SYS_OS" in
   361             Linux|CYGWIN*)
   362                 mode="$(stat -c '%a' "$(dirname "${dir}")")"
   363                 ;;
   364             Darwin|*BSD)
   365                 mode="$(stat -f '%Lp' "$(dirname "${dir}")")"
   366                 ;;
   367             *)
   368                 CT_Abort "Unhandled host OS $CT_SYS_OS"
   369                 ;;
   370         esac
   371         CT_DoExecLog ALL chmod u+w "$(dirname "${dir}")"
   372         CT_DoExecLog ALL chmod -R u+w "${dir}"
   373         CT_DoExecLog ALL rm -rf "${dir}"
   374         CT_DoExecLog ALL chmod ${mode} "$(dirname "${dir}")"
   375     done
   376 }
   377 
   378 # Echoes the specified string on stdout until the pipe breaks.
   379 # Doesn't fail
   380 # $1: string to echo
   381 # Usage: CT_DoYes "" |make oldconfig
   382 CT_DoYes() {
   383     yes "$1" || true
   384 }
   385 
   386 # Add the specified directory to LD_LIBRARY_PATH, and export it
   387 # If the specified patch is already present, just export
   388 # $1: path to add
   389 # $2: add as 'first' or 'last' path, 'first' is assumed if $2 is empty
   390 # Usage CT_SetLibPath /some/where/lib [first|last]
   391 CT_SetLibPath() {
   392     local path="$1"
   393     local pos="$2"
   394 
   395     case ":${LD_LIBRARY_PATH}:" in
   396         *:"${path}":*)  ;;
   397         *)  case "${pos}" in
   398                 last)
   399                     CT_DoLog DEBUG "Adding '${path}' at end of LD_LIBRARY_PATH"
   400                     LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${path}"
   401                     ;;
   402                 first|"")
   403                     CT_DoLog DEBUG "Adding '${path}' at start of LD_LIBRARY_PATH"
   404                     LD_LIBRARY_PATH="${path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
   405                     ;;
   406                 *)
   407                     CT_Abort "Incorrect position '${pos}' to add '${path}' to LD_LIBRARY_PATH"
   408                     ;;
   409             esac
   410             ;;
   411     esac
   412     CT_DoLog DEBUG "==> LD_LIBRARY_PATH='${LD_LIBRARY_PATH}'"
   413     export LD_LIBRARY_PATH
   414 }
   415 
   416 # Build up the list of allowed tarball extensions
   417 # Add them in the prefered order; most preferred comes first
   418 CT_DoListTarballExt() {
   419     if [ "${CT_CONFIGURE_has_xz}" = "y" ]; then
   420         printf ".tar.xz\n"
   421     fi
   422     if [    "${CT_CONFIGURE_has_lzma}" = "y"    \
   423          -o "${CT_CONFIGURE_has_xz}" = "y" ]; then
   424         printf ".tar.lzma\n"
   425     fi
   426     printf ".tar.bz2\n"
   427     printf ".tar.gz\n.tgz\n"
   428     printf ".tar\n"
   429 }
   430 
   431 # Get the file name extension of a component
   432 # Usage: CT_GetFileExtension <component_name-component_version> [extension]
   433 # If found, echoes the extension to stdout, and return 0
   434 # If not found, echoes nothing on stdout, and return !0.
   435 CT_GetFileExtension() {
   436     local ext
   437     local file="$1"
   438     shift
   439     local first_ext="$1"
   440 
   441     # we need to also check for an empty extension for those very
   442     # peculiar components that don't have one (such as sstrip from
   443     # buildroot).
   444     for ext in ${first_ext} $(CT_DoListTarballExt) /.git ''; do
   445         if [ -e "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
   446             echo "${ext}"
   447             exit 0
   448         fi
   449     done
   450 
   451     exit 1
   452 }
   453 
   454 # Try to retrieve the specified URL (HTTP or FTP)
   455 # Usage: CT_DoGetFile <URL>
   456 # This functions always returns true (0), as it can be legitimate not
   457 # to find the requested URL (think about snapshots, different layouts
   458 # for different gcc versions, etc...).
   459 CT_DoGetFile() {
   460     local url="${1}"
   461     local dest="${CT_TARBALLS_DIR}/${url##*/}"
   462     local tmp="${dest}.tmp-dl"
   463 
   464     # Remove potential left-over from a previous run
   465     rm -f "${tmp}"
   466 
   467     # We also retry a few times, in case there is a transient error (eg. behind
   468     # a dynamic IP that changes during the transfer...)
   469     # With automated download as we are doing, it can be very dangerous to
   470     # continue the downloads. It's far better to simply overwrite the
   471     # destination file.
   472     # Some company networks have firewalls to connect to the internet, but it's
   473     # not easy to detect them, so force a global ${CT_CONNECT_TIMEOUT}-second
   474     # timeout.
   475     # For curl, no good progress indicator is available. So, be silent.
   476     if CT_DoExecLog ALL wget --passive-ftp --tries=3 -nc    \
   477                              --progress=dot:binary          \
   478                              -T ${CT_CONNECT_TIMEOUT}       \
   479                              -O "${tmp}"                    \
   480                              "${url}"
   481     then
   482         # Success, we got it, good!
   483         mv "${tmp}" "${dest}"
   484     else
   485         # Woops...
   486         rm -f "${tmp}"
   487     fi
   488 }
   489 
   490 # This function tries to retrieve a tarball form a local directory
   491 # Usage: CT_GetLocal <basename> [.extension]
   492 CT_GetLocal() {
   493     local basename="$1"
   494     local first_ext="$2"
   495     local ext
   496 
   497     # Do we already have it in *our* tarballs dir?
   498     if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
   499         CT_DoLog DEBUG "Already have '${basename}'"
   500         return 0
   501     fi
   502 
   503     if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
   504         CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
   505         # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
   506         # or, as a failover, a file without extension.
   507         for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
   508             CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
   509             if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
   510                  "${CT_FORCE_DOWNLOAD}" != "y" ]; then
   511                 CT_DoLog DEBUG "Got '${basename}' from local storage"
   512                 CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
   513                 return 0
   514             fi
   515         done
   516     fi
   517     return 1
   518 }
   519 
   520 # This function saves the specified to local storage if possible,
   521 # and if so, symlinks it for later usage
   522 # Usage: CT_SaveLocal </full/path/file.name>
   523 CT_SaveLocal() {
   524     local file="$1"
   525     local basename="${file##*/}"
   526 
   527     if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
   528         CT_DoLog EXTRA "Saving '${basename}' to local storage"
   529         # The file may already exist if downloads are forced: remove it first
   530         CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
   531         CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
   532         CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
   533     fi
   534 }
   535 
   536 # Download the file from one of the URLs passed as argument
   537 # Usage: CT_GetFile <basename> [.extension] <url> [url ...]
   538 CT_GetFile() {
   539     local ext
   540     local -a URLS
   541     local url
   542     local file="$1"
   543     local first_ext
   544     shift
   545     # If next argument starts with a dot, then this is not an URL,
   546     # and we can consider that it is a preferred extension.
   547     case "$1" in
   548         .*) first_ext="$1"
   549             shift
   550             ;;
   551     esac
   552 
   553     # Does it exist localy?
   554     if CT_GetLocal "${file}" ${first_ext}; then
   555         return 0
   556     fi
   557     # No, it does not...
   558 
   559     # Try to retrieve the file
   560     CT_DoLog EXTRA "Retrieving '${file}'"
   561 
   562     # Add URLs on the LAN mirror
   563     if [ "${CT_USE_MIRROR}" = "y" ]; then
   564         CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
   565         URLS+=( "${CT_MIRROR_BASE_URL}/${file%-*}" )
   566         URLS+=( "${CT_MIRROR_BASE_URL}" )
   567     fi
   568 
   569     if [ "${CT_FORBID_DOWNLOAD}" != "y" ]; then
   570         URLS+=( "${@}" )
   571     fi
   572 
   573     # Scan all URLs in turn, and try to grab a tarball from there
   574     # Do *not* try git trees (ext=/.git), this is handled in a specific
   575     # wrapper, below
   576     for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
   577         # Try all urls in turn
   578         for url in "${URLS[@]}"; do
   579             [ -n "${url}" ] || continue
   580             CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
   581             CT_DoGetFile "${url}/${file}${ext}"
   582             if [ -f "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
   583                 CT_DoLog DEBUG "Got '${file}' from the Internet"
   584                 CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
   585                 return 0
   586             fi
   587         done
   588     done
   589 
   590     # Just return error, someone may want to catch and handle the error
   591     # (eg. glibc/eglibc add-ons can be missing).
   592     return 1
   593 }
   594 
   595 # Checkout from CVS, and build the associated tarball
   596 # The tarball will be called ${basename}.tar.bz2
   597 # Prerequisite: either the server does not require password,
   598 # or the user must already be logged in.
   599 # 'tag' is the tag to retrieve. Must be specified, but can be empty.
   600 # If dirname is specified, then module will be renamed to dirname
   601 # prior to building the tarball.
   602 # Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
   603 # Note: if '=subdir' is given, then it is used instead of 'module'.
   604 CT_GetCVS() {
   605     local basename="$1"
   606     local uri="$2"
   607     local module="$3"
   608     local tag="${4:+-r ${4}}"
   609     local dirname="$5"
   610     local tmp_dir
   611 
   612     # First try locally, then the mirror
   613     if CT_GetFile "${basename}"; then
   614         # Got it! Return early! :-)
   615         return 0
   616     fi
   617 
   618     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   619         CT_DoLog WARN "Downloads forbidden, not trying cvs retrieval"
   620         return 1
   621     fi
   622 
   623     CT_MktempDir tmp_dir
   624     CT_Pushd "${tmp_dir}"
   625 
   626     CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
   627     if [ -n "${dirname}" ]; then
   628         case "${dirname}" in
   629             *=*)
   630                 CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
   631                 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
   632                 ;;
   633             *)
   634                 CT_DoExecLog ALL mv "${module}" "${dirname}"
   635                 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
   636                 ;;
   637         esac
   638     fi
   639     CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
   640 
   641     CT_Popd
   642     CT_DoExecLog ALL rm -rf "${tmp_dir}"
   643 }
   644 
   645 # Check out from SVN, and build the associated tarball
   646 # The tarball will be called ${basename}.tar.bz2
   647 # Prerequisite: either the server does not require password,
   648 # or the user must already be logged in.
   649 # 'rev' is the revision to retrieve
   650 # Usage: CT_GetSVN <basename> <url> [rev]
   651 CT_GetSVN() {
   652     local basename="$1"
   653     local uri="$2"
   654     local rev="$3"
   655 
   656     # First try locally, then the mirror
   657     if CT_GetFile "${basename}"; then
   658         # Got it! Return early! :-)
   659         return 0
   660     fi
   661 
   662     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   663         CT_DoLog WARN "Downloads forbidden, not trying svn retrieval"
   664         return 1
   665     fi
   666 
   667     CT_MktempDir tmp_dir
   668     CT_Pushd "${tmp_dir}"
   669 
   670     if ! CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"; then
   671         CT_DoLog WARN "Could not retrieve '${basename}'"
   672         return 1
   673     fi
   674     CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
   675     CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
   676 
   677     CT_Popd
   678     CT_DoExecLog ALL rm -rf "${tmp_dir}"
   679 }
   680 
   681 # Clone a git tree
   682 # Tries the given URLs in turn until one can get cloned. No tarball will be created.
   683 # Prerequisites: either the server does not require password,
   684 # or the user has already taken any action to authenticate to the server.
   685 # The cloned tree will *not* be stored in the local tarballs dir!
   686 # Usage: CT_GetGit <basename> <url [url ...]>
   687 CT_GetGit() {
   688     local basename="$1"; shift
   689     local url
   690     local cloned=0
   691 
   692     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   693         CT_DoLog WARN "Downloads forbidden, not trying git retrieval"
   694         return 1
   695     fi
   696 
   697     # Do we have it in our tarballs dir?
   698     if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
   699         CT_DoLog EXTRA "Updating git tree '${basename}'"
   700         CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
   701         CT_DoExecLog ALL git pull
   702         CT_Popd
   703     else
   704         CT_DoLog EXTRA "Retrieving git tree '${basename}'"
   705         for url in "${@}"; do
   706             CT_DoLog ALL "Trying to clone from '${url}'"
   707             CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
   708             if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
   709                 cloned=1
   710                 break
   711             fi
   712         done
   713         CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
   714     fi
   715 }
   716 
   717 # Extract a tarball
   718 # Some tarballs need to be extracted in specific places. Eg.: glibc addons
   719 # must be extracted in the glibc directory; uCLibc locales must be extracted
   720 # in the extra/locale sub-directory of uClibc. This is taken into account
   721 # by the caller, that did a 'cd' into the correct path before calling us
   722 # and sets nochdir to 'nochdir'.
   723 # Note also that this function handles the git trees!
   724 # Usage: CT_Extract <basename> [nochdir] [options]
   725 # where 'options' are dependent on the source (eg. git branch/tag...)
   726 CT_Extract() {
   727     local nochdir="$1"
   728     local basename
   729     local ext
   730     local lzma_prog
   731     local -a tar_opts
   732 
   733     if [ "${nochdir}" = "nochdir" ]; then
   734         shift
   735         nochdir="$(pwd)"
   736     else
   737         nochdir="${CT_SRC_DIR}"
   738     fi
   739 
   740     basename="$1"
   741     shift
   742 
   743     if ! ext="$(CT_GetFileExtension "${basename}")"; then
   744         CT_DoLog WARN "'${basename}' not found in '${CT_TARBALLS_DIR}'"
   745         return 1
   746     fi
   747     local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
   748 
   749     # Check if already extracted
   750     if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
   751         CT_DoLog DEBUG "Already extracted '${basename}'"
   752         return 0
   753     fi
   754 
   755     # Check if previously partially extracted
   756     if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
   757         CT_DoLog ERROR "The '${basename}' sources were partially extracted."
   758         CT_DoLog ERROR "Please remove first:"
   759         CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
   760         CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
   761         CT_Abort "I'll stop now to avoid any carnage..."
   762     fi
   763     CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
   764 
   765     CT_Pushd "${nochdir}"
   766 
   767     CT_DoLog EXTRA "Extracting '${basename}'"
   768     CT_DoExecLog FILE mkdir -p "${basename}"
   769     tar_opts=( "--strip-components=1" )
   770     tar_opts+=( "-C" "${basename}" )
   771     tar_opts+=( "-xv" )
   772 
   773     # One note here:
   774     # - lzma can be handled either with 'xz' or 'lzma'
   775     # - we get lzma tarball only if either or both are available
   776     # - so, if we get an lzma tarball, and either 'xz' or 'lzma' is
   777     #   missing, we can assume the other is available
   778     if [ "${CT_CONFIGURE_has_lzma}" = "y" ]; then
   779         lzma_prog="lzma -fdc"
   780     else
   781         lzma_prog="xz -fdc"
   782     fi
   783     case "${ext}" in
   784         .tar.xz)      xz -fdc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   785         .tar.lzma)    ${lzma_prog} "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   786         .tar.bz2)     bzip2 -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   787         .tar.gz|.tgz) gzip -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   788         .tar)         CT_DoExecLog FILE tar "${tar_opts[@]}" -f "${full_file}";;
   789         /.git)        CT_ExtractGit "${basename}" "${@}";;
   790         *)            CT_DoLog WARN "Don't know how to handle '${basename}${ext}': unknown extension"
   791                       return 1
   792                       ;;
   793     esac
   794 
   795     # Don't mark as being extracted for git
   796     case "${ext}" in
   797         /.git)  ;;
   798         *)      CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
   799     esac
   800     CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
   801 
   802     CT_Popd
   803 }
   804 
   805 # Create a working git clone of a local git repository
   806 # Usage: CT_ExtractGit <basename> [ref]
   807 # where 'ref' is the reference to use:
   808 #   the full name of a branch, like "remotes/origin/branch_name"
   809 #   a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
   810 #   a tag name
   811 # If 'ref' is not given, the current repository HEAD will be used
   812 CT_ExtractGit() {
   813     local basename="${1}"
   814     local ref="${2}"
   815     local repo
   816     local ref_type
   817 
   818     # pushd now to be able to get git revlist in case ref is a date
   819     repo="${CT_TARBALLS_DIR}/${basename}"
   820     CT_Pushd "${repo}"
   821 
   822     # What kind of reference is ${ref} ?
   823     if [ -z "${ref}" ]; then
   824         ref_type=head
   825         ref=$(git rev-list -n1 HEAD)
   826     elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
   827         ref_type=tag
   828     elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
   829         ref_type=branch
   830     elif date -d "${ref}" >/dev/null 2>&1; then
   831         ref_type=date
   832         ref=$(git rev-list -n1 --before="${ref}")
   833     else
   834         CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
   835     fi
   836 
   837     CT_Popd
   838 
   839     CT_DoExecLog FILE rmdir "${basename}"
   840     case "${ref_type}" in
   841         branch) CT_DoExecLog FILE git clone -b "${ref}" "${repo}" "${basename}" ;;
   842         *)      CT_DoExecLog FILE git clone "${repo}" "${basename}"
   843                 CT_Pushd "${basename}"
   844                 CT_DoExecLog FILE git checkout "${ref}"
   845                 CT_Popd
   846                 ;;
   847     esac
   848 }
   849 
   850 # Patches the specified component
   851 # See CT_Extract, above, for explanations on 'nochdir'
   852 # Usage: CT_Patch [nochdir] <packagename> <packageversion>
   853 # If the package directory is *not* packagename-packageversion, then
   854 # the caller must cd into the proper directory first, and call us
   855 # with nochdir
   856 CT_Patch() {
   857     local nochdir="$1"
   858     local pkgname
   859     local version
   860     local pkgdir
   861     local base_file
   862     local ver_file
   863     local d
   864     local -a patch_dirs
   865     local bundled_patch_dir
   866     local local_patch_dir
   867 
   868     if [ "${nochdir}" = "nochdir" ]; then
   869         shift
   870         pkgname="$1"
   871         version="$2"
   872         pkgdir="${pkgname}-${version}"
   873         nochdir="$(pwd)"
   874     else
   875         pkgname="$1"
   876         version="$2"
   877         pkgdir="${pkgname}-${version}"
   878         nochdir="${CT_SRC_DIR}/${pkgdir}"
   879     fi
   880 
   881     # Check if already patched
   882     if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
   883         CT_DoLog DEBUG "Already patched '${pkgdir}'"
   884         return 0
   885     fi
   886 
   887     # Check if already partially patched
   888     if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
   889         CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
   890         CT_DoLog ERROR "Please remove first:"
   891         CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
   892         CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
   893         CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
   894         CT_Abort "I'll stop now to avoid any carnage..."
   895     fi
   896     touch "${CT_SRC_DIR}/.${pkgdir}.patching"
   897 
   898     CT_Pushd "${nochdir}"
   899 
   900     CT_DoLog EXTRA "Patching '${pkgdir}'"
   901 
   902     bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
   903     local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
   904 
   905     case "${CT_PATCH_ORDER}" in
   906         bundled)        patch_dirs=("${bundled_patch_dir}");;
   907         local)          patch_dirs=("${local_patch_dir}");;
   908         bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
   909         local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
   910         none)           patch_dirs=;;
   911     esac
   912 
   913     for d in "${patch_dirs[@]}"; do
   914         CT_DoLog DEBUG "Looking for patches in '${d}'..."
   915         if [ -n "${d}" -a -d "${d}" ]; then
   916             for p in "${d}"/*.patch; do
   917                 if [ -f "${p}" ]; then
   918                     CT_DoLog DEBUG "Applying patch '${p}'"
   919                     CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f <"${p}"
   920                 fi
   921             done
   922             if [ "${CT_PATCH_SINGLE}" = "y" ]; then
   923                 break
   924             fi
   925         fi
   926     done
   927 
   928     if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
   929         CT_DoLog ALL "Overiding config.guess and config.sub"
   930         for cfg in config_guess config_sub; do
   931             eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
   932             [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
   933             # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
   934             find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
   935         done
   936     fi
   937 
   938     CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
   939     CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
   940 
   941     CT_Popd
   942 }
   943 
   944 # Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
   945 # Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
   946 CT_DoConfigGuess() {
   947     if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
   948         "${CT_TOP_DIR}/scripts/config.guess"
   949     else
   950         "${CT_LIB_DIR}/scripts/config.guess"
   951     fi
   952 }
   953 
   954 CT_DoConfigSub() {
   955     if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
   956         "${CT_TOP_DIR}/scripts/config.sub" "$@"
   957     else
   958         "${CT_LIB_DIR}/scripts/config.sub" "$@"
   959     fi
   960 }
   961 
   962 # Compute the target tuple from what is provided by the user
   963 # Usage: CT_DoBuildTargetTuple
   964 # In fact this function takes the environment variables to build the target
   965 # tuple. It is needed both by the normal build sequence, as well as the
   966 # sample saving sequence.
   967 CT_DoBuildTargetTuple() {
   968     # Set the endianness suffix, and the default endianness gcc option
   969     case "${CT_ARCH_ENDIAN}" in
   970         big)
   971             target_endian_eb=eb
   972             target_endian_el=
   973             CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
   974             CT_ARCH_ENDIAN_LDFLAG="-EB"
   975             ;;
   976         little)
   977             target_endian_eb=
   978             target_endian_el=el
   979             CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
   980             CT_ARCH_ENDIAN_LDFLAG="-EL"
   981             ;;
   982     esac
   983 
   984     # Build the default architecture tuple part
   985     CT_TARGET_ARCH="${CT_ARCH}"
   986 
   987     # Set defaults for the system part of the tuple. Can be overriden
   988     # by architecture-specific values.
   989     case "${CT_LIBC}" in
   990         *glibc) CT_TARGET_SYS=gnu;;
   991         uClibc) CT_TARGET_SYS=uclibc;;
   992         *)      CT_TARGET_SYS=elf;;
   993     esac
   994 
   995     # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
   996     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
   997     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
   998     [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
   999     [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
  1000     [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
  1001     [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
  1002     [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
  1003 
  1004     case "${CT_ARCH_FLOAT}" in
  1005         hard)
  1006             CT_ARCH_FLOAT_CFLAG="-mhard-float"
  1007             CT_ARCH_WITH_FLOAT="--with-float=hard"
  1008             ;;
  1009         soft)
  1010             CT_ARCH_FLOAT_CFLAG="-msoft-float"
  1011             CT_ARCH_WITH_FLOAT="--with-float=soft"
  1012             ;;
  1013         softfp)
  1014             CT_ARCH_FLOAT_CFLAG="-mfloat-abi=softfp"
  1015             CT_ARCH_WITH_FLOAT="--with-float=softfp"
  1016             ;;
  1017     esac
  1018 
  1019     # Build the default kernel tuple part
  1020     CT_TARGET_KERNEL="${CT_KERNEL}"
  1021 
  1022     # Overide the default values with the components specific settings
  1023     CT_DoArchTupleValues
  1024     CT_DoKernelTupleValues
  1025 
  1026     # Finish the target tuple construction
  1027     CT_TARGET="${CT_TARGET_ARCH}"
  1028     CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
  1029     CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
  1030     CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
  1031 
  1032     # Sanity checks
  1033     __sed_alias=""
  1034     if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
  1035         __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
  1036     fi
  1037     case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
  1038       :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
  1039       :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
  1040       :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
  1041       :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
  1042     esac
  1043 
  1044     # Canonicalise it
  1045     CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
  1046     # Prepare the target CFLAGS
  1047     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
  1048     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
  1049     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
  1050     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
  1051     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
  1052     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
  1053     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
  1054 
  1055     # Now on for the target LDFLAGS
  1056     CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
  1057 }
  1058 
  1059 # This function does pause the build until the user strikes "Return"
  1060 # Usage: CT_DoPause [optional_message]
  1061 CT_DoPause() {
  1062     local foo
  1063     local message="${1:-Pausing for your pleasure}"
  1064     CT_DoLog INFO "${message}"
  1065     read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
  1066     return 0
  1067 }
  1068 
  1069 # This function creates a tarball of the specified directory, but
  1070 # only if it exists
  1071 # Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
  1072 CT_DoTarballIfExists() {
  1073     local dir="$1"
  1074     local tarball="$2"
  1075     shift 2
  1076     local -a extra_tar_opts=( "$@" )
  1077     local -a compress
  1078 
  1079     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1080         y)  compress=( gzip -c -3 - ); tar_ext=.gz;;
  1081         *)  compress=( cat - );        tar_ext=;;
  1082     esac
  1083 
  1084     if [ -d "${dir}" ]; then
  1085         CT_DoLog DEBUG "  Saving '${dir}'"
  1086         { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" .    \
  1087           |"${compress[@]}" >"${tarball}.tar${tar_ext}"         ;
  1088         } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
  1089     else
  1090         CT_DoLog STATE "  Not saving '${dir}': does not exist"
  1091     fi
  1092 }
  1093 
  1094 # This function extracts a tarball to the specified directory, but
  1095 # only if the tarball exists
  1096 # Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
  1097 CT_DoExtractTarballIfExists() {
  1098     local tarball="$1"
  1099     local dir="$2"
  1100     shift 2
  1101     local -a extra_tar_opts=( "$@" )
  1102     local -a uncompress
  1103 
  1104     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1105         y)  uncompress=( gzip -c -d ); tar_ext=.gz;;
  1106         *)  uncompress=( cat );        tar_ext=;;
  1107     esac
  1108 
  1109     if [ -f "${tarball}.tar${tar_ext}" ]; then
  1110         CT_DoLog DEBUG "  Restoring '${dir}'"
  1111         CT_DoForceRmdir "${dir}"
  1112         CT_DoExecLog DEBUG mkdir -p "${dir}"
  1113         { "${uncompress[@]}" "${tarball}.tar${tar_ext}"     \
  1114           |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
  1115         } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
  1116     else
  1117         CT_DoLog STATE "  Not restoring '${dir}': does not exist"
  1118     fi
  1119 }
  1120 
  1121 # This function saves the state of the toolchain to be able to restart
  1122 # at any one point
  1123 # Usage: CT_DoSaveState <next_step_name>
  1124 CT_DoSaveState() {
  1125 	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
  1126     local state_name="$1"
  1127     local state_dir="${CT_STATE_DIR}/${state_name}"
  1128 
  1129     # Log this to the log level required by the user
  1130     CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
  1131 
  1132     rm -rf "${state_dir}"
  1133     mkdir -p "${state_dir}"
  1134 
  1135     CT_DoLog STATE "  Saving environment and aliases"
  1136     # We must omit shell functions, and some specific bash variables
  1137     # that break when restoring the environment, later. We could do
  1138     # all the processing in the awk script, but a sed is easier...
  1139     set |awk '
  1140               BEGIN { _p = 1; }
  1141               $0~/^[^ ]+ \(\)/ { _p = 0; }
  1142               _p == 1
  1143               $0 == "}" { _p = 1; }
  1144               ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
  1145                            /^(UID|EUID)=/d;
  1146                            /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
  1147 
  1148     CT_DoTarballIfExists "${CT_BUILDTOOLS_PREFIX_DIR}" "${state_dir}/buildtools_dir"
  1149     CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
  1150     CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
  1151 
  1152     CT_DoLog STATE "  Saving log file"
  1153     exec >/dev/null
  1154     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1155         y)  gzip -3 -c "${tmp_log_file}"  >"${state_dir}/log.gz";;
  1156         *)  cat "${tmp_log_file}" >"${state_dir}/log";;
  1157     esac
  1158     exec >>"${tmp_log_file}"
  1159 }
  1160 
  1161 # This function restores a previously saved state
  1162 # Usage: CT_DoLoadState <state_name>
  1163 CT_DoLoadState(){
  1164     local state_name="$1"
  1165     local state_dir="${CT_STATE_DIR}/${state_name}"
  1166     local old_RESTART="${CT_RESTART}"
  1167     local old_STOP="${CT_STOP}"
  1168 
  1169     CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
  1170 
  1171     # We need to do something special with the log file!
  1172     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
  1173         exec >"${state_dir}/tail.log"
  1174     fi
  1175 
  1176     # Log this to the log level required by the user
  1177     CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
  1178 
  1179     CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
  1180     CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
  1181     CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_PREFIX_DIR}"
  1182 
  1183     # Restore the environment, discarding any error message
  1184     # (for example, read-only bash internals)
  1185     CT_DoLog STATE "  Restoring environment"
  1186     . "${state_dir}/env.sh" >/dev/null 2>&1 || true
  1187 
  1188     # Restore the new RESTART and STOP steps
  1189     CT_RESTART="${old_RESTART}"
  1190     CT_STOP="${old_STOP}"
  1191     unset old_stop old_restart
  1192 
  1193     CT_DoLog STATE "  Restoring log file"
  1194     exec >/dev/null
  1195     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1196         y)  zcat "${state_dir}/log.gz" >"${tmp_log_file}";;
  1197         *)  cat "${state_dir}/log" >"${tmp_log_file}";;
  1198     esac
  1199     cat "${state_dir}/tail.log" >>"${tmp_log_file}"
  1200     exec >>"${tmp_log_file}"
  1201     rm -f "${state_dir}/tail.log"
  1202 }