scripts/functions
author Michael Hope <michael.hope@linaro.org>
Wed Oct 19 15:27:32 2011 +1300 (2011-10-19)
changeset 2739 f320e22f2cba
parent 2738 149c33923f47
child 2763 3f1798d436da
permissions -rw-r--r--
arch: add softfp support

Some architectures support a mixed hard/soft floating point, where
the compiler emits hardware floating point instructions, but passes
the operands in core (aka integer) registers.

For example, ARM supports this mode (to come in the next changeset).

Add support for softfp cross compilers to the GCC and GLIBC
configuration. Needed for Ubuntu and other distros that are softfp.

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