scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Jul 13 10:32:38 2008 +0000 (2008-07-13)
changeset 645 8e58024f8e37
parent 582 522e4fe1ca75
child 646 e0cc6a00953e
permissions -rw-r--r--
Ioannis E. VENETIS <venetis@mail.capsl.udel.edu> pointed out that GMP and MPFR were not used by gcc.
Turned out that none could use GMP and MPFR as the config option changed its name, but the change was not propagated to all users.

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