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