scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Thu Dec 23 20:43:32 2010 +0100 (2010-12-23)
changeset 2307 2efd46963086
parent 2280 3d480d12124e
child 2308 911b3a703497
permissions -rw-r--r--
buildtools: move to working directory

There is absolutely *no* reason for the buildtools (wrappers to gcc, g++,
as, ld... for the local machine) to be in the toolchain directory. Moreover,
they are removed after the build completes.

Move them out of the toolchain directory, and into the build directory (but
yet the part specific to the current toolchain). This means we no longer
need to explicitly remove them either, BTW, but we need to save/restore them
for the restart feature.

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
anthony@2155
     1
# This file contains some usefull common functions -*- sh -*-
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@726
     8
    # Bail out early in subshell, the upper level shell will act accordingly.
yann@726
     9
    [ ${BASH_SUBSHELL} -eq 0 ] || exit $ret
yann@523
    10
    CT_DoLog ERROR "Build failed in step '${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}'"
yann@1
    11
    for((step=(CT_STEP_COUNT-1); step>1; step--)); do
yann@523
    12
        CT_DoLog ERROR "      called in step '${CT_STEP_MESSAGE[${step}]}'"
yann@1
    13
    done
yann@523
    14
    CT_DoLog ERROR "Error happened in '${BASH_SOURCE[1]}' in function '${FUNCNAME[1]}' (line unknown, sorry)"
yann@1
    15
    for((depth=2; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
yann@523
    16
        CT_DoLog ERROR "      called from '${BASH_SOURCE[${depth}]}' at line # ${BASH_LINENO[${depth}-1]} in function '${FUNCNAME[${depth}]}'"
yann@1
    17
    done
yann@523
    18
    [ "${CT_LOG_TO_FILE}" = "y" ] && CT_DoLog ERROR "Look at '${CT_LOG_FILE}' for more info on this error."
yann@96
    19
    CT_STEP_COUNT=1
yann@96
    20
    CT_DoEnd ERROR
yann@1
    21
    exit $ret
yann@1
    22
}
yann@136
    23
yann@136
    24
# Install the fault handler
yann@1
    25
trap CT_OnError ERR
yann@1
    26
yann@136
    27
# Inherit the fault handler in subshells and functions
yann@1
    28
set -E
yann@136
    29
yann@136
    30
# Make pipes fail on the _first_ failed command
yann@136
    31
# Not supported on bash < 3.x, but we need it, so drop the obsoleting bash-2.x
yann@1
    32
set -o pipefail
yann@1
    33
yann@136
    34
# Don't hash commands' locations, and search every time it is requested.
yann@136
    35
# This is slow, but needed because of the static/shared core gcc which shall
yann@136
    36
# always match to shared if it exists, and only fallback to static if the
yann@136
    37
# shared is not found
yann@136
    38
set +o hashall
yann@136
    39
yann@165
    40
# Log policy:
yann@165
    41
#  - first of all, save stdout so we can see the live logs: fd #6
yann@165
    42
exec 6>&1
yann@165
    43
#  - then point stdout to the log file (temporary for now)
yann@165
    44
tmp_log_file="${CT_TOP_DIR}/log.$$"
yann@165
    45
exec >>"${tmp_log_file}"
yann@165
    46
yann@1
    47
# The different log levels:
yann@1
    48
CT_LOG_LEVEL_ERROR=0
yann@1
    49
CT_LOG_LEVEL_WARN=1
yann@1
    50
CT_LOG_LEVEL_INFO=2
yann@1
    51
CT_LOG_LEVEL_EXTRA=3
anthony@2154
    52
CT_LOG_LEVEL_CFG=4
anthony@2154
    53
CT_LOG_LEVEL_FILE=5
anthony@2155
    54
CT_LOG_LEVEL_STATE=6
anthony@2155
    55
CT_LOG_LEVEL_ALL=7
anthony@2155
    56
CT_LOG_LEVEL_DEBUG=8
yann@1
    57
yann@1083
    58
# Make it easy to use \n and !
yann@1081
    59
CR=$(printf "\n")
yann@1083
    60
BANG='!'
yann@1081
    61
yann@1
    62
# A function to log what is happening
yann@1
    63
# Different log level are available:
yann@1
    64
#   - ERROR:   A serious, fatal error occurred
yann@1
    65
#   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
yann@1
    66
#   - INFO:    Informational messages
yann@1
    67
#   - EXTRA:   Extra informational messages
anthony@2154
    68
#   - CFG:     Output of various "./configure"-type scripts
anthony@2154
    69
#   - FILE:    File / archive unpacking.
anthony@2155
    70
#   - STATE:   State save & restore
yann@78
    71
#   - ALL:     Component's build messages
anthony@2155
    72
#   - DEBUG:   Internal debug messages
yann@1
    73
# Usage: CT_DoLog <level> [message]
yann@1
    74
# If message is empty, then stdin will be logged.
yann@1
    75
CT_DoLog() {
yann@47
    76
    local max_level LEVEL level cur_l cur_L
yann@47
    77
    local l
yann@1
    78
    eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
yann@1
    79
    # Set the maximum log level to DEBUG if we have none
yann@78
    80
    [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
yann@1
    81
yann@47
    82
    LEVEL="$1"; shift
yann@1
    83
    eval level="\${CT_LOG_LEVEL_${LEVEL}}"
yann@1
    84
yann@1
    85
    if [ $# -eq 0 ]; then
yann@1
    86
        cat -
yann@1
    87
    else
yann@2096
    88
        printf "%s\n" "${*}"
yann@1081
    89
    fi |( IFS="${CR}" # We want the full lines, even leading spaces
yann@523
    90
          _prog_bar_cpt=0
yann@523
    91
          _prog_bar[0]='/'
yann@523
    92
          _prog_bar[1]='-'
yann@523
    93
          _prog_bar[2]='\'
yann@523
    94
          _prog_bar[3]='|'
yann@1
    95
          indent=$((2*CT_STEP_COUNT))
yann@1
    96
          while read line; do
yann@47
    97
              case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
yann@47
    98
                y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@112
    99
                y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@47
   100
                *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@919
   101
                *"make["*"]: *** ["*)   cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@47
   102
                *)                      cur_L="${LEVEL}"; cur_l="${level}";;
yann@47
   103
              esac
yann@523
   104
              # There will always be a log file (stdout, fd #1), be it /dev/null
yann@523
   105
              printf "[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}"
yann@47
   106
              if [ ${cur_l} -le ${max_level} ]; then
yann@523
   107
                  # Only print to console (fd #6) if log level is high enough.
yann@523
   108
                  printf "\r[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}" >&6
yann@82
   109
              fi
yann@82
   110
              if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
yann@523
   111
                  printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${_prog_bar[$((_prog_bar_cpt/10))]}" >&6
yann@523
   112
                  _prog_bar_cpt=$(((_prog_bar_cpt+1)%40))
yann@1
   113
              fi
yann@1
   114
          done
yann@1
   115
        )
yann@1
   116
yann@1
   117
    return 0
yann@1
   118
}
yann@1
   119
yann@535
   120
# Execute an action, and log its messages
yann@1257
   121
# Usage: [VAR=val...] CT_DoExecLog <level> <command [parameters...]>
yann@535
   122
CT_DoExecLog() {
yann@535
   123
    local level="$1"
yann@535
   124
    shift
yann@1516
   125
    CT_DoLog DEBUG "==> Executing: '${*}'"
yann@668
   126
    "${@}" 2>&1 |CT_DoLog "${level}"
yann@535
   127
}
yann@535
   128
yann@96
   129
# Tail message to be logged whatever happens
yann@96
   130
# Usage: CT_DoEnd <level>
yann@96
   131
CT_DoEnd()
yann@96
   132
{
yann@145
   133
    local level="$1"
yann@523
   134
    CT_STOP_DATE=$(CT_DoDate +%s%N)
yann@523
   135
    CT_STOP_DATE_HUMAN=$(CT_DoDate +%Y%m%d.%H%M%S)
yann@599
   136
    if [ "${level}" != "ERROR" ]; then
yann@582
   137
        CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
yann@582
   138
    fi
yann@96
   139
    elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
yann@96
   140
    elapsed_min=$((elapsed/(60*1000*1000*1000)))
yann@523
   141
    elapsed_sec=$(printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000))))
