scripts/functions
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Sun May 05 00:01:05 2013 +0200 (2013-05-05)
changeset 3218 3709e61ad85b
parent 3205 30de175d3ed3
child 3247 01ef2159b12a
permissions -rw-r--r--
complibs/cloog: add support for the ISL backend

CLooG 0.18+ will use ISL instead of PPL, so we have to configure
adequately depending of which backend is in use.

The Kconfig entries will decide for us which is selected, so we
can rely on either PPL xor ISL to be selected, not both.

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