scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Wed May 21 22:00:52 2008 +0000 (2008-05-21)
changeset 527 4ac12179ef23
parent 523 010f6f4e4dd6
child 535 1035cecf3850
permissions -rw-r--r--
Introduce target-specific LDFLAGS, the same way we have CFLAGS for the target.
It seems to be helping gcc somewhat into telling the correct endianness to ld that sticks with little endian even when the target is big (eg armeb-unknown-linux-uclibcgnueabi).
There's still work to do, especially finish the gcc part that is not in this commit.

/trunk/scripts/functions | 9 7 2 0 +++++++--
1 file changed, 7 insertions(+), 2 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           _prog_bar_cpt=0
    79           _prog_bar[0]='/'
    80           _prog_bar[1]='-'
    81           _prog_bar[2]='\'
    82           _prog_bar[3]='|'
    83           indent=$((2*CT_STEP_COUNT))
    84           while read line; do
    85               case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
    86                 y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
    87                 y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
    88                 *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
    89                 *"make["?*"]:"*"Stop.") cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
    90                 *)                      cur_L="${LEVEL}"; cur_l="${level}";;
    91               esac
    92               # There will always be a log file (stdout, fd #1), be it /dev/null
    93               printf "[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}"
    94               if [ ${cur_l} -le ${max_level} ]; then
    95                   # Only print to console (fd #6) if log level is high enough.
    96                   printf "\r[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}" >&6
    97               fi
    98               if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
    99                   printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${_prog_bar[$((_prog_bar_cpt/10))]}" >&6
   100                   _prog_bar_cpt=$(((_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 firewalls to connect to the internet, but it's
   287     # not easy to detect them, and wget does not timeout by default  while
   288     # connecting, so force a global ${CT_CONNECT_TIMEOUT}-second timeout.
   289     wget -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary --tries=3 --passive-ftp "$1"    \
   290     || wget -T ${CT_CONNECT_TIMEOUT} -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 (above) 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 ${CT_CONNECT_TIMEOUT} >/dev/null    \
   301     || curl -O --retry 3 "$1" --connect-timeout ${CT_CONNECT_TIMEOUT} >/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 addon tarballs directly contain the correct addon directory,
   445         # while others have the addon directory named after 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     if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
   471         CT_DoLog ALL "Overiding config.guess and config.sub"
   472         for cfg in config_guess config_sub; do
   473             eval ${cfg}="${CT_LIB_DIR}/tools/${cfg/_/.}"
   474             [ -e "${CT_TOP_DIR}/tools/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/tools/${cfg/_/.}"
   475             find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
   476         done
   477     fi
   478 
   479     CT_Popd
   480 }
   481 
   482 # Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
   483 # Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
   484 CT_DoConfigGuess() {
   485     if [ -x "${CT_TOP_DIR}/tools/config.guess" ]; then
   486         "${CT_TOP_DIR}/tools/config.guess"
   487     else
   488         "${CT_LIB_DIR}/tools/config.guess"
   489     fi
   490 }
   491 
   492 CT_DoConfigSub() {
   493     if [ -x "${CT_TOP_DIR}/tools/config.sub" ]; then
   494         "${CT_TOP_DIR}/tools/config.sub" "$@"
   495     else
   496         "${CT_LIB_DIR}/tools/config.sub" "$@"
   497     fi
   498 }
   499 
   500 # Compute the target tuple from what is provided by the user
   501 # Usage: CT_DoBuildTargetTuple
   502 # In fact this function takes the environment variables to build the target
   503 # tuple. It is needed both by the normal build sequence, as well as the
   504 # sample saving sequence.
   505 CT_DoBuildTargetTuple() {
   506     # Set the endianness suffix, and the default endianness gcc option
   507     case "${CT_ARCH_BE},${CT_ARCH_LE}" in
   508         y,) target_endian_eb=eb
   509             target_endian_el=
   510             CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
   511             CT_ARCH_ENDIAN_LDFLAG="-EB"
   512             ;;
   513         ,y) target_endian_eb=
   514             target_endian_el=el
   515             CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
   516             CT_ARCH_ENDIAN_LDFLAG="-EL"
   517             ;;
   518     esac
   519 
   520     # Set defaults for the system part of the tuple. Can be overriden
   521     # by architecture-specific values.
   522     case "${CT_LIBC}" in
   523         glibc)  CT_TARGET_SYS=gnu;;
   524         uClibc) CT_TARGET_SYS=uclibc;;
   525     esac
   526 
   527     # Transform the ARCH into a kernel-understandable ARCH
   528     CT_KERNEL_ARCH="${CT_ARCH}"
   529 
   530     # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
   531     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
   532     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
   533     [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
   534     [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
   535     [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
   536     [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
   537     [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
   538     [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float";           CT_ARCH_WITH_FLOAT="--with-float=soft";          }
   539 
   540     # Call the architecture specific settings
   541     CT_DoArchValues
   542 
   543     # Finish the target tuple construction
   544     case "${CT_KERNEL}" in
   545         linux*)  CT_TARGET_KERNEL=linux;;
   546     esac
   547     CT_TARGET=$(CT_DoConfigSub "${CT_TARGET_ARCH}-${CT_TARGET_VENDOR:-unknown}-${CT_TARGET_KERNEL}-${CT_TARGET_SYS}")
   548 
   549     # Prepare the target CFLAGS
   550     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_ENDIAN_CFLAG}"
   551     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
   552     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
   553     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
   554     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
   555     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
   556     CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
   557 
   558     # Now on for the target LDFLAGS
   559     CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_ENDIAN_LDFLAG}"
   560 }
   561 
   562 # This function does pause the build until the user strikes "Return"
   563 # Usage: CT_DoPause [optional_message]
   564 CT_DoPause() {
   565     local foo
   566     local message="${1:-Pausing for your pleasure}"
   567     CT_DoLog INFO "${message}"
   568     read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
   569     return 0
   570 }
   571 
   572 # This function saves the state of the toolchain to be able to restart
   573 # at any one point
   574 # Usage: CT_DoSaveState <next_step_name>
   575 CT_DoSaveState() {
   576 	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
   577     local state_name="$1"
   578     local state_dir="${CT_STATE_DIR}/${state_name}"
   579 
   580     CT_DoLog DEBUG "Saving state to restart at step '${state_name}'..."
   581     rm -rf "${state_dir}"
   582     mkdir -p "${state_dir}"
   583 
   584     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   585         y)  tar_opt=z; tar_ext=.gz;;
   586         *)  tar_opt=;  tar_ext=;;
   587     esac
   588 
   589     CT_DoLog DEBUG "  Saving environment and aliases"
   590     # We must omit shell functions
   591     set |awk '
   592          BEGIN { _p = 1; }
   593          $0~/^[^ ]+ \(\)/ { _p = 0; }
   594          _p == 1
   595          $0 == "}" { _p = 1; }
   596          ' >"${state_dir}/env.sh"
   597 
   598     CT_DoLog DEBUG "  Saving CT_CC_CORE_STATIC_PREFIX_DIR='${CT_CC_CORE_STATIC_PREFIX_DIR}'"
   599     CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   600     tar cv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" . |CT_DoLog DEBUG
   601     CT_Popd
   602 
   603     CT_DoLog DEBUG "  Saving CT_CC_CORE_SHARED_PREFIX_DIR='${CT_CC_CORE_SHARED_PREFIX_DIR}'"
   604     CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
   605     tar cv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" . |CT_DoLog DEBUG
   606     CT_Popd
   607 
   608     CT_DoLog DEBUG "  Saving CT_PREFIX_DIR='${CT_PREFIX_DIR}'"
   609     CT_Pushd "${CT_PREFIX_DIR}"
   610     tar cv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" --exclude '*.log' . |CT_DoLog DEBUG
   611     CT_Popd
   612 
   613     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
   614         CT_DoLog DEBUG "  Saving log file"
   615         exec >/dev/null
   616         case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   617             y)  gzip -3 -c "${CT_LOG_FILE}"  >"${state_dir}/log.gz";;
   618             *)  cat "${CT_LOG_FILE}" >"${state_dir}/log";;
   619         esac
   620         exec >>"${CT_LOG_FILE}"
   621     fi
   622 }
   623 
   624 # This function restores a previously saved state
   625 # Usage: CT_DoLoadState <state_name>
   626 CT_DoLoadState(){
   627     local state_name="$1"
   628     local state_dir="${CT_STATE_DIR}/${state_name}"
   629     local old_RESTART="${CT_RESTART}"
   630     local old_STOP="${CT_STOP}"
   631 
   632     CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
   633 
   634     # We need to do something special with the log file!
   635     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
   636         exec >"${state_dir}/tail.log"
   637     fi
   638     CT_DoLog INFO "Restoring state at step '${state_name}', as requested."
   639 
   640     case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   641         y)  tar_opt=z; tar_ext=.gz;;
   642         *)  tar_opt=;  tar_ext=;;
   643     esac
   644 
   645     CT_DoLog DEBUG "  Removing previous build directories"
   646     chmod -R u+rwX "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   647     rm -rf         "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   648     mkdir -p       "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   649 
   650     CT_DoLog DEBUG "  Restoring CT_PREFIX_DIR='${CT_PREFIX_DIR}'"
   651     CT_Pushd "${CT_PREFIX_DIR}"
   652     tar xv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
   653     CT_Popd
   654 
   655     CT_DoLog DEBUG "  Restoring CT_CC_CORE_SHARED_PREFIX_DIR='${CT_CC_CORE_SHARED_PREFIX_DIR}'"
   656     CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
   657     tar xv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
   658     CT_Popd
   659 
   660     CT_DoLog DEBUG "  Restoring CT_CC_CORE_STATIC_PREFIX_DIR='${CT_CC_CORE_STATIC_PREFIX_DIR}'"
   661     CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
   662     tar xv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
   663     CT_Popd
   664 
   665     # Restore the environment, discarding any error message
   666     # (for example, read-only bash internals)
   667     CT_DoLog DEBUG "  Restoring environment"
   668     . "${state_dir}/env.sh" >/dev/null 2>&1 || true
   669 
   670     # Restore the new RESTART and STOP steps
   671     CT_RESTART="${old_RESTART}"
   672     CT_STOP="${old_STOP}"
   673     unset old_stop old_restart
   674 
   675     if [ "${CT_LOG_TO_FILE}" = "y" ]; then
   676         CT_DoLog DEBUG "  Restoring log file"
   677         exec >/dev/null
   678         case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
   679             y)  zcat "${state_dir}/log.gz" >"${CT_LOG_FILE}";;
   680             *)  cat "${state_dir}/log" >"${CT_LOG_FILE}";;
   681         esac
   682         cat "${state_dir}/tail.log" >>"${CT_LOG_FILE}"
   683         exec >>"${CT_LOG_FILE}"
   684         rm -f "${state_dir}/tail.log"
   685     fi
   686 }