yann@523
   142
    elapsed_csec=$(printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000))))
yann@145
   143
    CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
yann@96
   144
}
yann@96
   145
yann@2051
   146
# Remove entries referring to . and other relative paths
js@2044
   147
# Usage: CT_SanitizePath
js@2044
   148
CT_SanitizePath() {
js@2044
   149
    local new
yann@2051
   150
    local p
js@2044
   151
    local IFS=:
js@2044
   152
    for p in $PATH; do
yann@2051
   153
        # Only accept absolute paths;
yann@2051
   154
        # Note: as a special case the empty string in PATH is equivalent to .
yann@2051
   155
        if [ -n "${p}" -a -z "${p%%/*}" ]; then
js@2044
   156
            new="${new}${new:+:}${p}"
js@2044
   157
        fi
js@2044
   158
    done
js@2044
   159
    PATH="${new}"
js@2044
   160
}
js@2044
   161
yann@2280
   162
# Sanitise the directory name contained in the variable passed as argument:
yann@2280
   163
# - remove duplicate /
yann@2280
   164
# Usage: CT_SanitiseVarDir CT_PREFIX_DIR
yann@2280
   165
CT_SanitiseVarDir() {
yann@2280
   166
    local var
yann@2280
   167
    local old_dir
yann@2280
   168
    local new_dir
yann@2280
   169
yann@2280
   170
    for var in "$@"; do
yann@2280
   171
        eval "old_dir=\"\${${var}}\""
yann@2280
   172
        new_dir="$( printf "${old_dir}"     \
yann@2280
   173
                    |sed -r -e 's:/+:/:g;'  \
yann@2280
   174
                  )"
yann@2280
   175
        eval "${var}=\"${new_dir}\""
yann@2280
   176
        CT_DoLog DEBUG "Sanitised '${var}': '${old_dir}' -> '${new_dir}'"
yann@2280
   177
    done
yann@2280
   178
}
yann@2280
   179
yann@96
   180
# Abort the execution with an error message
yann@1
   181
# Usage: CT_Abort <message>
yann@1
   182
CT_Abort() {
yann@128
   183
    CT_DoLog ERROR "$1"
yann@1
   184
    exit 1
yann@1
   185
}
yann@1
   186
yann@1
   187
# Test a condition, and print a message if satisfied
yann@1
   188
# Usage: CT_Test <message> <tests>
yann@1
   189
CT_Test() {
yann@1
   190
    local ret
yann@1
   191
    local m="$1"
yann@1
   192
    shift
yann@1909
   193
    CT_DoLog DEBUG "Testing '! ( $* )'"
yann@1
   194
    test "$@" && CT_DoLog WARN "$m"
yann@1
   195
    return 0
yann@1
   196
}
yann@1
   197
yann@1
   198
# Test a condition, and abort with an error message if satisfied
yann@1
   199
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   200
CT_TestAndAbort() {
yann@1
   201
    local m="$1"
yann@1
   202
    shift
yann@1909
   203
    CT_DoLog DEBUG "Testing '! ( $* )'"
yann@1
   204
    test "$@" && CT_Abort "$m"
yann@1
   205
    return 0
yann@1
   206
}
yann@1
   207
yann@1
   208
# Test a condition, and abort with an error message if not satisfied
yann@1
   209
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   210
CT_TestOrAbort() {
yann@1
   211
    local m="$1"
yann@1
   212
    shift
yann@1909
   213
    CT_DoLog DEBUG "Testing '$*'"
yann@1
   214
    test "$@" || CT_Abort "$m"
yann@1
   215
    return 0
yann@1
   216
}
yann@1
   217
yann@1
   218
# Test the presence of a tool, or abort if not found
yann@1
   219
# Usage: CT_HasOrAbort <tool>
yann@1
   220
CT_HasOrAbort() {
yann@773
   221
    CT_TestAndAbort "'${1}' not found and needed for successful toolchain build." -z "$(CT_Which "${1}")"
yann@1
   222
    return 0
yann@1
   223
}
yann@1
   224
yann@210
   225
# Search a program: wrap "which" for those system where
yann@1226
   226
# "which" verbosely says there is no match (Mandriva is
yann@1226
   227
# such a sucker...)
yann@210
   228
# Usage: CT_Which <filename>
yann@210
   229
CT_Which() {
yann@210
   230
  which "$1" 2>/dev/null || true
yann@210
   231
}
yann@210
   232
yann@1
   233
# Get current date with nanosecond precision
yann@1
   234
# On those system not supporting nanosecond precision, faked with rounding down
yann@1
   235
# to the highest entire second
yann@1
   236
# Usage: CT_DoDate <fmt>
yann@1
   237
CT_DoDate() {
tvb377@1798
   238
    date "$1" |sed -r -e 's/N$/000000000/;'
yann@1
   239
}
yann@1
   240
yann@1
   241
CT_STEP_COUNT=1
yann@1
   242
CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
yann@1
   243
# Memorise a step being done so that any error is caught
yann@1
   244
# Usage: CT_DoStep <loglevel> <message>
yann@1
   245
CT_DoStep() {
yann@523
   246
    local start=$(CT_DoDate +%s%N)
yann@1
   247
    CT_DoLog "$1" "================================================================="
yann@1
   248
    CT_DoLog "$1" "$2"
yann@1
   249
    CT_STEP_COUNT=$((CT_STEP_COUNT+1))
yann@1
   250
    CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
yann@1
   251
    CT_STEP_START[${CT_STEP_COUNT}]="${start}"
yann@1
   252
    CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
yann@1
   253
    return 0
yann@1
   254
}
yann@1
   255
yann@1
   256
# End the step just being done
yann@1
   257
# Usage: CT_EndStep
yann@1
   258
