scripts/functions
author Cody Schafer <dev@codyps.com>
Fri May 09 19:13:49 2014 -0700 (2014-05-09)
changeset 3312 4876ff97e039
parent 3307 d7eaba5831d5
child 3314 f3f518cafd8a
permissions -rw-r--r--
cc/gcc: allow CC_EXTRA_CONFIG_ARRAY on baremetal

The final bare-metal compiler is built using the core backend.
Currently the core uses the CC_CORE_EXTRA_CONFIG_ARRAY variable.

While this works as supposed to, this can leave the user puzzled
in the menuconfig, since all he can see is the core options, not
the final options.

Only show the core options if any of the core passes are needed,
and use the final options in the core-backend if we're issuing
the bare-metal compiler.

Signed-off-by: Cody P Schafer <dev@codyps.com>
[yann.morin.1998@free.fr: hide core options if no core pass needed;
use final option in core backend if issuing the bare-metal compiler]
Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
Message-Id: <22181e546ba746202489.1399688067@localhost>
Patchwork-Id: 347586
     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     if [ ${CT_CONNECT_TIMEOUT} = -1 ]; then
   575         T=
   576     else
   577         T="-T ${CT_CONNECT_TIMEOUT}"
   578     fi
   579     if CT_DoExecLog ALL wget --passive-ftp --tries=3 -nc    \
   580                              --progress=dot:binary          \
   581                              ${T}                           \
   582                              -O "${tmp}"                    \
   583                              "${url}"
   584     then
   585         # Success, we got it, good!
   586         mv "${tmp}" "${dest}"
   587         CT_DoLog DEBUG "Got it from: \"${url}\""
   588     else
   589         # Woops...
   590         rm -f "${tmp}"
   591         CT_DoLog DEBUG "Not at this location: \"${url}\""
   592     fi
   593 }
   594 
   595 # This function tries to retrieve a tarball form a local directory
   596 # Usage: CT_GetLocal <basename> [.extension]
   597 CT_GetLocal() {
   598     local basename="$1"
   599     local first_ext="$2"
   600     local ext
   601 
   602     # Do we already have it in *our* tarballs dir?
   603     if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
   604         CT_DoLog DEBUG "Already have '${basename}'"
   605         return 0
   606     fi
   607 
   608     if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
   609         CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
   610         # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
   611         # or, as a failover, a file without extension.
   612         for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
   613             CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
   614             if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
   615                  "${CT_FORCE_DOWNLOAD}" != "y" ]; then
   616                 CT_DoLog DEBUG "Got '${basename}' from local storage"
   617                 CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
   618                 return 0
   619             fi
   620         done
   621     fi
   622     return 1
   623 }
   624 
   625 # This function gets the custom source from either a tarball or directory
   626 # Usage: CT_GetCustom <component> <custom_version> <custom_location>
   627 CT_GetCustom() {
   628     local custom_component="$1"
   629     local custom_version="$2"
   630     local custom_location="$3"
   631     local custom_name="${custom_component}-${custom_version}"
   632 
   633     CT_TestAndAbort "${custom_name}: CT_CUSTOM_LOCATION_ROOT_DIR or ${custom_component}'s CUSTOM_LOCATION must be set." \
   634                     -z "${CT_CUSTOM_LOCATION_ROOT_DIR}" -a -z "${custom_location}"
   635 
   636     if [ -n "${CT_CUSTOM_LOCATION_ROOT_DIR}" \
   637          -a -z "${custom_location}"          ]; then
   638         custom_location="${CT_CUSTOM_LOCATION_ROOT_DIR}/${custom_component}"
   639     fi
   640 
   641     CT_DoLog EXTRA "Using '${custom_name}' from custom location"
   642     if [ ! -d "${custom_location}" ]; then
   643         # We need to know the custom tarball extension,
   644         # so we can create a properly-named symlink, which
   645         # we use later on in 'extract'
   646         case "${custom_location}" in
   647             *.tar.xz)       custom_name="${custom_name}.tar.xz";;
   648             *.tar.bz2)      custom_name="${custom_name}.tar.bz2";;
   649             *.tar.gz|*.tgz) custom_name="${custom_name}.tar.gz";;
   650             *.tar)          custom_name="${custom_name}.tar";;
   651             *)  CT_Abort "Unknown extension for custom tarball '${custom_location}'";;
   652         esac
   653         CT_DoExecLog DEBUG ln -sf "${custom_location}"  \
   654                                   "${CT_TARBALLS_DIR}/${custom_name}"
   655     else
   656         CT_DoExecLog DEBUG ln -snf "${custom_location}" \
   657                                    "${CT_SRC_DIR}/${custom_name}"
   658     fi
   659 }
   660 
   661 # This function saves the specified to local storage if possible,
   662 # and if so, symlinks it for later usage
   663 # Usage: CT_SaveLocal </full/path/file.name>
   664 CT_SaveLocal() {
   665     local file="$1"
   666     local basename="${file##*/}"
   667 
   668     if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
   669         CT_DoLog EXTRA "Saving '${basename}' to local storage"
   670         # The file may already exist if downloads are forced: remove it first
   671         CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
   672         CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
   673         CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
   674     fi
   675 }
   676 
   677 # Download the file from one of the URLs passed as argument
   678 # Usage: CT_GetFile <basename> [.extension] <url> [url ...]
   679 CT_GetFile() {
   680     local ext
   681     local -a URLS
   682     local url
   683     local file="$1"
   684     local first_ext
   685     shift
   686     # If next argument starts with a dot, then this is not an URL,
   687     # and we can consider that it is a preferred extension.
   688     case "$1" in
   689         .*) first_ext="$1"
   690             shift
   691             ;;
   692     esac
   693 
   694     # Does it exist localy?
   695     if CT_GetLocal "${file}" ${first_ext}; then
   696         return 0
   697     fi
   698     # No, it does not...
   699 
   700     # If not allowed to download from the Internet, don't
   701     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   702         CT_DoLog DEBUG "Not allowed to download from the Internet, aborting ${file} download"
   703         return 1
   704     fi
   705 
   706     # Try to retrieve the file
   707     CT_DoLog EXTRA "Retrieving '${file}'"
   708 
   709     # Add URLs on the LAN mirror
   710     if [ "${CT_USE_MIRROR}" = "y" ]; then
   711         CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
   712         URLS+=( "${CT_MIRROR_BASE_URL}/${file%-*}" )
   713         URLS+=( "${CT_MIRROR_BASE_URL}" )
   714     fi
   715 
   716     if [ "${CT_FORCE_MIRROR}" != "y" ]; then
   717         URLS+=( "${@}" )
   718     fi
   719 
   720     # Scan all URLs in turn, and try to grab a tarball from there
   721     # Do *not* try git trees (ext=/.git), this is handled in a specific
   722     # wrapper, below
   723     for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
   724         # Try all urls in turn
   725         for url in "${URLS[@]}"; do
   726             [ -n "${url}" ] || continue
   727             CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
   728             CT_DoGetFile "${url}/${file}${ext}"
   729             if [ -f "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
   730                 CT_DoLog DEBUG "Got '${file}' from the Internet"
   731                 CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
   732                 return 0
   733             fi
   734         done
   735     done
   736 
   737     # Just return error, someone may want to catch and handle the error
   738     # (eg. glibc/eglibc add-ons can be missing).
   739     return 1
   740 }
   741 
   742 # Checkout from CVS, and build the associated tarball
   743 # The tarball will be called ${basename}.tar.bz2
   744 # Prerequisite: either the server does not require password,
   745 # or the user must already be logged in.
   746 # 'tag' is the tag to retrieve. Must be specified, but can be empty.
   747 # If dirname is specified, then module will be renamed to dirname
   748 # prior to building the tarball.
   749 # Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
   750 # Note: if '=subdir' is given, then it is used instead of 'module'.
   751 CT_GetCVS() {
   752     local basename="$1"
   753     local uri="$2"
   754     local module="$3"
   755     local tag="${4:+-r ${4}}"
   756     local dirname="$5"
   757     local tmp_dir
   758 
   759     # First try locally, then the mirror
   760     if CT_GetFile "${basename}"; then
   761         # Got it! Return early! :-)
   762         return 0
   763     fi
   764 
   765     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   766         CT_DoLog WARN "Downloads forbidden, not trying cvs retrieval"
   767         return 1
   768     fi
   769 
   770     CT_MktempDir tmp_dir
   771     CT_Pushd "${tmp_dir}"
   772 
   773     CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
   774     if [ -n "${dirname}" ]; then
   775         case "${dirname}" in
   776             *=*)
   777                 CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
   778                 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
   779                 ;;
   780             *)
   781                 CT_DoExecLog ALL mv "${module}" "${dirname}"
   782                 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
   783                 ;;
   784         esac
   785     fi
   786     CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
   787 
   788     CT_Popd
   789     CT_DoExecLog ALL rm -rf "${tmp_dir}"
   790 }
   791 
   792 # Check out from SVN, and build the associated tarball
   793 # The tarball will be called ${basename}.tar.bz2
   794 # Prerequisite: either the server does not require password,
   795 # or the user must already be logged in.
   796 # 'rev' is the revision to retrieve
   797 # Usage: CT_GetSVN <basename> <url> [rev]
   798 CT_GetSVN() {
   799     local basename="$1"
   800     local uri="$2"
   801     local rev="$3"
   802 
   803     # First try locally, then the mirror
   804     if CT_GetFile "${basename}"; then
   805         # Got it! Return early! :-)
   806         return 0
   807     fi
   808 
   809     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   810         CT_DoLog WARN "Downloads forbidden, not trying svn retrieval"
   811         return 1
   812     fi
   813 
   814     CT_MktempDir tmp_dir
   815     CT_Pushd "${tmp_dir}"
   816 
   817     if ! CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"; then
   818         CT_DoLog WARN "Could not retrieve '${basename}'"
   819         return 1
   820     fi
   821     CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
   822     CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
   823 
   824     CT_Popd
   825     CT_DoExecLog ALL rm -rf "${tmp_dir}"
   826 }
   827 
   828 # Clone a git tree
   829 # Tries the given URLs in turn until one can get cloned. No tarball will be created.
   830 # Prerequisites: either the server does not require password,
   831 # or the user has already taken any action to authenticate to the server.
   832 # The cloned tree will *not* be stored in the local tarballs dir!
   833 # Usage: CT_GetGit <basename> <url [url ...]>
   834 CT_GetGit() {
   835     local basename="$1"; shift
   836     local url
   837     local cloned=0
   838 
   839     if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
   840         CT_DoLog WARN "Downloads forbidden, not trying git retrieval"
   841         return 1
   842     fi
   843 
   844     # Do we have it in our tarballs dir?
   845     if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
   846         CT_DoLog EXTRA "Updating git tree '${basename}'"
   847         CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
   848         CT_DoExecLog ALL git pull
   849         CT_Popd
   850     else
   851         CT_DoLog EXTRA "Retrieving git tree '${basename}'"
   852         for url in "${@}"; do
   853             CT_DoLog ALL "Trying to clone from '${url}'"
   854             CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
   855             if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
   856                 cloned=1
   857                 break
   858             fi
   859         done
   860         CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
   861     fi
   862 }
   863 
   864 # Extract a tarball
   865 # Some tarballs need to be extracted in specific places. Eg.: glibc addons
   866 # must be extracted in the glibc directory; uCLibc locales must be extracted
   867 # in the extra/locale sub-directory of uClibc. This is taken into account
   868 # by the caller, that did a 'cd' into the correct path before calling us
   869 # and sets nochdir to 'nochdir'.
   870 # Note also that this function handles the git trees!
   871 # Usage: CT_Extract [nochdir] <basename> [options]
   872 # where 'options' are dependent on the source (eg. git branch/tag...)
   873 CT_Extract() {
   874     local nochdir="$1"
   875     local basename
   876     local ext
   877     local lzma_prog
   878     local -a tar_opts
   879 
   880     if [ "${nochdir}" = "nochdir" ]; then
   881         shift
   882         nochdir="$(pwd)"
   883     else
   884         nochdir="${CT_SRC_DIR}"
   885     fi
   886 
   887     basename="$1"
   888     shift
   889 
   890     if ! ext="$(CT_GetFileExtension "${basename}")"; then
   891         CT_DoLog WARN "'${basename}' not found in '${CT_TARBALLS_DIR}'"
   892         return 1
   893     fi
   894     local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
   895 
   896     # Check if already extracted
   897     if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
   898         CT_DoLog DEBUG "Already extracted '${basename}'"
   899         return 0
   900     fi
   901 
   902     # Check if previously partially extracted
   903     if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
   904         CT_DoLog ERROR "The '${basename}' sources were partially extracted."
   905         CT_DoLog ERROR "Please remove first:"
   906         CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
   907         CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
   908         CT_Abort "I'll stop now to avoid any carnage..."
   909     fi
   910     CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
   911 
   912     CT_Pushd "${nochdir}"
   913 
   914     CT_DoLog EXTRA "Extracting '${basename}'"
   915     CT_DoExecLog FILE mkdir -p "${basename}"
   916     tar_opts=( "--strip-components=1" )
   917     tar_opts+=( "-C" "${basename}" )
   918     tar_opts+=( "-xv" )
   919 
   920     # One note here:
   921     # - lzma can be handled either with 'xz' or 'lzma'
   922     # - we get lzma tarball only if either or both are available
   923     # - so, if we get an lzma tarball, and either 'xz' or 'lzma' is
   924     #   missing, we can assume the other is available
   925     if [ "${CT_CONFIGURE_has_lzma}" = "y" ]; then
   926         lzma_prog="lzma -fdc"
   927     else
   928         lzma_prog="xz -fdc"
   929     fi
   930     case "${ext}" in
   931         .tar.xz)      xz -fdc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   932         .tar.lzma)    ${lzma_prog} "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   933         .tar.bz2)     bzip2 -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   934         .tar.gz|.tgz) gzip -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
   935         .tar)         CT_DoExecLog FILE tar "${tar_opts[@]}" -f "${full_file}";;
   936         .zip)         CT_DoExecLog FILE unzip "${@}" "${full_file}";;
   937         /.git)        CT_ExtractGit "${basename}" "${@}";;
   938         *)            CT_DoLog WARN "Don't know how to handle '${basename}${ext}': unknown extension"
   939                       return 1
   940                       ;;
   941     esac
   942 
   943     # Don't mark as being extracted for git
   944     case "${ext}" in
   945         /.git)  ;;
   946         *)      CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
   947     esac
   948     CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
   949 
   950     CT_Popd
   951 }
   952 
   953 # Create a working git clone of a local git repository
   954 # Usage: CT_ExtractGit <basename> [ref]
   955 # where 'ref' is the reference to use:
   956 #   the full name of a branch, like "remotes/origin/branch_name"
   957 #   a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
   958 #   a tag name
   959 # If 'ref' is not given, the current repository HEAD will be used
   960 CT_ExtractGit() {
   961     local basename="${1}"
   962     local ref="${2}"
   963     local repo
   964     local ref_type
   965 
   966     # pushd now to be able to get git revlist in case ref is a date
   967     repo="${CT_TARBALLS_DIR}/${basename}"
   968     CT_Pushd "${repo}"
   969 
   970     # What kind of reference is ${ref} ?
   971     if [ -z "${ref}" ]; then
   972         ref_type=head
   973         ref=$(git rev-list -n1 HEAD)
   974     elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
   975         ref_type=tag
   976     elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
   977         ref_type=branch
   978     elif date -d "${ref}" >/dev/null 2>&1; then
   979         ref_type=date
   980         ref=$(git rev-list -n1 --before="${ref}")
   981     else
   982         CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
   983     fi
   984 
   985     CT_Popd
   986 
   987     CT_DoExecLog FILE rmdir "${basename}"
   988     case "${ref_type}" in
   989         branch) CT_DoExecLog FILE git clone -b "${ref}" "${repo}" "${basename}" ;;
   990         *)      CT_DoExecLog FILE git clone "${repo}" "${basename}"
   991                 CT_Pushd "${basename}"
   992                 CT_DoExecLog FILE git checkout "${ref}"
   993                 CT_Popd
   994                 ;;
   995     esac
   996 }
   997 
   998 # Patches the specified component
   999 # See CT_Extract, above, for explanations on 'nochdir'
  1000 # Usage: CT_Patch [nochdir] <packagename> <packageversion>
  1001 # If the package directory is *not* packagename-packageversion, then
  1002 # the caller must cd into the proper directory first, and call us
  1003 # with nochdir
  1004 CT_Patch() {
  1005     local nochdir="$1"
  1006     local pkgname
  1007     local version
  1008     local pkgdir
  1009     local base_file
  1010     local ver_file
  1011     local d
  1012     local -a patch_dirs
  1013     local bundled_patch_dir
  1014     local local_patch_dir
  1015 
  1016     if [ "${nochdir}" = "nochdir" ]; then
  1017         shift
  1018         pkgname="$1"
  1019         version="$2"
  1020         pkgdir="${pkgname}-${version}"
  1021         nochdir="$(pwd)"
  1022     else
  1023         pkgname="$1"
  1024         version="$2"
  1025         pkgdir="${pkgname}-${version}"
  1026         nochdir="${CT_SRC_DIR}/${pkgdir}"
  1027     fi
  1028 
  1029     # Check if already patched
  1030     if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
  1031         CT_DoLog DEBUG "Already patched '${pkgdir}'"
  1032         return 0
  1033     fi
  1034 
  1035     # Check if already partially patched
  1036     if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
  1037         CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
  1038         CT_DoLog ERROR "Please remove first:"
  1039         CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
  1040         CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
  1041         CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
  1042         CT_Abort "I'll stop now to avoid any carnage..."
  1043     fi
  1044     touch "${CT_SRC_DIR}/.${pkgdir}.patching"
  1045 
  1046     CT_Pushd "${nochdir}"
  1047 
  1048     CT_DoLog EXTRA "Patching '${pkgdir}'"
  1049 
  1050     bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
  1051     local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
  1052 
  1053     case "${CT_PATCH_ORDER}" in
  1054         bundled)        patch_dirs=("${bundled_patch_dir}");;
  1055         local)          patch_dirs=("${local_patch_dir}");;
  1056         bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
  1057         local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
  1058         none)           patch_dirs=;;
  1059     esac
  1060 
  1061     for d in "${patch_dirs[@]}"; do
  1062         CT_DoLog DEBUG "Looking for patches in '${d}'..."
  1063         if [ -n "${d}" -a -d "${d}" ]; then
  1064             for p in "${d}"/*.patch; do
  1065                 if [ -f "${p}" ]; then
  1066                     CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f -i "${p}"
  1067                 fi
  1068             done
  1069             if [ "${CT_PATCH_SINGLE}" = "y" ]; then
  1070                 break
  1071             fi
  1072         fi
  1073     done
  1074 
  1075     if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
  1076         CT_DoLog ALL "Overiding config.guess and config.sub"
  1077         for cfg in config_guess config_sub; do
  1078             eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
  1079             [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
  1080             # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
  1081             find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
  1082         done
  1083     fi
  1084 
  1085     CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
  1086     CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
  1087 
  1088     CT_Popd
  1089 }
  1090 
  1091 # Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
  1092 # Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
  1093 CT_DoConfigGuess() {
  1094     if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
  1095         "${CT_TOP_DIR}/scripts/config.guess"
  1096     else
  1097         "${CT_LIB_DIR}/scripts/config.guess"
  1098     fi
  1099 }
  1100 
  1101 CT_DoConfigSub() {
  1102     if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
  1103         "${CT_TOP_DIR}/scripts/config.sub" "$@"
  1104     else
  1105         "${CT_LIB_DIR}/scripts/config.sub" "$@"
  1106     fi
  1107 }
  1108 
  1109 # Compute the target tuple from what is provided by the user
  1110 # Usage: CT_DoBuildTargetTuple
  1111 # In fact this function takes the environment variables to build the target
  1112 # tuple. It is needed both by the normal build sequence, as well as the
  1113 # sample saving sequence.
  1114 CT_DoBuildTargetTuple() {
  1115     # Set the endianness suffix, and the default endianness gcc option
  1116     case "${CT_ARCH_ENDIAN}" in
  1117         big)
  1118             target_endian_eb=eb
  1119             target_endian_el=
  1120             CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
  1121             CT_ARCH_ENDIAN_LDFLAG="-Wl,-EB"
  1122             ;;
  1123         little)
  1124             target_endian_eb=
  1125             target_endian_el=el
  1126             CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
  1127             CT_ARCH_ENDIAN_LDFLAG="-Wl,-EL"
  1128             ;;
  1129     esac
  1130 
  1131     # Build the default architecture tuple part
  1132     CT_TARGET_ARCH="${CT_ARCH}${CT_ARCH_SUFFIX}"
  1133 
  1134     # Set defaults for the system part of the tuple. Can be overriden
  1135     # by architecture-specific values.
  1136     case "${CT_LIBC}" in
  1137         *glibc) CT_TARGET_SYS=gnu;;
  1138         uClibc) CT_TARGET_SYS=uclibc;;
  1139         *)      CT_TARGET_SYS=elf;;
  1140     esac
  1141 
  1142     # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
  1143     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
  1144     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
  1145     [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
  1146     [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
  1147     [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
  1148     [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
  1149     [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
  1150 
  1151     case "${CT_ARCH_FLOAT}" in
  1152         hard)
  1153             CT_ARCH_FLOAT_CFLAG="-mhard-float"
  1154             CT_ARCH_WITH_FLOAT="--with-float=hard"
  1155             ;;
  1156         soft)
  1157             CT_ARCH_FLOAT_CFLAG="-msoft-float"
  1158             CT_ARCH_WITH_FLOAT="--with-float=soft"
  1159             ;;
  1160         softfp)
  1161             CT_ARCH_FLOAT_CFLAG="-mfloat-abi=softfp"
  1162             CT_ARCH_WITH_FLOAT="--with-float=softfp"
  1163             ;;
  1164     esac
  1165 
  1166     # Build the default kernel tuple part
  1167     CT_TARGET_KERNEL="${CT_KERNEL}"
  1168 
  1169     # Overide the default values with the components specific settings
  1170     CT_DoArchTupleValues
  1171     CT_DoKernelTupleValues
  1172 
  1173     # Finish the target tuple construction
  1174     CT_TARGET="${CT_TARGET_ARCH}"
  1175     CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
  1176     CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
  1177     CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
  1178 
  1179     # Sanity checks
  1180     __sed_alias=""
  1181     if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
  1182         __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
  1183     fi
  1184     case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
  1185       :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
  1186       :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
  1187       :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
  1188       :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
  1189     esac
  1190 
  1191     # Canonicalise it
  1192     CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
  1193     # Prepare the target CFLAGS
  1194     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
  1195     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
  1196     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
  1197     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
  1198     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
  1199     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
  1200     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
  1201 
  1202     # Now on for the target LDFLAGS
  1203     CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
  1204 }
  1205 
  1206 # This function does pause the build until the user strikes "Return"
  1207 # Usage: CT_DoPause [optional_message]
  1208 CT_DoPause() {
  1209     local foo
  1210     local message="${1:-Pausing for your pleasure}"
  1211     CT_DoLog INFO "${message}"
  1212     read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
  1213     return 0
  1214 }
  1215 
  1216 # This function creates a tarball of the specified directory, but
  1217 # only if it exists
  1218 # Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
  1219 CT_DoTarballIfExists() {
  1220     local dir="$1"
  1221     local tarball="$2"
  1222     shift 2
  1223     local -a extra_tar_opts=( "$@" )
  1224     local -a compress
  1225 
  1226     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1227         y)  compress=( gzip -c -3 - ); tar_ext=.gz;;
  1228         *)  compress=( cat - );        tar_ext=;;
  1229     esac
  1230 
  1231     if [ -d "${dir}" ]; then
  1232         CT_DoLog DEBUG "  Saving '${dir}'"
  1233         { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" .    \
  1234           |"${compress[@]}" >"${tarball}.tar${tar_ext}"         ;
  1235         } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
  1236     else
  1237         CT_DoLog STATE "  Not saving '${dir}': does not exist"
  1238     fi
  1239 }
  1240 
  1241 # This function extracts a tarball to the specified directory, but
  1242 # only if the tarball exists
  1243 # Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
  1244 CT_DoExtractTarballIfExists() {
  1245     local tarball="$1"
  1246     local dir="$2"
  1247     shift 2
  1248     local -a extra_tar_opts=( "$@" )
  1249     local -a uncompress
  1250 
  1251     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1252         y)  uncompress=( gzip -c -d ); tar_ext=.gz;;
  1253         *)  uncompress=( cat );        tar_ext=;;
  1254     esac
  1255 
  1256     if [ -f "${tarball}.tar${tar_ext}" ]; then
  1257         CT_DoLog DEBUG "  Restoring '${dir}'"
  1258         CT_DoForceRmdir "${dir}"
  1259         CT_DoExecLog DEBUG mkdir -p "${dir}"
  1260         { "${uncompress[@]}" "${tarball}.tar${tar_ext}"     \
  1261           |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
  1262         } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
  1263     else
  1264         CT_DoLog STATE "  Not restoring '${dir}': does not exist"
  1265     fi
  1266 }
  1267 
  1268 # This function saves the state of the toolchain to be able to restart
  1269 # at any one point
  1270 # Usage: CT_DoSaveState <next_step_name>
  1271 CT_DoSaveState() {
  1272 	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
  1273     local state_name="$1"
  1274     local state_dir="${CT_STATE_DIR}/${state_name}"
  1275 
  1276     # Log this to the log level required by the user
  1277     CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
  1278 
  1279     rm -rf "${state_dir}"
  1280     mkdir -p "${state_dir}"
  1281 
  1282     CT_DoLog STATE "  Saving environment and aliases"
  1283     # We must omit shell functions, and some specific bash variables
  1284     # that break when restoring the environment, later. We could do
  1285     # all the processing in the awk script, but a sed is easier...
  1286     set |awk '
  1287               BEGIN { _p = 1; }
  1288               $0~/^[^ ]+ \(\)/ { _p = 0; }
  1289               _p == 1
  1290               $0 == "}" { _p = 1; }
  1291               ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
  1292                            /^(UID|EUID)=/d;
  1293                            /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
  1294 
  1295     CT_DoTarballIfExists "${CT_BUILDTOOLS_PREFIX_DIR}" "${state_dir}/buildtools_dir"
  1296     CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
  1297     CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
  1298 
  1299     CT_DoLog STATE "  Saving log file"
  1300     exec >/dev/null
  1301     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1302         y)  gzip -3 -c "${tmp_log_file}"  >"${state_dir}/log.gz";;
  1303         *)  cat "${tmp_log_file}" >"${state_dir}/log";;
  1304     esac
  1305     exec >>"${tmp_log_file}"
  1306 }
  1307 
  1308 # This function restores a previously saved state
  1309 # Usage: CT_DoLoadState <state_name>
  1310 CT_DoLoadState(){
  1311     local state_name="$1"
  1312     local state_dir="${CT_STATE_DIR}/${state_name}"
  1313     local old_RESTART="${CT_RESTART}"
  1314     local old_STOP="${CT_STOP}"
  1315 
  1316     CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
  1317 
  1318     # We need to do something special with the log file!
  1319     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
  1320         exec >"${state_dir}/tail.log"
  1321     fi
  1322 
  1323     # Log this to the log level required by the user
  1324     CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
  1325 
  1326     CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
  1327     CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
  1328     CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_PREFIX_DIR}"
  1329 
  1330     # Restore the environment, discarding any error message
  1331     # (for example, read-only bash internals)
  1332     CT_DoLog STATE "  Restoring environment"
  1333     . "${state_dir}/env.sh" >/dev/null 2>&1 || true
  1334 
  1335     # Restore the new RESTART and STOP steps
  1336     CT_RESTART="${old_RESTART}"
  1337     CT_STOP="${old_STOP}"
  1338     unset old_stop old_restart
  1339 
  1340     CT_DoLog STATE "  Restoring log file"
  1341     exec >/dev/null
  1342     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
  1343         y)  gzip -dc "${state_dir}/log.gz" >"${tmp_log_file}";;
  1344         *)  cat "${state_dir}/log" >"${tmp_log_file}";;
  1345     esac
  1346     cat "${state_dir}/tail.log" >>"${tmp_log_file}"
  1347     exec >>"${tmp_log_file}"
  1348     rm -f "${state_dir}/tail.log"
  1349 }