scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Feb 17 22:08:06 2008 +0000 (2008-02-17)
changeset 431 8bde4c6ea47a
parent 412 e1cc03fb2794
child 439 dd62fca2d6fd
permissions -rw-r--r--
Robert P. J. DAY says:

apparently, the patchset for gcc 4.2.1 applies properly to the
source for gcc 4.2.2 and gcc 4.2.3. so, if you want, you can simply
add support for those last two just by augmenting menuconfig and
adding a couple symlinks for those two directories. seems like a
cheap way to add a couple new versions.
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@63
   286
    wget -nc --progress=dot:binary --tries=3 --passive-ftp "$1" || wget -nc --progress=dot:binary --tries=3 "$1" || true
yann@63
   287
}
yann@63
   288
yann@63
   289
# Download an URL using curl
yann@63
   290
# Usage: CT_DoGetFileCurl <URL>
yann@63
   291
CT_DoGetFileCurl() {
yann@63
   292
	# Note: comments about wget method are also valid here
yann@63
   293
	# Plus: no good progreess indicator is available with curl,
yann@63
   294
	#       so output is consigned to oblivion
yann@63
   295
	curl --ftp-pasv -O --retry 3 "$1" >/dev/null || curl -O --retry 3 "$1" >/dev/null || true
yann@63
   296
}
yann@63
   297
yann@241
   298
_wget=`CT_Which wget`
yann@241
   299
_curl=`CT_Which curl`
yann@63
   300
# Wrapper function to call one of curl or wget
yann@63
   301
# Usage: CT_DoGetFile <URL>
yann@63
   302
CT_DoGetFile() {
yann@63
   303
    case "${_wget},${_curl}" in
yann@63
   304
        ,)  CT_DoError "Could find neither wget nor curl";;
yann@146
   305
        ,*) CT_DoGetFileCurl "$1" 2>&1 |CT_DoLog ALL;;
yann@146
   306
        *)  CT_DoGetFileWget "$1" 2>&1 |CT_DoLog ALL;;
yann@63
   307
    esac
yann@63
   308
}
yann@63
   309
yann@63
   310
# Download the file from one of the URLs passed as argument
yann@242
   311
# Usage: CT_GetFile <filename> [extension] <url> [url ...]
yann@63
   312
CT_GetFile() {
yann@63
   313
    local ext
yann@63
   314
    local url
yann@63
   315
    local file="$1"
yann@242
   316
    local first_ext=""
yann@63
   317
    shift
yann@242
   318
    case "$1" in
yann@242
   319
        .tar.bz2|.tar.gz|.tgz|.tar)
yann@242
   320
            first_ext="$1"
yann@242
   321
            shift
yann@242
   322
            ;;
yann@242
   323
    esac
yann@63
   324
yann@63
   325
    # Do we already have it?
yann@63
   326
    ext=`CT_GetFileExtension "${file}"`
yann@63
   327
    if [ -n "${ext}" ]; then
yann@85
   328
        CT_DoLog DEBUG "Already have \"${file}\""
yann@85
   329
        return 0
yann@63
   330
    fi
yann@63
   331
yann@63
   332
    CT_Pushd "${CT_TARBALLS_DIR}"
yann@242
   333
    # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
yann@242
   334
    # or, as a failover, a file without extension.
yann@102
   335
    # Try local copy first, if it exists
yann@242
   336
    for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@265
   337
        CT_DoLog DEBUG "Trying \"${CT_LOCAL_TARBALLS_DIR}/${file}${ext}\""
yann@102
   338
        if [ -r "${CT_LOCAL_TARBALLS_DIR}/${file}${ext}" -a \
yann@102
   339
             "${CT_FORCE_DOWNLOAD}" != "y" ]; then
yann@371
   340
            CT_DoLog EXTRA "Using \"${file}\" from local storage"