CT_EndStep() {
yann@523
   259
    local stop=$(CT_DoDate +%s%N)
yann@523
   260
    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
   261
    local elapsed=$(printf "%02d:%02d" $((SECONDS/60)) $((SECONDS%60)))
yann@1
   262
    local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
yann@1
   263
    local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
yann@1
   264
    CT_STEP_COUNT=$((CT_STEP_COUNT-1))
yann@582
   265
    CT_DoLog "${level}" "${message}: done in ${duration}s (at ${elapsed})"
yann@1
   266
    return 0
yann@1
   267
}
yann@1
   268
yann@1
   269
# Pushes into a directory, and pops back
yann@1
   270
CT_Pushd() {
yann@1
   271
    pushd "$1" >/dev/null 2>&1
yann@1
   272
}
yann@1
   273
CT_Popd() {
yann@1
   274
    popd >/dev/null 2>&1
yann@1
   275
}
yann@1
   276
yann@1
   277
# Creates a temporary directory
yann@1
   278
# $1: variable to assign to
yann@1
   279
# Usage: CT_MktempDir foo
yann@1
   280
CT_MktempDir() {
yann@1
   281
    # Some mktemp do not allow more than 6 Xs
yann@1113
   282
    eval "$1"=$(mktemp -q -d "${CT_BUILD_DIR}/tmp.XXXXXX")
yann@1
   283
    CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
yann@787
   284
    CT_DoLog DEBUG "Made temporary directory '${!1}'"
yann@787
   285
    return 0
yann@1
   286
}
yann@1
   287
yann@1148
   288
# Removes one or more directories, even if it is read-only, or its parent is
yann@1138
   289
# Usage: CT_DoForceRmdir dir [...]
yann@1138
   290
CT_DoForceRmdir() {
yann@1148
   291
    local dir
yann@1148
   292
    local mode
yann@1148
   293
    for dir in "${@}"; do
yann@1148
   294
        [ -d "${dir}" ] || continue
titus@1956
   295
        case "$CT_SYS_OS" in
yann@2029
   296
            Linux|CYGWIN*)
titus@1956
   297
                mode="$(stat -c '%a' "$(dirname "${dir}")")"
titus@1956
   298
                ;;
titus@1956
   299
            Darwin|*BSD)
titus@1956
   300
                mode="$(stat -f '%Lp' "$(dirname "${dir}")")"
titus@1956
   301
                ;;
titus@1956
   302
            *)
titus@1956
   303
                CT_Abort "Unhandled host OS $CT_SYS_OS"
titus@1956
   304
                ;;
titus@1956
   305
        esac
yann@1185
   306
        CT_DoExecLog ALL chmod u+w "$(dirname "${dir}")"
yann@1185
   307
        CT_DoExecLog ALL chmod -R u+w "${dir}"
yann@1148
   308
        CT_DoExecLog ALL rm -rf "${dir}"
yann@1185
   309
        CT_DoExecLog ALL chmod ${mode} "$(dirname "${dir}")"
yann@1148
   310
    done
yann@1138
   311
}
yann@1138
   312
yann@1
   313
# Echoes the specified string on stdout until the pipe breaks.
yann@1
   314
# Doesn't fail
yann@1
   315
# $1: string to echo
yann@1
   316
# Usage: CT_DoYes "" |make oldconfig
yann@1
   317
CT_DoYes() {
yann@1
   318
    yes "$1" || true
yann@1
   319
}
yann@63
   320
yann@1391
   321
# Add the specified directory to LD_LIBRARY_PATH, and export it
yann@1391
   322
# If the specified patch is already present, just export
yann@1391
   323
# $1: path to add
yann@1391
   324
# $2: add as 'first' or 'last' path, 'first' is assumed if $2 is empty
yann@1391
   325
# Usage CT_SetLibPath /some/where/lib [first|last]
yann@1391
   326
CT_SetLibPath() {
yann@1391
   327
    local path="$1"
yann@1391
   328
    local pos="$2"
yann@1391
   329
yann@1391
   330
    case ":${LD_LIBRARY_PATH}:" in
yann@1391
   331
        *:"${path}":*)  ;;
yann@1391
   332
        *)  case "${pos}" in
yann@1391
   333
                last)
yann@1391
   334
                    CT_DoLog DEBUG "Adding '${path}' at end of LD_LIBRARY_PATH"
yann@1391
   335
                    LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${path}"
yann@1391
   336
                    ;;
yann@1391
   337
                first|"")
yann@1391
   338
                    CT_DoLog DEBUG "Adding '${path}' at start of LD_LIBRARY_PATH"
yann@1391
   339
                    LD_LIBRARY_PATH="${path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
yann@1391
   340
                    ;;
yann@1391
   341
                *)
yann@1391
   342
                    CT_Abort "Incorrect position '${pos}' to add '${path}' to LD_LIBRARY_PATH"
yann@1391
   343
                    ;;
yann@1391
   344
            esac
yann@1391
   345
            ;;
yann@1391
   346
    esac
yann@1391
   347
    CT_DoLog DEBUG "==> LD_LIBRARY_PATH='${LD_LIBRARY_PATH}'"
yann@1391
   348
    export LD_LIBRARY_PATH
yann@1391
   349
}
yann@1391
   350
yann@85
   351
# Get the file name extension of a component
yann@719
   352
# Usage: CT_GetFileExtension <component_name-component_version> [extension]
yann@1690
   353
# If found, echoes the extension to stdout, and return 0
yann@1690
   354
# If not found, echoes nothing on stdout, and return !0.
yann@85
   355
