scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sat May 03 17:51:16 2008 +0000 (2008-05-03)
changeset 486 92f6149c4275
parent 439 dd62fca2d6fd
child 492 ef8ef3493392
child 511 1b0c1de0bcc9
permissions -rw-r--r--
Some people are reposrting that ftp does not work on their network, probably due to proxies, while http does work.
Some (most) of the sites we use toretrieve tarballs have http equivallent for the ftp service. Use http as a failover.
There's no solution for those sites that do not have such an http equivalent.

/trunk/scripts/build/binutils.sh | 5 2 3 0 ++---
/trunk/scripts/build/libc_glibc.sh | 4 2 2 0 ++--
/trunk/scripts/build/libc_uClibc.sh | 2 1 1 0 +-
/trunk/scripts/build/debug/400-ltrace.sh | 2 1 1 0 +-
/trunk/scripts/build/debug/300-gdb.sh | 8 3 5 0 +++-----
/trunk/scripts/build/kernel_linux.sh | 7 2 5 0 ++-----
/trunk/scripts/build/cc_gcc.sh | 6 2 4 0 ++----
/trunk/scripts/build/gmp.sh | 4 1 3 0 +---
8 files changed, 14 insertions(+), 24 deletions(-)
     1 # This file contains some usefull common functions
     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     ret=$?
     8     CT_DoLog ERROR "Build failed in step \"${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}\""
     9     for((step=(CT_STEP_COUNT-1); step>1; step--)); do
    10         CT_DoLog ERROR "      called in step \"${CT_STEP_MESSAGE[${step}]}\""
    11     done
    12     CT_DoLog ERROR "Error happened in \"${BASH_SOURCE[1]}\" in function \"${FUNCNAME[1]}\" (line unknown, sorry)"
    13     for((depth=2; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
    14         CT_DoLog ERROR "      called from \"${BASH_SOURCE[${depth}]}\" at line # ${BASH_LINENO[${depth}-1]} in function \"${FUNCNAME[${depth}]}\""
    15     done
    16     [ "${CT_LOG_TO_FILE}" = "y" ] && CT_DoLog ERROR "Look at \"${CT_LOG_FILE}\" for more info on this error."
    17     CT_STEP_COUNT=1
    18     CT_DoEnd ERROR
    19     exit $ret
    20 }
    21 
    22 # Install the fault handler
    23 trap CT_OnError ERR
    24 
    25 # Inherit the fault handler in subshells and functions
    26 set -E
    27 
    28 # Make pipes fail on the _first_ failed command
    29 # Not supported on bash < 3.x, but we need it, so drop the obsoleting bash-2.x
    30 set -o pipefail
    31 
    32 # Don't hash commands' locations, and search every time it is requested.
    33 # This is slow, but needed because of the static/shared core gcc which shall
    34 # always match to shared if it exists, and only fallback to static if the
    35 # shared is not found
    36 set +o hashall
    37 
    38 # Log policy:
    39 #  - first of all, save stdout so we can see the live logs: fd #6
    40 exec 6>&1
    41 #  - then point stdout to the log file (temporary for now)
    42 tmp_log_file="${CT_TOP_DIR}/log.$$"
    43 exec >>"${tmp_log_file}"
    44 
    45 # The different log levels:
    46 CT_LOG_LEVEL_ERROR=0
    47 CT_LOG_LEVEL_WARN=1
    48 CT_LOG_LEVEL_INFO=2
    49 CT_LOG_LEVEL_EXTRA=3
    50 CT_LOG_LEVEL_DEBUG=4
    51 CT_LOG_LEVEL_ALL=5
    52 
    53 # A function to log what is happening
    54 # Different log level are available:
    55 #   - ERROR:   A serious, fatal error occurred
    56 #   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
    57 #   - INFO:    Informational messages
    58 #   - EXTRA:   Extra informational messages
    59 #   - DEBUG:   Debug messages
    60 #   - ALL:     Component's build messages
    61 # Usage: CT_DoLog <level> [message]
    62 # If message is empty, then stdin will be logged.
    63 CT_DoLog() {
    64     local max_level LEVEL level cur_l cur_L
    65     local l
    66     eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
    67     # Set the maximum log level to DEBUG if we have none
    68     [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
    69 
    70     LEVEL="$1"; shift
    71     eval level="\${CT_LOG_LEVEL_${LEVEL}}"
    72 
    73     if [ $# -eq 0 ]; then
    74         cat -
    75     else
    76         echo "${1}"
    77     fi |( IFS="\n" # We want the full lines, even leading spaces
    78           CT_PROG_BAR_CPT=0
    79           indent=$((2*CT_STEP_COUNT))
    80           while read line; do
    81               case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
    82                 y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
    83                 y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
    84                 *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
    85                 *"make["?*"]:"*"Stop.") cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
    86                 *)                      cur_L="${LEVEL}"; cur_l="${level}";;
    87               esac
    88               l="`printf \"[%-5s]%*s%s%s\" \"${cur_L}\" \"${indent}\" \" \" \"${line}\"`"
    89               # There will always be a log file, be it /dev/null
    90               echo -e "${l}"
    91               if [ ${cur_l} -le ${max_level} ]; then
    92                   echo -e "\r${l}" >&6
    93               fi
    94               if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
    95                   [ ${CT_PROG_BAR_CPT} -eq 0  ] && bar="/"
    96                   [ ${CT_PROG_BAR_CPT} -eq 10 ] && bar="-"
    97                   [ ${CT_PROG_BAR_CPT} -eq 20 ] && bar="\\"
    98                   [ ${CT_PROG_BAR_CPT} -eq 30 ] && bar="|"
    99                   printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${bar}" >&6
   100                   CT_PROG_BAR_CPT=$(((CT_PROG_BAR_CPT+1)%40))
   101               fi
   102           done
   103         )
   104 
   105     return 0
   106 }
   107 
   108 # Tail message to be logged whatever happens
   109 # Usage: CT_DoEnd <level>
   110 CT_DoEnd()
   111 {
   112     local level="$1"
   113     CT_STOP_DATE=`CT_DoDate +%s%N`
   114     CT_STOP_DATE_HUMAN=`CT_DoDate +%Y%m%d.%H%M%S`
   115     CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
   116     elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
   117     elapsed_min=$((elapsed/(60*1000*1000*1000)))
   118     elapsed_sec=`printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000)))`
   119     elapsed_csec=`printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000)))`
   120     CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
   121 }
   122 
   123 # Abort the execution with an error message
   124 # Usage: CT_Abort <message>
   125 CT_Abort() {
   126     CT_DoLog ERROR "$1"
   127     exit 1
   128 }
   129 
   130 # Test a condition, and print a message if satisfied
   131 # Usage: CT_Test <message> <tests>
   132 CT_Test() {
   133     local ret
   134     local m="$1"
   135     shift
   136     test "$@" && CT_DoLog WARN "$m"
   137     return 0
   138 }
   139 
   140 # Test a condition, and abort with an error message if satisfied
   141 # Usage: CT_TestAndAbort <message> <tests>
   142 CT_TestAndAbort() {
   143     local m="$1"
   144     shift
   145     test "$@" && CT_Abort "$m"
   146     return 0
   147 }
   148 
   149 # Test a condition, and abort with an error message if not satisfied
   150 # Usage: CT_TestAndAbort <message> <tests>
   151 CT_TestOrAbort() {
   152     local m="$1"
   153     shift
   154     test "$@" || CT_Abort "$m"
   155     return 0
   156 }
   157 
   158 # Test the presence of a tool, or abort if not found
   159 # Usage: CT_HasOrAbort <tool>
   160 CT_HasOrAbort() {
   161     CT_TestAndAbort "\"${1}\" not found and needed for successful toolchain build." -z "`CT_Which \"${1}\"`"
   162     return 0
   163 }
   164 
   165 # Search a program: wrap "which" for those system where
   166 # "which" verbosely says there is no match (Mdk are such
   167 # suckers...)
   168 # Usage: CT_Which <filename>
   169 CT_Which() {
   170   which "$1" 2>/dev/null || true
   171 }
   172 
   173 # Get current date with nanosecond precision
   174 # On those system not supporting nanosecond precision, faked with rounding down
   175 # to the highest entire second
   176 # Usage: CT_DoDate <fmt>
   177 CT_DoDate() {
   178     date "$1" |sed -r -e 's/%N$/000000000/;'
   179 }
   180 
   181 CT_STEP_COUNT=1
   182 CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
   183 # Memorise a step being done so that any error is caught
   184 # Usage: CT_DoStep <loglevel> <message>
   185 CT_DoStep() {
   186     local start=`CT_DoDate +%s%N`
   187     CT_DoLog "$1" "================================================================="
   188     CT_DoLog "$1" "$2"
   189     CT_STEP_COUNT=$((CT_STEP_COUNT+1))
   190     CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
   191     CT_STEP_START[${CT_STEP_COUNT}]="${start}"
   192     CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
   193     return 0
   194 }
   195 
   196 # End the step just being done
   197 # Usage: CT_EndStep
   198 CT_EndStep() {
   199     local stop=`CT_DoDate +%s%N`
   200     local duration=`printf "%032d" $((stop-${CT_STEP_START[${CT_STEP_COUNT}]})) |sed -r -e 's/([[:digit:]]{2})[[:digit:]]{7}$/\.\1/; s/^0+//; s/^\./0\./;'`
   201     local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
   202     local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
   203     CT_STEP_COUNT=$((CT_STEP_COUNT-1))
   204     CT_DoLog "${level}" "${message}: done in ${duration}s"
   205     return 0
   206 }
   207 
   208 # Pushes into a directory, and pops back
   209 CT_Pushd() {
   210     pushd "$1" >/dev/null 2>&1
   211 }
   212 CT_Popd() {
   213     popd >/dev/null 2>&1
   214 }
   215 
   216 # Makes a path absolute
   217 # Usage: CT_MakeAbsolutePath path
   218 CT_MakeAbsolutePath() {
   219     # Try to cd in that directory
   220     if [ -d "$1" ]; then
   221         CT_Pushd "$1"
   222         pwd
   223         CT_Popd
   224     else
   225         # No such directory, fail back to guessing
   226         case "$1" in
   227             /*)  echo "$1";;
   228             *)   echo "`pwd`/$1";;
   229         esac
   230     fi
   231     
   232     return 0
   233 }
   234 
   235 # Creates a temporary directory
   236 # $1: variable to assign to
   237 # Usage: CT_MktempDir foo
   238 CT_MktempDir() {
   239     # Some mktemp do not allow more than 6 Xs
   240     eval "$1"="`mktemp -q -d \"${CT_BUILD_DIR}/.XXXXXX\"`"
   241     CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
   242 }
   243 
   244 # Echoes the specified string on stdout until the pipe breaks.
   245 # Doesn't fail
   246 # $1: string to echo
   247 # Usage: CT_DoYes "" |make oldconfig
   248 CT_DoYes() {
   249     yes "$1" || true
   250 }
   251 
   252 # Get the file name extension of a component
   253 # Usage: CT_GetFileExtension <component_name-component_version>
   254 # If found, echoes the extension to stdout
   255 # If not found, echoes nothing on stdout.
   256 CT_GetFileExtension() {
   257     local ext
   258     local file="$1"
   259 
   260     CT_Pushd "${CT_TARBALLS_DIR}"
   261     # we need to also check for an empty extension for those very
   262     # peculiar components that don't have one (such as sstrip from
   263     # buildroot).
   264     for ext in .tar.gz .tar.bz2 .tgz .tar ''; do
   265         if [ -f "${file}${ext}" ]; then
   266             echo "${ext}"
   267             break
   268         fi
   269     done
   270     CT_Popd
   271 
   272     return 0
   273 }
   274 
   275 # Download an URL using wget
   276 # Usage: CT_DoGetFileWget <URL>
   277 CT_DoGetFileWget() {
   278     # Need to return true because it is legitimate to not find the tarball at
   279     # some of the provided URLs (think about snapshots, different layouts for
   280     # different gcc versions, etc...)
   281     # Some (very old!) FTP server might not support the passive mode, thus
   282     # retry without
   283     # With automated download as we are doing, it can be very dangerous to use
   284     # -c to continue the downloads. It's far better to simply overwrite the
   285     # destination file
   286     # Some company networks have proxies to connect to to the internet, but
   287     # it's not easy to detect them, and wget may never timeout while connecting,
   288     # so force a global 120s timeout.
   289     wget -T 120 -nc --progress=dot:binary --tries=3 --passive-ftp "$1"  \
   290     || wget -T 120 -nc --progress=dot:binary --tries=3 "$1"             \
   291     || true
   292 }
   293 
   294 # Download an URL using curl
   295 # Usage: CT_DoGetFileCurl <URL>
   296 CT_DoGetFileCurl() {
   297     # Note: comments about wget method are also valid here
   298     # Plus: no good progress indicator is available with curl,
   299     #       so output is consigned to oblivion
   300     curl --ftp-pasv -O --retry 3 "$1" --connect-timeout 120 >/dev/null  \
   301     || curl -O --retry 3 "$1" --connect-timeout 120 >/dev/null          \
   302     || true
   303 }
   304 
   305 _wget=`CT_Which wget`
   306 _curl=`CT_Which curl`
   307 # Wrapper function to call one of curl or wget
   308 # Usage: CT_DoGetFile <URL>
   309 CT_DoGetFile() {
   310     case "${_wget},${_curl}" in
   311         ,)  CT_DoError "Could find neither wget nor curl";;
   312         ,*) CT_DoGetFileCurl "$1" 2>&1 |CT_DoLog ALL;;
   313         *)  CT_DoGetFileWget "$1" 2>&1 |CT_DoLog ALL;;
   314     esac
   315 }
   316 
   317 # Download the file from one of the URLs passed as argument
   318 # Usage: CT_GetFile <filename> [extension] <url> [url ...]
   319 CT_GetFile() {
   320     local ext
   321     local url
   322     local file="$1"
   323     local first_ext=""
   324     shift
   325     case "$1" in
   326         .tar.bz2|.tar.gz|.tgz|.tar)
   327             first_ext="$1"
   328             shift
   329             ;;
   330     esac
   331 
   332     # Do we already have it?
   333     ext=`CT_GetFileExtension "${file}"`
   334     if [ -n "${ext}" ]; then
   335         CT_DoLog DEBUG "Already have \"${file}\""
   336         return 0
   337     fi
   338 
   339     CT_Pushd "${CT_TARBALLS_DIR}"
   340     # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
   341     # or, as a failover, a file without extension.
   342     # Try local copy first, if it exists
   343     for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
   344         CT_DoLog DEBUG "Trying \"${CT_LOCAL_TARBALLS_DIR}/${file}${ext}\""
   345         if [ -r "${CT_LOCAL_TARBALLS_DIR}/${file}${ext}" -a \
   346              "${CT_FORCE_DOWNLOAD}" != "y" ]; then
   347             CT_DoLog EXTRA "Using \"${file}\" from local storage"
   348             ln -sv "${CT_LOCAL_TARBALLS_DIR}/${file}${ext}" "${file}${ext}" |CT_DoLog ALL
   349             return 0
   350         fi
   351     done
   352     # Try to download it
   353     CT_DoLog EXTRA "Retrieving \"${file}\" from network"
   354     for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
   355         # Try all urls in turn
   356         for url in "$@"; do
   357             CT_DoLog DEBUG "Trying \"${url}/${file}${ext}\""
   358             CT_DoGetFile "${url}/${file}${ext}"
   359             if [ -f "${file}${ext}" ]; then
   360                 # No need to test if the file already exists because
   361                 # it does NOT. If it did exist, we'd have been stopped
   362                 # above, when looking for local copies.
   363                 if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
   364                     CT_DoLog EXTRA "Saving \"${file}\" to local storage"
   365                     mv "${file}${ext}" "${CT_LOCAL_TARBALLS_DIR}" |CT_DoLog ALL
   366                     ln -sv "${CT_LOCAL_TARBALLS_DIR}/${file}${ext}" "${file}${ext}" |CT_DoLog ALL
   367                 fi
   368                 return 0
   369             fi
   370         done
   371     done
   372     CT_Popd
   373 
   374     CT_Abort "Could not download \"${file}\", and not present in \"${CT_LOCAL_TARBALLS_DIR}\""
   375 }
   376 
   377 # Extract a tarball and patch the resulting sources if necessary.
   378 # Some tarballs need to be extracted in specific places. Eg.: glibc addons
   379 # must be extracted in the glibc directory; uCLibc locales must be extracted
   380 # in the extra/locale sub-directory of uClibc.
   381 CT_ExtractAndPatch() {
   382     local file="$1"
   383     local base_file=`echo "${file}" |cut -d - -f 1`
   384     local ver_file=`echo "${file}" |cut -d - -f 2-`
   385     local official_patch_dir
   386     local custom_patch_dir
   387     local libc_addon
   388     local ext=`CT_GetFileExtension "${file}"`
   389     CT_TestAndAbort "\"${file}\" not found in \"${CT_TARBALLS_DIR}\"" -z "${ext}"
   390     local full_file="${CT_TARBALLS_DIR}/${file}${ext}"
   391 
   392     CT_Pushd "${CT_SRC_DIR}"
   393 
   394     # Add-ons need a little love, really.
   395     case "${file}" in
   396         glibc-[a-z]*-*)
   397             CT_TestAndAbort "Trying to extract the C-library addon/locales \"${file}\" when C-library not yet extracted" ! -d "${CT_LIBC_FILE}"
   398             cd "${CT_LIBC_FILE}"
   399             libc_addon=y
   400             [ -f ".${file}.extracted" ] && return 0
   401             touch ".${file}.extracted"
   402             ;;
   403         uClibc-locale-*)
   404             CT_TestAndAbort "Trying to extract the C-library addon/locales \"${file}\" when C-library not yet extracted" ! -d "${CT_LIBC_FILE}"
   405             cd "${CT_LIBC_FILE}/extra/locale"
   406             libc_addon=y
   407             [ -f ".${file}.extracted" ] && return 0
   408             touch ".${file}.extracted"
   409             ;;
   410     esac
   411 
   412     # If the directory exists, then consider extraction and patching done
   413     if [ -d "${file}" ]; then
   414         CT_DoLog DEBUG "Already extracted \"${file}\""
   415         return 0
   416     fi
   417 
   418     CT_DoLog EXTRA "Extracting \"${file}\""
   419     case "${ext}" in
   420         .tar.bz2)     tar xvjf "${full_file}" |CT_DoLog ALL;;
   421         .tar.gz|.tgz) tar xvzf "${full_file}" |CT_DoLog ALL;;
   422         .tar)         tar xvf  "${full_file}" |CT_DoLog ALL;;
   423         *)            CT_Abort "Don't know how to handle \"${file}\": unknown extension" ;;
   424     esac
   425 
   426     # Snapshots might not have the version number in the extracted directory
   427     # name. This is also the case for some (odd) packages, such as D.U.M.A.
   428     # Overcome this issue by symlink'ing the directory.
   429     if [ ! -d "${file}" -a "${libc_addon}" != "y" ]; then
   430         case "${ext}" in
   431             .tar.bz2)     base=`tar tjf "${full_file}" |head -n 1 |cut -d / -f 1 || true`;;
   432             .tar.gz|.tgz) base=`tar tzf "${full_file}" |head -n 1 |cut -d / -f 1 || true`;;
   433             .tar)         base=`tar tf  "${full_file}" |head -n 1 |cut -d / -f 1 || true`;;
   434         esac
   435         CT_TestOrAbort "There was a problem when extracting \"${file}\"" -d "${base}" -o "${base}" != "${file}"
   436         ln -s "${base}" "${file}"
   437     fi
   438 
   439     # Kludge: outside this function, we wouldn't know if we had just extracted
   440     # a libc addon, or a plain package. Apply patches now.
   441     CT_DoLog EXTRA "Patching \"${file}\""
   442 
   443     if [ "${libc_addon}" = "y" ]; then
   444         # Some addons tarball directly contian the correct addon directory,
   445         # while others have the addon directory named ofter the tarball.
   446         # Fix that by always using the short name (eg: linuxthreads, ports, etc...)
   447         addon_short_name=`echo "${file}" |sed -r -e 's/^[^-]+-//; s/-[^-]+$//;'`
   448         [ -d "${addon_short_name}" ] || ln -s "${file}" "${addon_short_name}"
   449         # If libc addon, we're already in the correct place
   450     else
   451         cd "${file}"
   452     fi
   453 
   454     official_patch_dir=
   455     custom_patch_dir=
   456     [ "${CUSTOM_PATCH_ONLY}" = "y" ] || official_patch_dir="${CT_LIB_DIR}/patches/${base_file}/${ver_file}"
   457     [ "${CT_CUSTOM_PATCH}" = "y" ] && custom_patch_dir="${CT_CUSTOM_PATCH_DIR}/${base_file}/${ver_file}"
   458     for patch_dir in "${official_patch_dir}" "${custom_patch_dir}"; do
   459         if [ -n "${patch_dir}" -a -d "${patch_dir}" ]; then
   460             for p in "${patch_dir}"/*.patch; do
   461                 if [ -f "${p}" ]; then
   462                     CT_DoLog DEBUG "Applying patch \"${p}\""
   463                     patch -g0 -F1 -p1 -f <"${p}" |CT_DoLog ALL
   464                     CT_TestAndAbort "Failed while applying patch file \"${p}\"" ${PIPESTATUS[0]} -ne 0
   465                 fi
   466             done
   467         fi
   468     done
   469 
   470     CT_Popd
   471 }
   472 
   473 # Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
   474 # Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
   475 CT_DoConfigGuess() {
   476     if [ -x "${CT_TOP_DIR}/tools/config.guess" ]; then
   477         "${CT_TOP_DIR}/tools/config.guess"
   478     else
   479         "${CT_LIB_DIR}/tools/config.guess"
   480     fi
   481 }
   482 
   483 CT_DoConfigSub() {
   484     if [ -x "${CT_TOP_DIR}/tools/config.sub" ]; then
   485         "${CT_TOP_DIR}/tools/config.sub" "$@"
   486     else
   487         "${CT_LIB_DIR}/tools/config.sub" "$@"
   488     fi
   489 }
   490 
   491 # Compute the target tuple from what is provided by the user
   492 # Usage: CT_DoBuildTargetTuple
   493 # In fact this function takes the environment variables to build the target
   494 # tuple. It is needed both by the normal build sequence, as well as the
   495 # sample saving sequence.
   496 CT_DoBuildTargetTuple() {
   497     # Set the endianness suffix, and the default endianness gcc option
   498     case "${CT_ARCH_BE},${CT_ARCH_LE}" in
   499         y,) target_endian_eb=eb
   500             target_endian_el=
   501             CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
   502             ;;
   503         ,y) target_endian_eb=
   504             target_endian_el=el
   505             CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
   506             ;;
   507     esac
   508 
   509     # Set defaults for the system part of the tuple. Can be overriden
   510     # by architecture-specific values.
   511     case "${CT_LIBC}" in
   512         glibc)  CT_TARGET_SYS=gnu;;
   513         uClibc) CT_TARGET_SYS=uclibc;;
   514     esac
   515 
   516     # Transform the ARCH into a kernel-understandable ARCH
   517     CT_KERNEL_ARCH="${CT_ARCH}"
   518 
   519     # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
   520     unset CT_ARCH_ARCH_CFLAG CT_ARCH_ABI_CFLAG CT_ARCH_CPU_CFLAG CT_ARCH_TUNE_CFLAG CT_ARCH_FPU_CFLAG
   521     unset CT_ARCH_WITH_ARCH CT_ARCH_WITH_ABI CT_ARCH_WITH_CPU CT_ARCH_WITH_TUNE CT_ARCH_WITH_FPU
   522     [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
   523     [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
   524     [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
   525     [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
   526     [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
   527     [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float";           CT_ARCH_WITH_FLOAT="--with-float=soft";          }
   528 
   529     # Call the architecture specific settings
   530     CT_DoArchValues
   531 
   532     # Finish the target tuple construction
   533     case "${CT_KERNEL}" in
   534         linux*)  CT_TARGET_KERNEL=linux;;
   535     esac
   536     CT_TARGET=`CT_DoConfigSub "${CT_TARGET_ARCH}-${CT_TARGET_VENDOR:-unknown}-${CT_TARGET_KERNEL}-${CT_TARGET_SYS}"`
   537 
   538     # Prepare the target CFLAGS
   539     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_ARCH_CFLAG}"
   540     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
   541     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
   542     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
   543     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
   544     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
   545 }
   546 
   547 # This function does pause the build until the user strikes "Return"
   548 # Usage: CT_DoPause [optional_message]
   549 CT_DoPause() {
   550     local foo
   551     local message="${1:-Pausing for your pleasure}"
   552     CT_DoLog INFO "${message}"
   553     read -p "Press \"Enter\" to continue, or Ctrl-C to stop..." foo >&6
   554     return 0
   555 }
   556 
   557 # This function saves the state of the toolchain to be able to restart
   558 # at any one point
   559 # Usage: CT_DoSaveState <next_step_name>
   560 CT_DoSaveState() {
   561 	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
   562     local state_name="$1"
   563     local state_dir="${CT_STATE_DIR}/${state_name}"
   564 
   565     CT_DoLog DEBUG "Saving state to restart at step \"${state_name}\"..."
   566     rm -rf "${state_dir}"
   567     mkdir -p "${state_dir}"
   568 
   569     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   570         y)  tar_opt=z; tar_ext=.gz;;
   571         *)  tar_opt=;  tar_ext=;;
   572     esac
   573 
   574     CT_DoLog DEBUG "  Saving environment and aliases"
   575     # We must omit shell functions
   576     set |awk '
   577          BEGIN { _p = 1; }
   578          $0~/^[^ ]+ \(\)/ { _p = 0; }
   579          _p == 1
   580          $0 == "}" { _p = 1; }
   581          ' >"${state_dir}/env.sh"
   582 
   583     CT_DoLog DEBUG "  Saving CT_CC_CORE_STATIC_PREFIX_DIR=\"${CT_CC_CORE_STATIC_PREFIX_DIR}\""
   584     CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   585     tar cv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" . |CT_DoLog DEBUG
   586     CT_Popd
   587 
   588     CT_DoLog DEBUG "  Saving CT_CC_CORE_SHARED_PREFIX_DIR=\"${CT_CC_CORE_SHARED_PREFIX_DIR}\""
   589     CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
   590     tar cv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" . |CT_DoLog DEBUG
   591     CT_Popd
   592 
   593     CT_DoLog DEBUG "  Saving CT_PREFIX_DIR=\"${CT_PREFIX_DIR}\""
   594     CT_Pushd "${CT_PREFIX_DIR}"
   595     tar cv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" --exclude '*.log' . |CT_DoLog DEBUG
   596     CT_Popd
   597 
   598     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
   599         CT_DoLog DEBUG "  Saving log file"
   600         exec >/dev/null
   601         case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   602             y)  gzip -3 -c "${CT_LOG_FILE}"  >"${state_dir}/log.gz";;
   603             *)  cat "${CT_LOG_FILE}" >"${state_dir}/log";;
   604         esac
   605         exec >>"${CT_LOG_FILE}"
   606     fi
   607 }
   608 
   609 # This function restores a previously saved state
   610 # Usage: CT_DoLoadState <state_name>
   611 CT_DoLoadState(){
   612     local state_name="$1"
   613     local state_dir="${CT_STATE_DIR}/${state_name}"
   614     local old_RESTART="${CT_RESTART}"
   615     local old_STOP="${CT_STOP}"
   616 
   617     CT_TestOrAbort "The previous build did not reach the point where it could be restarted at \"${CT_RESTART}\"" -d "${state_dir}"
   618 
   619     # We need to do something special with the log file!
   620     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
   621         exec >"${state_dir}/tail.log"
   622     fi
   623     CT_DoLog INFO "Restoring state at step \"${state_name}\", as requested."
   624 
   625     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   626         y)  tar_opt=z; tar_ext=.gz;;
   627         *)  tar_opt=;  tar_ext=;;
   628     esac
   629 
   630     CT_DoLog DEBUG "  Removing previous build directories"
   631     chmod -R u+rwX "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   632     rm -rf         "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   633     mkdir -p       "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   634 
   635     CT_DoLog DEBUG "  Restoring CT_PREFIX_DIR=\"${CT_PREFIX_DIR}\""
   636     CT_Pushd "${CT_PREFIX_DIR}"
   637     tar xv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
   638     CT_Popd
   639 
   640     CT_DoLog DEBUG "  Restoring CT_CC_CORE_SHARED_PREFIX_DIR=\"${CT_CC_CORE_SHARED_PREFIX_DIR}\""
   641     CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
   642     tar xv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
   643     CT_Popd
   644 
   645     CT_DoLog DEBUG "  Restoring CT_CC_CORE_STATIC_PREFIX_DIR=\"${CT_CC_CORE_STATIC_PREFIX_DIR}\""
   646     CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   647     tar xv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
   648     CT_Popd
   649 
   650     # Restore the environment, discarding any error message
   651     # (for example, read-only bash internals)
   652     CT_DoLog DEBUG "  Restoring environment"
   653     . "${state_dir}/env.sh" >/dev/null 2>&1 || true
   654 
   655     # Restore the new RESTART and STOP steps
   656     CT_RESTART="${old_RESTART}"
   657     CT_STOP="${old_STOP}"
   658     unset old_stop old_restart
   659 
   660     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
   661         CT_DoLog DEBUG "  Restoring log file"
   662         exec >/dev/null
   663         case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   664             y)  zcat "${state_dir}/log.gz" >"${CT_LOG_FILE}";;
   665             *)  cat "${state_dir}/log" >"${CT_LOG_FILE}";;
   666         esac
   667         cat "${state_dir}/tail.log" >>"${CT_LOG_FILE}"
   668         exec >>"${CT_LOG_FILE}"
   669         rm -f "${state_dir}/tail.log"
   670     fi
   671 }