yann@371
   341
            ln -sv "${CT_LOCAL_TARBALLS_DIR}/${file}${ext}" "${file}${ext}" |CT_DoLog ALL
yann@102
   342
            return 0
yann@63
   343
        fi
yann@63
   344
    done
yann@102
   345
    # Try to download it
yann@265
   346
    CT_DoLog EXTRA "Retrieving \"${file}\" from network"
yann@242
   347
    for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@102
   348
        # Try all urls in turn
yann@102
   349
        for url in "$@"; do
yann@265
   350
            CT_DoLog DEBUG "Trying \"${url}/${file}${ext}\""
yann@265
   351
            CT_DoGetFile "${url}/${file}${ext}"
yann@265
   352
            if [ -f "${file}${ext}" ]; then
yann@265
   353
                # No need to test if the file already exists because
yann@265
   354
                # it does NOT. If it did exist, we'd have been stopped
yann@265
   355
                # above, when looking for local copies.
yann@265
   356
                if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
yann@265
   357
                    CT_DoLog EXTRA "Saving \"${file}\" to local storage"
yann@371
   358
                    mv "${file}${ext}" "${CT_LOCAL_TARBALLS_DIR}" |CT_DoLog ALL
yann@371
   359
                    ln -sv "${CT_LOCAL_TARBALLS_DIR}/${file}${ext}" "${file}${ext}" |CT_DoLog ALL
yann@265
   360
                fi
yann@265
   361
                return 0
yann@265
   362
            fi
yann@102
   363
        done
yann@102
   364
    done
yann@63
   365
    CT_Popd
yann@63
   366
yann@102
   367
    CT_Abort "Could not download \"${file}\", and not present in \"${CT_LOCAL_TARBALLS_DIR}\""
yann@63
   368
}
yann@63
   369
yann@63
   370
# Extract a tarball and patch the resulting sources if necessary.
yann@63
   371
# Some tarballs need to be extracted in specific places. Eg.: glibc addons
yann@63
   372
# must be extracted in the glibc directory; uCLibc locales must be extracted
yann@63
   373
# in the extra/locale sub-directory of uClibc.
yann@63
   374
CT_ExtractAndPatch() {
yann@63
   375
    local file="$1"
yann@63
   376
    local base_file=`echo "${file}" |cut -d - -f 1`
yann@63
   377
    local ver_file=`echo "${file}" |cut -d - -f 2-`
yann@63
   378
    local official_patch_dir
yann@63
   379
    local custom_patch_dir
yann@63
   380
    local libc_addon
yann@63
   381
    local ext=`CT_GetFileExtension "${file}"`
yann@63
   382
    CT_TestAndAbort "\"${file}\" not found in \"${CT_TARBALLS_DIR}\"" -z "${ext}"
yann@63
   383
    local full_file="${CT_TARBALLS_DIR}/${file}${ext}"
yann@63
   384
yann@63
   385
    CT_Pushd "${CT_SRC_DIR}"
yann@63
   386
yann@63
   387
    # Add-ons need a little love, really.
yann@63
   388
    case "${file}" in
yann@63
   389
        glibc-[a-z]*-*)
yann@63
   390
            CT_TestAndAbort "Trying to extract the C-library addon/locales \"${file}\" when C-library not yet extracted" ! -d "${CT_LIBC_FILE}"
yann@63
   391
            cd "${CT_LIBC_FILE}"
yann@63
   392
            libc_addon=y
yann@63
   393
            [ -f ".${file}.extracted" ] && return 0
yann@63
   394
            touch ".${file}.extracted"
yann@63
   395
            ;;
yann@63
   396
        uClibc-locale-*)
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}/extra/locale"
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
    esac
yann@63
   404
yann@63
   405
    # If the directory exists, then consider extraction and patching done
yann@77
   406
    if [ -d "${file}" ]; then
yann@78
   407
        CT_DoLog DEBUG "Already extracted \"${file}\""
yann@77
   408
        return 0