CT_GetFileExtension() {
yann@85
   356
    local ext
yann@85
   357
    local file="$1"
yann@719
   358
    shift
yann@719
   359
    local first_ext="$1"
yann@85
   360
yann@160
   361
    # we need to also check for an empty extension for those very
yann@160
   362
    # peculiar components that don't have one (such as sstrip from
yann@160
   363
    # buildroot).
yann@1763
   364
    for ext in ${first_ext} .tar.gz .tar.bz2 .tgz .tar /.git ''; do
yann@1763
   365
        if [ -e "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
yann@85
   366
            echo "${ext}"
yann@1690
   367
            exit 0
yann@85
   368
        fi
yann@85
   369
    done
yann@85
   370
yann@1690
   371
    exit 1
yann@85
   372
}
yann@85
   373
yann@2204
   374
# Try to retrieve the specified URL (HTTP or FTP)
yann@2204
   375
# Usage: CT_DoGetFile <URL>
yann@2204
   376
# This functions always returns true (0), as it can be legitimate not
yann@2204
   377
# to find the requested URL (think about snapshots, different layouts
yann@2204
   378
# for different gcc versions, etc...).
yann@2204
   379
CT_DoGetFile() {
yann@2205
   380
    local dest="${1##*/}"
yann@2205
   381
    local tmp="${dest}.tmp-dl"
yann@2204
   382
    # OK, just look if we have them...
yann@2204
   383
    # We are sure at least one is available, ./configure checked for it.
yann@2204
   384
    local _curl=$(CT_Which curl)
yann@2204
   385
    local _wget=$(CT_Which wget)
yann@2204
   386
    _curl="${_curl:-false}"
yann@2204
   387
    _wget="${_wget:-false}"
yann@2204
   388
yann@2205
   389
    # Remove potential left-over from a previous run
yann@2205
   390
    rm -f "${tmp}"
yann@2205
   391
yann@63
   392
    # Some (very old!) FTP server might not support the passive mode, thus
yann@2204
   393
    # retry without.
yann@2204
   394
    # We also retry a few times, in case there is a transient error (eg. behind
yann@2204
   395
    # a dynamic IP that changes during the transfer...)
yann@2204
   396
    # With automated download as we are doing, it can be very dangerous to
yann@2204
   397
    # continue the downloads. It's far better to simply overwrite the
yann@2204
   398
    # destination file.
yann@492
   399
    # Some company networks have firewalls to connect to the internet, but it's
yann@1113
   400
    # not easy to detect them, and wget does not timeout by default while
yann@492
   401
    # connecting, so force a global ${CT_CONNECT_TIMEOUT}-second timeout.
yann@2204
   402
    # For curl, no good progress indicator is available. So, be silent.
yann@2205
   403
    if CT_DoExecLog ALL "${_curl}" --ftp-pasv    --retry 3 --connect-timeout ${CT_CONNECT_TIMEOUT} -L -f -s -o "${tmp}"   "$1"  \
yann@2205
   404
    || CT_DoExecLog ALL "${_curl}"               --retry 3 --connect-timeout ${CT_CONNECT_TIMEOUT} -L -f -s -o "${tmp}"   "$1"  \
yann@2205
   405
    || CT_DoExecLog ALL "${_wget}" --passive-ftp --tries=3 -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary -O "${tmp}" "$1"  \
yann@2205
   406
    || CT_DoExecLog ALL "${_wget}"               --tries=3 -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary -O "${tmp}" "$1"  \
yann@2205
   407
    ; then
yann@2205
   408
        # One of them succeeded, good!
yann@2205
   409
        mv "${tmp}" "${dest}"
yann@2205
   410
    else
yann@2205
   411
        # Woops...
yann@2205
   412
        rm -f "${tmp}"
yann@2205
   413
    fi
yann@63
   414
}
yann@63
   415
yann@1113
   416
# This function tries to retrieve a tarball form a local directory
yann@1113
   417
# Usage: CT_GetLocal <basename> [.extension]
yann@1113
   418
CT_GetLocal() {
yann@1113
   419
    local basename="$1"
yann@1113
   420
    local first_ext="$2"
yann@1113
   421
    local ext
yann@1113
   422
yann@1113
   423
    # Do we already have it in *our* tarballs dir?
yann@1690
   424
    if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
yann@1113
   425
        CT_DoLog DEBUG "Already have '${basename}'"
yann@1113
   426
        return 0
yann@1113
   427
    fi
yann@1113
   428
yann@1113
   429
    if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
yann@1113
   430
        CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
yann@1113
   431
        # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
yann@1113
   432
        # or, as a failover, a file without extension.
yann@1113
   433
        for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@1113
   434
            CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
yann@1113
   435
            if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
yann@1113
   436
                 "${CT_FORCE_DOWNLOAD}" != "y" ]; then
yann@1113
   437
                CT_DoLog DEBUG "Got '${basename}' from local storage"
yann@1113
   438
                CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1113
   439
                return 0
yann@1113
   440
            fi
yann@1113
   441
        done
yann@1113
   442
    fi
yann@1113
   443
    return 1
yann@1113
   444
}
yann@1113
   445
yann@1113
   446
# This function saves the specified to local storage if possible,
yann@1113
   447
# and if so, symlinks it for later usage
yann@1113
   448
# Usage: CT_SaveLocal </full/path/file.name>
yann@1113
   449
CT_SaveLocal() {
yann@1113
   450
    local file="$1"
yann@1113
   451
    local basename="${file##*/}"
yann@1113
   452
yann@1113
   453
    if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
yann@1134
   454
        CT_DoLog EXTRA "Saving '${basename}' to local storage"
yann@1113
   455
        # The file may already exist if downloads are forced: remove it first
yann@1113
   456
        CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
yann@1113
   457
        CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
yann@1113
   458
        CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
yann@1113
   459
    fi
yann@1113
   460
}
yann@1113
   461
yann@63
   462
# Download the file from one of the URLs passed as argument
yann@1113
   463
# Usage: CT_GetFile <basename> [.extension] <url> [url ...]
yann@63
   464
CT_GetFile() {
yann@63
   465
    local ext
yann@1179
   466
    local url URLS LAN_URLS
yann@63
   467
    local file="$1"
yann@1113
   468
    local first_ext
yann@63
   469
    shift
yann@712
   470
    # If next argument starts with a dot, then this is not an URL,
yann@712
   471
    # and we can consider that it is a preferred extension.
yann@242
   472
    case "$1" in
yann@712
   473
        .*) first_ext="$1"
yann@242
   474
            shift
yann@242
   475
            ;;
yann@242
   476
    esac
yann@63
   477
yann@1113
   478
    # Does it exist localy?
yann@1113
   479
    CT_GetLocal "${file}" ${first_ext} && return 0 || true
yann@1113
   480
    # No, it does not...
yann@63
   481
yann@754
   482
    # Try to retrieve the file
yann@788
   483
    CT_DoLog EXTRA "Retrieving '${file}'"
yann@63
   484
    CT_Pushd "${CT_TARBALLS_DIR}"
yann@754
   485
yann@1179
   486
    URLS="$@"
yann@1179
   487
yann@1022
   488
    # Add URLs on the LAN mirror
yann@1022
   489
    LAN_URLS=
yann@1022
   490
    if [ "${CT_USE_MIRROR}" = "y" ]; then
yann@1294
   491
        CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
yann@1294
   492
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}/${file%-*}"
yann@1294
   493
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}"
yann@695
   494
yann@1134
   495
        if [ "${CT_PREFER_MIRROR}" = "y" ]; then
yann@1134
   496
            CT_DoLog DEBUG "Pre-pending LAN mirror URLs"
yann@1179
   497
            URLS="${LAN_URLS} ${URLS}"
yann@1134
   498
        else
yann@1134
   499
            CT_DoLog DEBUG "Appending LAN mirror URLs"
yann@1179
   500
            URLS="${URLS} ${LAN_URLS}"
yann@1134
   501
        fi
yann@1022
   502
    fi
yann@1022
   503
yann@1022
   504
    # Scan all URLs in turn, and try to grab a tarball from there
yann@1763
   505
    # Do *not* try git trees (ext=/.git), this is handled in a specific
yann@1763
   506
    # wrapper, below
yann@242
   507
    for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@102
   508
        # Try all urls in turn
yann@1022
   509
        for url in ${URLS}; do
yann@523
   510
            CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
yann@265
   511
            CT_DoGetFile "${url}/${file}${ext}"
yann@265
   512
            if [ -f "${file}${ext}" ]; then
yann@799
   513
                CT_DoLog DEBUG "Got '${file}' from the Internet"
yann@1113
   514
                CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
yann@265
   515
                return 0
yann@265
   516
            fi
yann@102
   517
        done
yann@102
   518
    done
yann@63
   519
    CT_Popd
yann@63
   520
yann@754
   521
    CT_Abort "Could not retrieve '${file}'."
yann@63
   522
}
yann@63
   523
yann@1113
   524
# Checkout from CVS, and build the associated tarball
yann@1113
   525
# The tarball will be called ${basename}.tar.bz2
yann@1113
   526
# Prerequisite: either the server does not require password,
yann@1113
   527
# or the user must already be logged in.
yann@1113
   528
# 'tag' is the tag to retrieve. Must be specified, but can be empty.
yann@1113
   529
# If dirname is specified, then module will be renamed to dirname
yann@1113
   530
# prior to building the tarball.
yann@1592
   531
# Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
yann@1592
   532
# Note: if '=subdir' is given, then it is used instead of 'module'.
yann@1113
   533
CT_GetCVS() {
yann@1113
   534
    local basename="$1"
yann@1113
   535
    local uri="$2"
yann@1113
   536
    local module="$3"
yann@1113
   537
    local tag="${4:+-r ${4}}"
yann@1113
   538
    local dirname="$5"
yann@1113
   539
    local tmp_dir
yann@1113
   540
yann@1113
   541
    # Does it exist localy?
yann@1113
   542
    CT_GetLocal "${basename}" && return 0 || true
yann@1113
   543
    # No, it does not...
yann@1113
   544
yann@1113
   545
    CT_DoLog EXTRA "Retrieving '${basename}'"
yann@1113
   546
yann@1113
   547
    CT_MktempDir tmp_dir
yann@1113
   548
    CT_Pushd "${tmp_dir}"
yann@1113
   549
yann@1113
   550
    CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
yann@1592
   551
    if [ -n "${dirname}" ]; then
yann@1592
   552
        case "${dirname}" in
yann@1592
   553
            *=*)
yann@1593
   554
                CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
yann@1593
   555
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
yann@1592
   556
                ;;
yann@1592
   557
            *)
yann@1592
   558
                CT_DoExecLog ALL mv "${module}" "${dirname}"
yann@1592
   559
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
yann@1592
   560
                ;;
yann@1592
   561
        esac
yann@1592
   562
    fi
yann@1113
   563
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1113
   564
yann@1113
   565
    CT_Popd
yann@1113
   566
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1113
   567
}
yann@1113
   568
yann@1244
   569
# Check out from SVN, and build the associated tarball
yann@1244
   570
# The tarball will be called ${basename}.tar.bz2
yann@1244
   571
# Prerequisite: either the server does not require password,
yann@1244
   572
# or the user must already be logged in.
yann@1244
   573
# 'rev' is the revision to retrieve
yann@1244
   574
# Usage: CT_GetSVN <basename> <url> [rev]
yann@1244
   575
CT_GetSVN() {
yann@1244
   576
    local basename="$1"
yann@1244
   577
    local uri="$2"
yann@1244
   578
    local rev="$3"
yann@1244
   579
yann@1244
   580
    # Does it exist localy?
yann@1244
   581
    CT_GetLocal "${basename}" && return 0 || true
yann@1244
   582
    # No, it does not...
yann@1244
   583
yann@1244
   584
    CT_DoLog EXTRA "Retrieving '${basename}'"
yann@1244
   585
yann@1244
   586
    CT_MktempDir tmp_dir
yann@1244
   587
    CT_Pushd "${tmp_dir}"
yann@1244
   588
yann@1244
   589
    CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"
yann@1244
   590
    CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
yann@1244
   591
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1244
   592
yann@1244
   593
    CT_Popd
yann@1244
   594
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1244
   595
}
yann@1244
   596
yann@1763
   597
# Clone a git tree
yann@1763
   598
# Tries the given URLs in turn until one can get cloned. No tarball will be created.
yann@1763
   599
# Prerequisites: either the server does not require password,
yann@1763
   600
# or the user has already taken any action to authenticate to the server.
yann@1763
   601
# The cloned tree will *not* be stored in the local tarballs dir!
yann@1763
   602
# Usage: CT_GetGit <basename> <url [url ...]>
yann@1763
   603
CT_GetGit() {
yann@1763
   604
    local basename="$1"; shift
yann@1763
   605
    local url
yann@1763
   606
    local cloned=0
yann@1763
   607
yann@1763
   608
    # Do we have it in our tarballs dir?
yann@1763
   609
    if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
yann@1763
   610
        CT_DoLog EXTRA "Updating git tree '${basename}'"
yann@1763
   611
        CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   612
        CT_DoExecLog ALL git pull
yann@1763
   613
        CT_Popd
yann@1763
   614
    else
yann@1763
   615
        CT_DoLog EXTRA "Retrieving git tree '${basename}'"
yann@1763
   616
        for url in "${@}"; do
yann@1763
   617
            CT_DoLog ALL "Trying to clone from '${url}'"
yann@1763
   618
            CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   619
            if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
yann@1763
   620
                cloned=1
yann@1763
   621
                break
yann@1763
   622
            fi
yann@1763
   623
        done
yann@1763
   624
        CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
yann@1763
   625
    fi
yann@1763
   626
}
yann@1763
   627
yann@1126
   628
# Extract a tarball
yann@63
   629
# Some tarballs need to be extracted in specific places. Eg.: glibc addons
yann@63
   630
# must be extracted in the glibc directory; uCLibc locales must be extracted
yann@1123
   631
# in the extra/locale sub-directory of uClibc. This is taken into account
yann@1123
   632
# by the caller, that did a 'cd' into the correct path before calling us
yann@1123
   633
# and sets nochdir to 'nochdir'.
yann@1763
   634
# Note also that this function handles the git trees!
yann@1763
   635
# Usage: CT_Extract <basename> [nochdir] [options]
yann@1763
   636
# where 'options' are dependent on the source (eg. git branch/tag...)
yann@1126
   637
CT_Extract() {
yann@1761
   638
    local nochdir="$1"
yann@1761
   639
    local basename
yann@1690
   640
    local ext
yann@1690
   641
yann@1761
   642
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
   643
        shift
yann@1761
   644
        nochdir="$(pwd)"
yann@1761
   645
    else
yann@1761
   646
        nochdir="${CT_SRC_DIR}"
yann@1761
   647
    fi
yann@1761
   648
yann@1761
   649
    basename="$1"
yann@1761
   650
    shift
yann@1761
   651
yann@1690
   652
    if ! ext="$(CT_GetFileExtension "${basename}")"; then
yann@1763
   653
      CT_Abort "'${basename}' not found in '${CT_TARBALLS_DIR}'"
yann@1690
   654
    fi
yann@1126
   655
    local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1126
   656
yann@1718
   657
    # Check if already extracted
yann@1718
   658
    if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
yann@1718
   659
        CT_DoLog DEBUG "Already extracted '${basename}'"
yann@1718
   660
        return 0
yann@1718
   661
    fi
yann@1718
   662
yann@1691
   663
    # Check if previously partially extracted
yann@1691
   664
    if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
yann@1691
   665
        CT_DoLog ERROR "The '${basename}' sources were partially extracted."
yann@1691
   666
        CT_DoLog ERROR "Please remove first:"
yann@1691
   667
        CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
yann@1691
   668
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
yann@1691
   669
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1691
   670
    fi
yann@1691
   671
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
yann@1691
   672
yann@1761
   673
    CT_Pushd "${nochdir}"
yann@63
   674
yann@1126
   675
    CT_DoLog EXTRA "Extracting '${basename}'"
yann@63
   676
    case "${ext}" in
anthony@2154
   677
        .tar.bz2)     CT_DoExecLog FILE tar xvjf "${full_file}";;