yann@77
   409
    fi
yann@63
   410
yann@63
   411
    CT_DoLog EXTRA "Extracting \"${file}\""
yann@63
   412
    case "${ext}" in
yann@78
   413
        .tar.bz2)     tar xvjf "${full_file}" |CT_DoLog ALL;;
yann@78
   414
        .tar.gz|.tgz) tar xvzf "${full_file}" |CT_DoLog ALL;;
yann@78
   415
        .tar)         tar xvf  "${full_file}" |CT_DoLog ALL;;
yann@63
   416
        *)            CT_Abort "Don't know how to handle \"${file}\": unknown extension" ;;
yann@63
   417
    esac
yann@63
   418
yann@63
   419
    # Snapshots might not have the version number in the extracted directory
yann@305
   420
    # name. This is also the case for some (odd) packages, such as D.U.M.A.
yann@63
   421
    # Overcome this issue by symlink'ing the directory.
yann@63
   422
    if [ ! -d "${file}" -a "${libc_addon}" != "y" ]; then
yann@63
   423
        case "${ext}" in
yann@63
   424
            .tar.bz2)     base=`tar tjf "${full_file}" |head -n 1 |cut -d / -f 1 || true`;;
yann@63
   425
            .tar.gz|.tgz) base=`tar tzf "${full_file}" |head -n 1 |cut -d / -f 1 || true`;;
yann@63
   426
            .tar)         base=`tar tf  "${full_file}" |head -n 1 |cut -d / -f 1 || true`;;
yann@63
   427
        esac
yann@63
   428
        CT_TestOrAbort "There was a problem when extracting \"${file}\"" -d "${base}" -o "${base}" != "${file}"
yann@63
   429
        ln -s "${base}" "${file}"
yann@63
   430
    fi
yann@63
   431
yann@63
   432
    # Kludge: outside this function, we wouldn't know if we had just extracted
yann@63
   433
    # a libc addon, or a plain package. Apply patches now.
yann@63
   434
    CT_DoLog EXTRA "Patching \"${file}\""
yann@63
   435
yann@136
   436
    if [ "${libc_addon}" = "y" ]; then
yann@136
   437
        # Some addons tarball directly contian the correct addon directory,
yann@136
   438
        # while others have the addon directory named ofter the tarball.
yann@365
   439
        # Fix that by always using the short name (eg: linuxthreads, ports, etc...)
yann@136
   440
        addon_short_name=`echo "${file}" |sed -r -e 's/^[^-]+-//; s/-[^-]+$//;'`
yann@136
   441
        [ -d "${addon_short_name}" ] || ln -s "${file}" "${addon_short_name}"
yann@136
   442
        # If libc addon, we're already in the correct place
yann@136
   443
    else
yann@136
   444
        cd "${file}"
yann@136
   445
    fi
yann@63
   446
yann@182
   447
    official_patch_dir=
yann@182
   448
    custom_patch_dir=
yann@182
   449
    [ "${CUSTOM_PATCH_ONLY}" = "y" ] || official_patch_dir="${CT_LIB_DIR}/patches/${base_file}/${ver_file}"
yann@63
   450
    [ "${CT_CUSTOM_PATCH}" = "y" ] && custom_patch_dir="${CT_CUSTOM_PATCH_DIR}/${base_file}/${ver_file}"
yann@63
   451
    for patch_dir in "${official_patch_dir}" "${custom_patch_dir}"; do
yann@63
   452
        if [ -n "${patch_dir}" -a -d "${patch_dir}" ]; then