anthony@2154
   678
        .tar.gz|.tgz) CT_DoExecLog FILE tar xvzf "${full_file}";;
anthony@2154
   679
        .tar)         CT_DoExecLog FILE tar xvf  "${full_file}";;
yann@1763
   680
        /.git)        CT_ExtractGit "${basename}" "${@}";;
yann@1763
   681
        *)            CT_Abort "Don't know how to handle '${basename}${ext}': unknown extension";;
yann@63
   682
    esac
yann@63
   683
yann@1208
   684
    # Some tarballs have read-only files... :-(
yann@1258
   685
    # Because of nochdir, we don't know where we are, so chmod all
yann@1258
   686
    # the src tree
yann@1271
   687
    CT_DoExecLog DEBUG chmod -R u+w "${CT_SRC_DIR}"
yann@1208
   688
yann@1763
   689
    # Don't mark as being extracted for git
yann@1763
   690
    case "${ext}" in
yann@1763
   691
        /.git)  ;;
yann@1763
   692
        *)      CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
yann@1763
   693
    esac
yann@1691
   694
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
yann@1126
   695
yann@1761
   696
    CT_Popd
yann@1126
   697
}
yann@1126
   698
yann@1763
   699
# Create a working git clone
yann@1763
   700
# Usage: CT_ExtractGit <basename> [ref]
yann@1763
   701
# where 'ref' is the reference to use:
yann@1763
   702
#   the full name of a branch, like "remotes/origin/branch_name"
yann@1763
   703
#   a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
yann@1763
   704
#   a tag name
yann@1763
   705
CT_ExtractGit() {
yann@1763
   706
    local basename="${1}"
yann@1763
   707
    local ref="${2}"
yann@1763
   708
    local clone_dir
yann@1763
   709
    local ref_type
yann@1763
   710
yann@1763
   711
    # pushd now to be able to get git revlist in case ref is a date
yann@1763
   712
    clone_dir="${CT_TARBALLS_DIR}/${basename}"
yann@1763
   713
    CT_Pushd "${clone_dir}"
yann@1763
   714
yann@1763
   715
    # What kind of reference is ${ref} ?
yann@1763
   716
    if [ -z "${ref}" ]; then
yann@1763
   717
        # Don't update the clone, keep as-is
yann@1763
   718
        ref_type=none
yann@1763
   719
    elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
yann@1763
   720
        ref_type=tag
yann@1763
   721
    elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
yann@1763
   722
        ref_type=branch
yann@1763
   723
    elif date -d "${ref}" >/dev/null 2>&1; then
yann@1763
   724
        ref_type=date
yann@1763
   725
        ref=$(git rev-list -n1 --before="${ref}")
yann@1763
   726
    else
yann@1763
   727
        CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
yann@1763
   728
    fi
yann@1763
   729
yann@1763
   730
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/${basename}"
yann@1763
   731
    CT_DoExecLog ALL ln -sf "${clone_dir}" "${CT_SRC_DIR}/${basename}"
yann@1763
   732
yann@1763
   733
    case "${ref_type}" in
yann@1763
   734
        none)   ;;
anthony@2154
   735
        *)      CT_DoExecLog FILE git checkout "${ref}";;
yann@1763
   736
    esac
yann@1763
   737
yann@1763
   738
    CT_Popd
yann@1763
   739
}
yann@1763
   740
yann@1126
   741
# Patches the specified component
yann@1761
   742
# See CT_Extract, above, for explanations on 'nochdir'
yann@1901
   743
# Usage: CT_Patch [nochdir] <packagename> <packageversion>
yann@1901
   744
# If the package directory is *not* packagename-packageversion, then
yann@1901
   745
# the caller must cd into the proper directory first, and call us
yann@1901
   746
# with nochdir
yann@1126
   747
CT_Patch() {
yann@1761
   748
    local nochdir="$1"
yann@1901
   749
    local pkgname
yann@1901
   750
    local version
yann@1901
   751
    local pkgdir
yann@1761
   752
    local base_file
yann@1761
   753
    local ver_file
yann@1507
   754
    local d
yann@1507
   755
    local -a patch_dirs
yann@1507
   756
    local bundled_patch_dir
yann@1507
   757
    local local_patch_dir
yann@1126
   758
yann@1761
   759
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
   760
        shift
yann@1906
   761
        pkgname="$1"
yann@1906
   762
        version="$2"
yann@1906
   763
        pkgdir="${pkgname}-${version}"
yann@1761
   764
        nochdir="$(pwd)"
yann@1761
   765
    else
yann@1906
   766
        pkgname="$1"
yann@1906
   767
        version="$2"
yann@1906
   768
        pkgdir="${pkgname}-${version}"
yann@1901
   769
        nochdir="${CT_SRC_DIR}/${pkgdir}"
yann@1761
   770
    fi
yann@1761
   771
yann@1126
   772
    # Check if already patched
yann@1901
   773
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
yann@1901
   774
        CT_DoLog DEBUG "Already patched '${pkgdir}'"
yann@1126
   775
        return 0
yann@63
   776
    fi
yann@63
   777
yann@1271
   778
    # Check if already partially patched
yann@1901
   779
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
yann@1901
   780
        CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
yann@1271
   781
        CT_DoLog ERROR "Please remove first:"
yann@1901
   782
        CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
yann@1901
   783
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
yann@1901
   784
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
yann@1271
   785
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1271
   786
    fi
yann@1901
   787
    touch "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1271
   788
yann@1761
   789
    CT_Pushd "${nochdir}"
yann@1123
   790
yann@1901
   791
    CT_DoLog EXTRA "Patching '${pkgdir}'"
yann@63
   792
yann@1901
   793
    bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
yann@1901
   794
    local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
yann@1507
   795
yann@1507
   796
    case "${CT_PATCH_ORDER}" in
yann@1507
   797
        bundled)        patch_dirs=("${bundled_patch_dir}");;
yann@1507
   798
        local)          patch_dirs=("${local_patch_dir}");;
yann@1507
   799
        bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
yann@1508
   800
        local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
yann@1630
   801
        none)           patch_dirs=;;
yann@1507
   802
    esac
yann@1507
   803
yann@1507
   804
    for d in "${patch_dirs[@]}"; do
yann@1507
   805
        CT_DoLog DEBUG "Looking for patches in '${d}'..."
yann@1507
   806
        if [ -n "${d}" -a -d "${d}" ]; then