yann@63
   453
            for p in "${patch_dir}"/*.patch; do
yann@63
   454
                if [ -f "${p}" ]; then
yann@63
   455
                    CT_DoLog DEBUG "Applying patch \"${p}\""
yann@78
   456
                    patch -g0 -F1 -p1 -f <"${p}" |CT_DoLog ALL
yann@63
   457
                    CT_TestAndAbort "Failed while applying patch file \"${p}\"" ${PIPESTATUS[0]} -ne 0
yann@63
   458
                fi
yann@63
   459
            done
yann@63
   460
        fi
yann@63
   461
    done
yann@63
   462
yann@63
   463
    CT_Popd
yann@63
   464
}
yann@63
   465
yann@182
   466
# Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
yann@182
   467
# Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
yann@182
   468
CT_DoConfigGuess() {
yann@182
   469
    if [ -x "${CT_TOP_DIR}/tools/config.guess" ]; then
yann@182
   470
        "${CT_TOP_DIR}/tools/config.guess"
yann@182
   471
    else
yann@182
   472
        "${CT_LIB_DIR}/tools/config.guess"
yann@182
   473
    fi
yann@182
   474
}
yann@182
   475
yann@182
   476
CT_DoConfigSub() {
yann@182
   477
    if [ -x "${CT_TOP_DIR}/tools/config.sub" ]; then
yann@182
   478
        "${CT_TOP_DIR}/tools/config.sub" "$@"
yann@182
   479
    else
yann@182
   480
        "${CT_LIB_DIR}/tools/config.sub" "$@"
yann@182
   481
    fi
yann@182
   482
}
yann@182
   483
yann@335
   484
# Compute the target tuple from what is provided by the user
yann@335
   485
# Usage: CT_DoBuildTargetTuple
yann@63
   486
# In fact this function takes the environment variables to build the target
yann@335
   487
# tuple. It is needed both by the normal build sequence, as well as the
yann@63
   488
# sample saving sequence.
yann@335
   489
CT_DoBuildTargetTuple() {
yann@383
   490
    # Set the endianness suffix, and the default endianness gcc option
yann@63
   491
    case "${CT_ARCH_BE},${CT_ARCH_LE}" in
yann@383
   492
        y,) target_endian_eb=eb
yann@383
   493
            target_endian_el=
yann@391
   494
            CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
yann@383
   495
            ;;
yann@383
   496
        ,y) target_endian_eb=
yann@383
   497
            target_endian_el=el
yann@391
   498
            CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
yann@383
   499
            ;;
yann@63
   500
    esac
yann@383
   501
yann@383
   502
    # Set defaults for the system part of the tuple. Can be overriden
yann@383
   503
    # by architecture-specific values.
yann@383
   504
    case "${CT_LIBC}" in
yann@383
   505
        glibc)  CT_TARGET_SYS=gnu;;
yann@383
   506
        uClibc) CT_TARGET_SYS=uclibc;;
yann@63
   507
    esac
yann@383
   508
yann@387
   509
    # Transform the ARCH into a kernel-understandable ARCH
yann@387
   510
    CT_KERNEL_ARCH="${CT_ARCH}"
yann@387
   511
yann@391
   512
    # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
yann@391
   513
    unset CT_ARCH_ARCH_CFLAG CT_ARCH_ABI_CFLAG CT_ARCH_CPU_CFLAG CT_ARCH_TUNE_CFLAG CT_ARCH_FPU_CFLAG
yann@391
   514
    unset CT_ARCH_WITH_ARCH CT_ARCH_WITH_ABI CT_ARCH_WITH_CPU CT_ARCH_WITH_TUNE CT_ARCH_WITH_FPU
yann@391
   515
    [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
yann@391
   516
    [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
yann@391
   517
    [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
yann@405
   518
    [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
yann@391
   519
    [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
yann@412
   520
    [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float";           CT_ARCH_WITH_FLOAT="--with-float=soft";          }
yann@391
   521
yann@383
   522
    # Call the architecture specific settings
yann@383
   523
    CT_DoArchValues
yann@383
   524
yann@391
   525
    # Finish the target tuple construction
yann@383
   526
    case "${CT_KERNEL}" in
yann@383
   527
        linux*)  CT_TARGET_KERNEL=linux;;
yann@63
   528
    esac
yann@383
   529
    CT_TARGET=`CT_DoConfigSub "${CT_TARGET_ARCH}-${CT_TARGET_VENDOR:-unknown}-${CT_TARGET_KERNEL}-${CT_TARGET_SYS}"`
yann@391
   530
yann@391
   531
    # Prepare the target CFLAGS
yann@397
   532
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_ARCH_CFLAG}"
yann@397
   533
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
yann@397
   534
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
yann@397
   535
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
yann@397
   536
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
yann@397
   537
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
yann@63
   538
}
yann@121
   539
yann@121
   540
# This function does pause the build until the user strikes "Return"
yann@121
   541
# Usage: CT_DoPause [optional_message]
yann@121
   542
CT_DoPause() {
yann@121
   543
    local foo
yann@121
   544
    local message="${1:-Pausing for your pleasure}"
yann@121
   545
    CT_DoLog INFO "${message}"
yann@121
   546
    read -p "Press \"Enter\" to continue, or Ctrl-C to stop..." foo >&6
yann@121
   547
    return 0
yann@121
   548
}
yann@121
   549
yann@121
   550
# This function saves the state of the toolchain to be able to restart
yann@121
   551
# at any one point
yann@121
   552
# Usage: CT_DoSaveState <next_step_name>
yann@121
   553
CT_DoSaveState() {
yann@121
   554
	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
yann@121
   555
    local state_name="$1"
yann@121
   556
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@121
   557
yann@121
   558
    CT_DoLog DEBUG "Saving state to restart at step \"${state_name}\"..."
yann@121
   559
    rm -rf "${state_dir}"
yann@121
   560
    mkdir -p "${state_dir}"
yann@121
   561
yann@121
   562
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@327
   563
        y)  tar_opt=z; tar_ext=.gz;;
yann@327
   564
        *)  tar_opt=;  tar_ext=;;
yann@121
   565
    esac
yann@121
   566
yann@121
   567
    CT_DoLog DEBUG "  Saving environment and aliases"
yann@121
   568
    # We must omit shell functions
yann@121
   569
    set |awk '
yann@121
   570
         BEGIN { _p = 1; }
yann@326
   571
         $0~/^[^ ]+ \(\)/ { _p = 0; }
yann@121
   572
         _p == 1
yann@121
   573
         $0 == "}" { _p = 1; }
yann@326
   574
         ' >"${state_dir}/env.sh"
yann@121
   575
yann@136
   576
    CT_DoLog DEBUG "  Saving CT_CC_CORE_STATIC_PREFIX_DIR=\"${CT_CC_CORE_STATIC_PREFIX_DIR}\""
yann@136
   577
    CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@327
   578
    tar cv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" . |CT_DoLog DEBUG
yann@136
   579
    CT_Popd
yann@136
   580
yann@136
   581
    CT_DoLog DEBUG "  Saving CT_CC_CORE_SHARED_PREFIX_DIR=\"${CT_CC_CORE_SHARED_PREFIX_DIR}\""
yann@136
   582
    CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
yann@327
   583
    tar cv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" . |CT_DoLog DEBUG
yann@121
   584
    CT_Popd
yann@121
   585
yann@121
   586
    CT_DoLog DEBUG "  Saving CT_PREFIX_DIR=\"${CT_PREFIX_DIR}\""
yann@121
   587
    CT_Pushd "${CT_PREFIX_DIR}"
yann@327
   588
    tar cv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" --exclude '*.log' . |CT_DoLog DEBUG
yann@121
   589
    CT_Popd
yann@121
   590
yann@121
   591
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
   592
        CT_DoLog DEBUG "  Saving log file"
yann@121
   593
        exec >/dev/null
yann@121
   594
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
   595
            y)  gzip -3 -c "${CT_LOG_FILE}"  >"${state_dir}/log.gz";;
yann@121
   596
            *)  cat "${CT_LOG_FILE}" >"${state_dir}/log";;
yann@121
   597
        esac
yann@121
   598
        exec >>"${CT_LOG_FILE}"
yann@121
   599
    fi
yann@121
   600
}
yann@121
   601
yann@136
   602
# This function restores a previously saved state
yann@121
   603
# Usage: CT_DoLoadState <state_name>
yann@121
   604
CT_DoLoadState(){
yann@121
   605
    local state_name="$1"
yann@121
   606
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@135
   607
    local old_RESTART="${CT_RESTART}"
yann@135
   608
    local old_STOP="${CT_STOP}"
yann@121
   609
yann@141
   610
    CT_TestOrAbort "The previous build did not reach the point where it could be restarted at \"${CT_RESTART}\"" -d "${state_dir}"
yann@141
   611
yann@121
   612
    # We need to do something special with the log file!
yann@121
   613
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
   614
        exec >"${state_dir}/tail.log"
yann@121
   615
    fi
yann@135
   616
    CT_DoLog INFO "Restoring state at step \"${state_name}\", as requested."
yann@121
   617
yann@121
   618
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@327
   619
        y)  tar_opt=z; tar_ext=.gz;;
yann@327
   620
        *)  tar_opt=;  tar_ext=;;
yann@121
   621
    esac
yann@121
   622
yann@121
   623
    CT_DoLog DEBUG "  Removing previous build directories"
yann@136
   624
    chmod -R u+rwX "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@136
   625
    rm -rf         "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@136
   626
    mkdir -p       "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@121
   627
yann@121
   628
    CT_DoLog DEBUG "  Restoring CT_PREFIX_DIR=\"${CT_PREFIX_DIR}\""
yann@121
   629
    CT_Pushd "${CT_PREFIX_DIR}"
yann@343
   630
    tar xv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
yann@121
   631
    CT_Popd
yann@121
   632
yann@136
   633
    CT_DoLog DEBUG "  Restoring CT_CC_CORE_SHARED_PREFIX_DIR=\"${CT_CC_CORE_SHARED_PREFIX_DIR}\""
yann@136
   634
    CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
yann@327
   635
    tar xv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
yann@136
   636
    CT_Popd
yann@136
   637
yann@136
   638
    CT_DoLog DEBUG "  Restoring CT_CC_CORE_STATIC_PREFIX_DIR=\"${CT_CC_CORE_STATIC_PREFIX_DIR}\""
yann@136
   639
    CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@327
   640
    tar xv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" |CT_DoLog DEBUG
yann@121
   641
    CT_Popd
yann@121
   642
yann@121
   643
    # Restore the environment, discarding any error message
yann@121
   644
    # (for example, read-only bash internals)
yann@121
   645
    CT_DoLog DEBUG "  Restoring environment"
yann@121
   646
    . "${state_dir}/env.sh" >/dev/null 2>&1 || true
yann@121
   647
yann@135
   648
    # Restore the new RESTART and STOP steps
yann@135
   649
    CT_RESTART="${old_RESTART}"
yann@135
   650
    CT_STOP="${old_STOP}"
yann@135
   651
    unset old_stop old_restart
yann@135
   652
yann@121
   653
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
   654
        CT_DoLog DEBUG "  Restoring log file"
yann@121
   655
        exec >/dev/null
yann@121
   656
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
   657
            y)  zcat "${state_dir}/log.gz" >"${CT_LOG_FILE}";;
yann@121
   658
            *)  cat "${state_dir}/log" >"${CT_LOG_FILE}";;
yann@121
   659
        esac
yann@121
   660
        cat "${state_dir}/tail.log" >>"${CT_LOG_FILE}"
yann@121
   661
        exec >>"${CT_LOG_FILE}"
yann@121
   662
        rm -f "${state_dir}/tail.log"
yann@121
   663
    fi
yann@121
   664
}