yann@1507
   807
            for p in "${d}"/*.patch; do
yann@63
   808
                if [ -f "${p}" ]; then
yann@523
   809
                    CT_DoLog DEBUG "Applying patch '${p}'"
yann@1765
   810
                    CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f <"${p}"
yann@63
   811
                fi
yann@63
   812
            done
yann@1509
   813
            if [ "${CT_PATCH_SINGLE}" = "y" ]; then
yann@1509
   814
                break
yann@1509
   815
            fi
yann@63
   816
        fi
yann@63
   817
    done
yann@63
   818
yann@508
   819
    if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
yann@508
   820
        CT_DoLog ALL "Overiding config.guess and config.sub"
yann@508
   821
        for cfg in config_guess config_sub; do
yann@1101
   822
            eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
yann@1101
   823
            [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
yann@776
   824
            # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
yann@508
   825
            find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
yann@508
   826
        done
yann@508
   827
    fi
yann@508
   828
yann@1903
   829
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
yann@1903
   830
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1126
   831
yann@1761
   832
    CT_Popd
yann@63
   833
}
yann@63
   834
yann@182
   835
# Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
yann@182
   836
# Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
yann@182
   837
CT_DoConfigGuess() {
yann@1101
   838
    if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
yann@1101
   839
        "${CT_TOP_DIR}/scripts/config.guess"
yann@182
   840
    else
yann@1101
   841
        "${CT_LIB_DIR}/scripts/config.guess"
yann@182
   842
    fi
yann@182
   843
}
yann@182
   844
yann@182
   845
CT_DoConfigSub() {
yann@1101
   846
    if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
yann@1101
   847
        "${CT_TOP_DIR}/scripts/config.sub" "$@"
yann@182
   848
    else
yann@1101
   849
        "${CT_LIB_DIR}/scripts/config.sub" "$@"
yann@182
   850
    fi
yann@182
   851
}
yann@182
   852
yann@335
   853
# Compute the target tuple from what is provided by the user
yann@335
   854
# Usage: CT_DoBuildTargetTuple
yann@63
   855
# In fact this function takes the environment variables to build the target
yann@335
   856
# tuple. It is needed both by the normal build sequence, as well as the
yann@63
   857
# sample saving sequence.
yann@335
   858
CT_DoBuildTargetTuple() {
yann@383
   859
    # Set the endianness suffix, and the default endianness gcc option
yann@63
   860
    case "${CT_ARCH_BE},${CT_ARCH_LE}" in
yann@383
   861
        y,) target_endian_eb=eb
yann@383
   862
            target_endian_el=
yann@391
   863
            CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
yann@527
   864
            CT_ARCH_ENDIAN_LDFLAG="-EB"
yann@383
   865
            ;;
yann@383
   866
        ,y) target_endian_eb=
yann@383
   867
            target_endian_el=el
yann@391
   868
            CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
yann@527
   869
            CT_ARCH_ENDIAN_LDFLAG="-EL"
yann@383
   870
            ;;
yann@63
   871
    esac
yann@383
   872
yann@965
   873
    # Build the default architecture tuple part
yann@965
   874
    CT_TARGET_ARCH="${CT_ARCH}"
yann@965
   875
yann@383
   876
    # Set defaults for the system part of the tuple. Can be overriden
yann@383
   877
    # by architecture-specific values.
yann@383
   878
    case "${CT_LIBC}" in
yann@787
   879
        *glibc) CT_TARGET_SYS=gnu;;
yann@383
   880
        uClibc) CT_TARGET_SYS=uclibc;;
yann@1591
   881
        *)      CT_TARGET_SYS=elf;;
yann@63
   882
    esac
yann@383
   883
yann@391
   884
    # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
yann@497
   885
    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
   886
    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
   887
    [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
yann@391
   888
    [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
yann@391
   889
    [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
yann@405
   890
    [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
yann@391
   891
    [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
yann@412
   892
    [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float";           CT_ARCH_WITH_FLOAT="--with-float=soft";          }
yann@391
   893
yann@965
   894
    # Build the default kernel tuple part
yann@965
   895
    CT_TARGET_KERNEL="${CT_KERNEL}"
yann@964
   896
yann@965
   897
    # Overide the default values with the components specific settings
yann@964
   898
    CT_DoArchTupleValues
yann@965
   899
    CT_DoKernelTupleValues
yann@383
   900
yann@391
   901
    # Finish the target tuple construction
bartvdrmeulen@1896
   902
    CT_TARGET="${CT_TARGET_ARCH}"
bartvdrmeulen@1896
   903
    CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
bartvdrmeulen@1896
   904
    CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
bartvdrmeulen@1896
   905
    CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
yann@1094
   906
yann@1094
   907
    # Sanity checks
yann@1094
   908
    __sed_alias=""
yann@1094
   909
    if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
yann@1094
   910
        __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
yann@1094
   911
    fi
yann@1094
   912
    case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
yann@1094
   913
      :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
yann@1094
   914
      :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
yann@1094
   915
      :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
yann@1094
   916
      :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
yann@1094
   917
    esac
yann@1094
   918
yann@1094
   919
    # Canonicalise it
yann@1094
   920
    CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
yann@391
   921
    # Prepare the target CFLAGS
yann@767
   922
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
yann@527
   923
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
yann@397
   924
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
yann@397
   925
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
yann@397
   926
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
yann@397
   927
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
yann@397
   928
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
yann@527
   929
yann@527
   930
    # Now on for the target LDFLAGS
yann@767
   931
    CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
yann@63
   932
}
yann@121
   933
yann@121
   934
# This function does pause the build until the user strikes "Return"
yann@121
   935
# Usage: CT_DoPause [optional_message]
yann@121
   936
CT_DoPause() {
yann@121
   937
    local foo
yann@121
   938
    local message="${1:-Pausing for your pleasure}"
yann@121
   939
    CT_DoLog INFO "${message}"
yann@523
   940
    read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
yann@121
   941
    return 0
yann@121
   942
}
yann@121
   943
yann@1907
   944
# This function creates a tarball of the specified directory, but
yann@1907
   945
# only if it exists
yann@1907
   946
# Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
yann@1907
   947
CT_DoTarballIfExists() {
yann@1907
   948
    local dir="$1"
yann@1907
   949
    local tarball="$2"
yann@1907
   950
    shift 2
yann@1907
   951
    local -a extra_tar_opts=( "$@" )
yann@1908
   952
    local -a compress
yann@1907
   953
yann@1907
   954
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
   955
        y)  compress=( gzip -c -3 - ); tar_ext=.gz;;
yann@1908
   956
        *)  compress=( cat - );        tar_ext=;;
yann@1907
   957
    esac
yann@1907
   958
yann@1907
   959
    if [ -d "${dir}" ]; then
yann@1907
   960
        CT_DoLog DEBUG "  Saving '${dir}'"
yann@1908
   961
        { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" .    \
yann@1908
   962
          |"${compress[@]}" >"${tarball}.tar${tar_ext}"         ;
anthony@2155
   963
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
   964
    else
anthony@2155
   965
        CT_DoLog STATE "  Not saving '${dir}': does not exist"
yann@1907
   966
    fi
yann@1907
   967
}
yann@1907
   968
yann@1907
   969
# This function extracts a tarball to the specified directory, but
yann@1907
   970
# only if the tarball exists
anthony@2155
   971
# Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
yann@1907
   972
CT_DoExtractTarballIfExists() {
yann@1907
   973
    local tarball="$1"
yann@1907
   974
    local dir="$2"
yann@1907
   975
    shift 2
yann@1907
   976
    local -a extra_tar_opts=( "$@" )
yann@1908
   977
    local -a uncompress
yann@1907
   978
yann@1907
   979
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
   980
        y)  uncompress=( gzip -c -d ); tar_ext=.gz;;
yann@1908
   981
        *)  uncompress=( cat );        tar_ext=;;
yann@1907
   982
    esac
yann@1907
   983
yann@1907
   984
    if [ -f "${tarball}.tar${tar_ext}" ]; then
yann@1907
   985
        CT_DoLog DEBUG "  Restoring '${dir}'"
yann@1907
   986
        CT_DoForceRmdir "${dir}"
yann@1907
   987
        CT_DoExecLog DEBUG mkdir -p "${dir}"
yann@1908
   988
        { "${uncompress[@]}" "${tarball}.tar${tar_ext}"     \
yann@1908
   989
          |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
anthony@2155
   990
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
   991
    else
anthony@2155
   992
        CT_DoLog STATE "  Not restoring '${dir}': does not exist"
yann@1907
   993
    fi
yann@1907
   994
}
yann@1907
   995
yann@121
   996
# This function saves the state of the toolchain to be able to restart
yann@121
   997
# at any one point
yann@121
   998
# Usage: CT_DoSaveState <next_step_name>
yann@121
   999
CT_DoSaveState() {
yann@121
  1000
	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
yann@121
  1001
    local state_name="$1"
yann@121
  1002
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@121
  1003
yann@1266
  1004
    # Log this to the log level required by the user
yann@1266
  1005
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
yann@1134
  1006
yann@121
  1007
    rm -rf "${state_dir}"
yann@121
  1008
    mkdir -p "${state_dir}"
yann@121
  1009
anthony@2155
  1010
    CT_DoLog STATE "  Saving environment and aliases"
yann@738
  1011
    # We must omit shell functions, and some specific bash variables
yann@738
  1012
    # that break when restoring the environment, later. We could do
yann@1299
  1013
    # all the processing in the awk script, but a sed is easier...
yann@1299
  1014
    set |awk '
yann@1017
  1015
              BEGIN { _p = 1; }
yann@1017
  1016
              $0~/^[^ ]+ \(\)/ { _p = 0; }
yann@1017
  1017
              _p == 1
yann@1017
  1018
              $0 == "}" { _p = 1; }
yann@1017
  1019
              ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
yann@738
  1020
                           /^(UID|EUID)=/d;
yann@738
  1021
                           /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
yann@121
  1022
yann@2130
  1023
    if [ "${CT_COMPLIBS_BACKUP}" = "y" ]; then
yann@1907
  1024
        CT_DoTarballIfExists "${CT_COMPLIBS_DIR}" "${state_dir}/complibs_dir"
yann@1894
  1025
    fi
yann@2307
  1026
    CT_DoTarballIfExists "${CT_BUILDTOOLS_DIR}" "${state_dir}/buildtools_dir"
yann@1907
  1027
    CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
yann@1907
  1028
    CT_DoTarballIfExists "${CT_CC_CORE_STATIC_PREFIX_DIR}" "${state_dir}/cc_core_static_prefix_dir"
yann@1907
  1029
    CT_DoTarballIfExists "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${state_dir}/cc_core_shared_prefix_dir"
yann@1907
  1030
    CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
yann@121
  1031
yann@121
  1032
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
anthony@2155
  1033
        CT_DoLog STATE "  Saving log file"
yann@121
  1034
        exec >/dev/null
yann@121
  1035
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
  1036
            y)  gzip -3 -c "${CT_LOG_FILE}"  >"${state_dir}/log.gz";;
yann@121
  1037
            *)  cat "${CT_LOG_FILE}" >"${state_dir}/log";;
yann@121
  1038
        esac
yann@121
  1039
        exec >>"${CT_LOG_FILE}"
yann@121
  1040
    fi
yann@121
  1041
}
yann@121
  1042
yann@136
  1043
# This function restores a previously saved state
yann@121
  1044
# Usage: CT_DoLoadState <state_name>
yann@121
  1045
CT_DoLoadState(){
yann@121
  1046
    local state_name="$1"
yann@121
  1047
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@135
  1048
    local old_RESTART="${CT_RESTART}"
yann@135
  1049
    local old_STOP="${CT_STOP}"
yann@121
  1050
yann@523
  1051
    CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
yann@141
  1052
yann@121
  1053
    # We need to do something special with the log file!
yann@121
  1054
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
  1055
        exec >"${state_dir}/tail.log"
yann@121
  1056
    fi
yann@1266
  1057
yann@1266
  1058
    # Log this to the log level required by the user
yann@1266
  1059
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
yann@121
  1060
yann@1907
  1061
    CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
yann@1907
  1062
    CT_DoExtractTarballIfExists "${state_dir}/cc_core_shared_prefix_dir" "${CT_CC_CORE_SHARED_PREFIX_DIR}"
yann@1907
  1063
    CT_DoExtractTarballIfExists "${state_dir}/cc_core_static_prefix_dir" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@1907
  1064
    CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
yann@2307
  1065
    CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_DIR}"
yann@2130
  1066
    if [ "${CT_COMPLIBS_BACKUP}" = "y" ]; then
yann@1907
  1067
        CT_DoExtractTarballIfExists "${state_dir}/complibs_dir" "${CT_COMPLIBS_DIR}"
yann@1894
  1068
    fi
yann@1894
  1069
yann@121
  1070
    # Restore the environment, discarding any error message
yann@121
  1071
    # (for example, read-only bash internals)
anthony@2155
  1072
    CT_DoLog STATE "  Restoring environment"
yann@121
  1073
    . "${state_dir}/env.sh" >/dev/null 2>&1 || true
yann@121
  1074
yann@135
  1075
    # Restore the new RESTART and STOP steps
yann@135
  1076
    CT_RESTART="${old_RESTART}"
yann@135
  1077
    CT_STOP="${old_STOP}"
yann@135
  1078
    unset old_stop old_restart
yann@135
  1079
yann@121
  1080
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
anthony@2155
  1081
        CT_DoLog STATE "  Restoring log file"
yann@121
  1082
        exec >/dev/null
yann@121
  1083
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
  1084
            y)  zcat "${state_dir}/log.gz" >"${CT_LOG_FILE}";;
yann@121
  1085
            *)  cat "${state_dir}/log" >"${CT_LOG_FILE}";;
yann@121
  1086
        esac
yann@121
  1087
        cat "${state_dir}/tail.log" >>"${CT_LOG_FILE}"
yann@121
  1088
        exec >>"${CT_LOG_FILE}"
yann@121
  1089
        rm -f "${state_dir}/tail.log"
yann@121
  1090
    fi
yann@121
  1091
}