scripts/functions
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Sun May 11 23:43:52 2014 +0200 (2014-05-11)
changeset 3320 78af1c99bc6d
parent 3314 f3f518cafd8a
child 3321 8a753e6c5621
permissions -rw-r--r--
scripts/functions: add target_endian_le and target_endian_be

We currently define target_endian_el and target_endian_eb to be the
tuple extension depending on endianness, defined to be respectively
'el' or 'eb' according to the endianness.

Some architecture do not use 'el' or 'eb', but use 'le' or 'be'.

Provide that as well, as two new variables: target_endian_le and
target_endian_be.

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
Cc: Cody P Schafer <dev@codyps.com>
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@2388
     7
    local ret=$?
yann@3083
     8
    local result
yann@3083
     9
    local old_trap
yann@2388
    10
    local intro
yann@2807
    11
    local file line func
yann@2807
    12
    local step step_depth
yann@2388
    13
yann@2807
    14
    # To avoid printing the backtace for each sub-shell
yann@2807
    15
    # up to the top-level, just remember we've dumped it
js@3082
    16
    if [ ! -f "${CT_WORK_DIR}/backtrace" ]; then
js@3082
    17
        touch "${CT_WORK_DIR}/backtrace"
yann@2388
    18
yann@2807
    19
        # Print steps backtrace
yann@2807
    20
        step_depth=${CT_STEP_COUNT}
yann@2807
    21
        CT_STEP_COUNT=1     # To have a zero-indentation
yann@2807
    22
        CT_DoLog ERROR ""
yann@2807
    23
        CT_DoLog ERROR ">>"
yann@2807
    24
        intro="Build failed"
yann@2807
    25
        for((step=step_depth; step>0; step--)); do
yann@2807
    26
            CT_DoLog ERROR ">>  ${intro} in step '${CT_STEP_MESSAGE[${step}]}'"
yann@2807
    27
            intro="      called"
yann@2807
    28
        done
yann@2388
    29
yann@2807
    30
        # Print functions backtrace
yann@2807
    31
        intro="Error happened in"
yann@2807
    32
        CT_DoLog ERROR ">>"
yann@2807
    33
        for((depth=1; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
yann@2807
    34
            file="${BASH_SOURCE[${depth}]#${CT_LIB_DIR}/}"
yann@2807
    35
            func="${FUNCNAME[${depth}]}"
yann@2807
    36
            line="@${BASH_LINENO[${depth}-1]:-?}"
yann@2807
    37
            CT_DoLog ERROR ">>  ${intro}: ${func}[${file}${line}]"
yann@2807
    38
            intro="      called from"
yann@2807
    39
        done
yann@3083
    40
yann@3083
    41
        # If the user asked for interactive debugging, dump him/her to a shell
yann@3083
    42
        if [ "${CT_DEBUG_INTERACTIVE}" = "y" ]; then
yann@3083
    43
            # We do not want this sub-shell exit status to be caught, because
yann@3083
    44
            # it is absolutely legit that it exits with non-zero.
yann@3083
    45
            # Save the trap handler to restore it after our debug-shell
yann@3083
    46
            old_trap="$(trap -p ERR)"
yann@3083
    47
            trap -- ERR
yann@3083
    48
            (
js@3097
    49
                exec >&6 2>&7 <&8
yann@3083
    50
                printf "\r         \n\nCurrent command"
yann@3083
    51
                if [ -n "${cur_cmd}" ]; then
yann@3083
    52
                    printf ":\n  %s\n" "${cur_cmd}"
yann@3083
    53
                else
yann@3083
    54
                    printf " (unknown), "
yann@3083
    55
                fi
yann@3083
    56
                printf "exited with error code: %d\n" ${ret}
yann@3083
    57
                printf "Please fix it up and finish by exiting the shell with one of these values:\n"
yann@3083
    58
                printf "    1  fixed, continue with next build command\n"
yann@3083
    59
                if [ -n "${cur_cmd}" ]; then
yann@3083
    60
                    printf "    2  repeat this build command\n"
yann@3083
    61
                fi
yann@3083
    62
                printf "    3  abort build\n\n"
yann@3083
    63
                while true; do
yann@3083
    64
                    ${bash} --rcfile <(printf "PS1='ct-ng:\w> '\nPROMPT_COMMAND=''\n") -i
yann@3083
    65
                    result=$?
yann@3083
    66
                    case $result in
yann@3083
    67
                        1)  printf "\nContinuing past the failed command.\n\n"
yann@3083
    68
                            break
yann@3083
    69
                            ;;
yann@3083
    70
                        2)  if [ -n "${cur_cmd}" ]; then
yann@3083
    71
                                printf "\nRe-trying last command.\n\n"
yann@3083
    72
                                break
yann@3083
    73
                            fi
yann@3127
    74
                            ;;
yann@3083
    75
                        3)  break;;
yann@3083
    76
                    esac
yann@3127
    77
                    printf "\nPlease exit with one of these values:\n"
yann@3127
    78
                    printf "    1  fixed, continue with next build command\n"
yann@3127
    79
                    if [ -n "${cur_cmd}" ]; then
yann@3127
    80
                        printf "    2  repeat this build command\n"
yann@3127
    81
                    fi
yann@3127
    82
                    printf "    3  abort build\n"
yann@3083
    83
                done
yann@3083
    84
                exit $result
yann@3083
    85
            )
yann@3083
    86
            result=$?
yann@3083
    87
            # Restore the trap handler
yann@3083
    88
            eval "${old_trap}"
yann@3083
    89
            case "${result}" in
yann@3127
    90
                1)  rm -f "${CT_WORK_DIR}/backtrace"; touch "${CT_BUILD_DIR}/skip"; return;;
yann@3083
    91
                2)  rm -f "${CT_WORK_DIR}/backtrace"; touch "${CT_BUILD_DIR}/repeat"; return;;
yann@3083
    92
                # 3 is an abort, continue...
yann@3083
    93
            esac
yann@3083
    94
        fi
yann@2807
    95
    fi
yann@2388
    96
yann@2807
    97
    # And finally, in top-level shell, print some hints
yann@2807
    98
    if [ ${BASH_SUBSHELL} -eq 0 ]; then
yann@2807
    99
        # Help diagnose the error
yann@2807
   100
        CT_STEP_COUNT=1     # To have a zero-indentation
yann@2807
   101
        CT_DoLog ERROR ">>"
yann@2807
   102
        if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@2807
   103
            CT_DoLog ERROR ">>  For more info on this error, look at the file: '${tmp_log_file#${CT_TOP_DIR}/}'"
yann@2807
   104
        fi
yann@2807
   105
        CT_DoLog ERROR ">>  There is a list of known issues, some with workarounds, in:"
yann@2807
   106
        CT_DoLog ERROR ">>      '${CT_DOC_DIR#${CT_TOP_DIR}/}/B - Known issues.txt'"
yann@2807
   107
yann@2807
   108
        CT_DoLog ERROR ""
yann@2807
   109
        CT_DoEnd ERROR
js@3082
   110
        rm -f "${CT_WORK_DIR}/backtrace"
yann@2388
   111
    fi
yann@1
   112
    exit $ret
yann@1
   113
}
yann@136
   114
yann@136
   115
# Install the fault handler
yann@1
   116
trap CT_OnError ERR
yann@1
   117
yann@136
   118
# Inherit the fault handler in subshells and functions
yann@1
   119
set -E
yann@136
   120
yann@136
   121
# Make pipes fail on the _first_ failed command
yann@136
   122
# Not supported on bash < 3.x, but we need it, so drop the obsoleting bash-2.x
yann@1
   123
set -o pipefail
yann@1
   124
yann@136
   125
# Don't hash commands' locations, and search every time it is requested.
yann@136
   126
# This is slow, but needed because of the static/shared core gcc which shall
yann@136
   127
# always match to shared if it exists, and only fallback to static if the
yann@136
   128
# shared is not found
yann@136
   129
set +o hashall
yann@136
   130
yann@165
   131
# Log policy:
yann@165
   132
#  - first of all, save stdout so we can see the live logs: fd #6
js@3097
   133
# (also save stdin and stderr for use by CT_DEBUG_INTERACTIVE)
js@3097
   134
exec 6>&1 7>&2 8<&0
yann@2339
   135
#  - then point stdout to the log file
yann@2339
   136
tmp_log_file="${CT_TOP_DIR}/build.log"
yann@2339
   137
rm -f "${tmp_log_file}"
yann@165
   138
exec >>"${tmp_log_file}"
yann@165
   139
yann@1
   140
# The different log levels:
yann@1
   141
CT_LOG_LEVEL_ERROR=0
yann@1
   142
CT_LOG_LEVEL_WARN=1
yann@1
   143
CT_LOG_LEVEL_INFO=2
yann@1
   144
CT_LOG_LEVEL_EXTRA=3
anthony@2154
   145
CT_LOG_LEVEL_CFG=4
anthony@2154
   146
CT_LOG_LEVEL_FILE=5
anthony@2155
   147
CT_LOG_LEVEL_STATE=6
anthony@2155
   148
CT_LOG_LEVEL_ALL=7
anthony@2155
   149
CT_LOG_LEVEL_DEBUG=8
yann@1
   150
yann@1083
   151
# Make it easy to use \n and !
yann@1081
   152
CR=$(printf "\n")
yann@1083
   153
BANG='!'
yann@1081
   154
yann@1
   155
# A function to log what is happening
yann@1
   156
# Different log level are available:
yann@1
   157
#   - ERROR:   A serious, fatal error occurred
yann@1
   158
#   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
yann@1
   159
#   - INFO:    Informational messages
yann@1
   160
#   - EXTRA:   Extra informational messages
anthony@2154
   161
#   - CFG:     Output of various "./configure"-type scripts
anthony@2154
   162
#   - FILE:    File / archive unpacking.
anthony@2155
   163
#   - STATE:   State save & restore
yann@78
   164
#   - ALL:     Component's build messages
anthony@2155
   165
#   - DEBUG:   Internal debug messages
yann@1
   166
# Usage: CT_DoLog <level> [message]
yann@1
   167
# If message is empty, then stdin will be logged.
yann@1
   168
CT_DoLog() {
yann@47
   169
    local max_level LEVEL level cur_l cur_L
yann@47
   170
    local l
yann@1
   171
    eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
yann@1
   172
    # Set the maximum log level to DEBUG if we have none
yann@78
   173
    [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
yann@1
   174
yann@47
   175
    LEVEL="$1"; shift
yann@1
   176
    eval level="\${CT_LOG_LEVEL_${LEVEL}}"
yann@1
   177
yann@1
   178
    if [ $# -eq 0 ]; then
yann@1
   179
        cat -
yann@1
   180
    else
yann@2096
   181
        printf "%s\n" "${*}"
yann@1081
   182
    fi |( IFS="${CR}" # We want the full lines, even leading spaces
yann@523
   183
          _prog_bar_cpt=0
yann@523
   184
          _prog_bar[0]='/'
yann@523
   185
          _prog_bar[1]='-'
yann@523
   186
          _prog_bar[2]='\'
yann@523
   187
          _prog_bar[3]='|'
yann@1
   188
          indent=$((2*CT_STEP_COUNT))
yann@1
   189
          while read line; do
yann@47
   190
              case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
yann@47
   191
                y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@112
   192
                y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@47
   193
                *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@919
   194
                *"make["*"]: *** ["*)   cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@47
   195
                *)                      cur_L="${LEVEL}"; cur_l="${level}";;
yann@47
   196
              esac
yann@523
   197
              # There will always be a log file (stdout, fd #1), be it /dev/null
yann@523
   198
              printf "[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}"
yann@47
   199
              if [ ${cur_l} -le ${max_level} ]; then
yann@523
   200
                  # Only print to console (fd #6) if log level is high enough.
javier@2382
   201
                  printf "${CT_LOG_PROGRESS_BAR:+\r}[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}" >&6
yann@82
   202
              fi
yann@82
   203
              if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
yann@523
   204
                  printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${_prog_bar[$((_prog_bar_cpt/10))]}" >&6
yann@523
   205
                  _prog_bar_cpt=$(((_prog_bar_cpt+1)%40))
yann@1
   206
              fi
yann@1
   207
          done
yann@1
   208
        )
yann@1
   209
yann@1
   210
    return 0
yann@1
   211
}
yann@1
   212
yann@535
   213
# Execute an action, and log its messages
yann@2340
   214
# It is possible to even log local variable assignments (a-la: var=val ./cmd opts)
yann@2340
   215
# Usage: CT_DoExecLog <level> [VAR=val...] <command> [parameters...]
yann@535
   216
CT_DoExecLog() {
yann@535
   217
    local level="$1"
yann@3083
   218
    local cur_cmd
yann@3085
   219
    local ret
yann@535
   220
    shift
yann@2340
   221
    (
yann@2340
   222
    for i in "$@"; do
yann@3083
   223
        cur_cmd+="'${i}' "
yann@2340
   224
    done
yann@2340
   225
    while true; do
yann@2340
   226
        case "${1}" in
yann@2340
   227
            *=*)    eval export "'${1}'"; shift;;
yann@2340
   228
            *)      break;;
yann@2340
   229
        esac
yann@2340
   230
    done
yann@3083
   231
    # This while-loop goes hand-in-hand with the ERR trap handler:
yann@3083
   232
    # - if the command terminates successfully, then we hit the break
yann@3083
   233
    #   statement, and we exit the loop
yann@3083
   234
    # - if the command terminates in error, then the ERR handler kicks
yann@3083
   235
    #   in, then:
yann@3083
   236
    #     - if the user did *not* ask for interactive debugging, the ERR
yann@3083
   237
    #       handler exits, and we hit the end of the sub-shell
yann@3083
   238
    #     - if the user did ask for interactive debugging, the ERR handler
yann@3083
   239
    #       spawns a shell. Upon termination of this shell, the ERR handler
yann@3083
   240
    #       examines the exit status of the shell:
yann@3083
   241
    #         - if 1, the ERR handler returns; then we hit the else statement,
yann@3083
   242
    #           then the break, and we exit the 'while' loop, to continue the
yann@3083
   243
    #           build;
yann@3083
   244
    #         - if 2, the ERR handler touches the repeat file, and returns;
yann@3083
   245
    #           then we hit the if statement, and we loop for one more
yann@3083
   246
    #           iteration;
yann@3083
   247
    #         - if 3, the ERR handler exits with the command's exit status,
yann@3083
   248
    #           and we're dead;
yann@3083
   249
    #         - for any other exit status of the shell, the ERR handler
yann@3083
   250
    #           prints an informational message, and respawns the shell
yann@3083
   251
    #
yann@3083
   252
    # This allows a user to get an interactive shell that has the same
yann@3083
   253
    # environment (PATH and so on) that the failed command was ran with.
yann@3083
   254
    while true; do
yann@3083
   255
        rm -f "${CT_BUILD_DIR}/repeat"
yann@3083
   256
        CT_DoLog DEBUG "==> Executing: ${cur_cmd}"
yann@3083
   257
        "${@}" 2>&1 |CT_DoLog "${level}"
yann@3085
   258
        ret="${?}"
yann@3083
   259
        if [ -f "${CT_BUILD_DIR}/repeat" ]; then
yann@3127
   260
            rm -f "${CT_BUILD_DIR}/repeat"
yann@3083
   261
            continue
yann@3127
   262
        elif [ -f "${CT_BUILD_DIR}/skip" ]; then
yann@3127
   263
            rm -f "${CT_BUILD_DIR}/skip"
yann@3127
   264
            ret=0
yann@3127
   265
            break
yann@3083
   266
        else
yann@3083
   267
            break
yann@3083
   268
        fi
yann@3083
   269
    done
yann@3085
   270
    exit ${ret}
yann@2340
   271
    )
yann@2340
   272
    # Catch failure of the sub-shell
yann@2340
   273
    [ $? -eq 0 ]
yann@535
   274
}
yann@535
   275
yann@96
   276
# Tail message to be logged whatever happens
yann@96
   277
# Usage: CT_DoEnd <level>
yann@96
   278
CT_DoEnd()
yann@96
   279
{
yann@145
   280
    local level="$1"
yann@523
   281
    CT_STOP_DATE=$(CT_DoDate +%s%N)
yann@523
   282
    CT_STOP_DATE_HUMAN=$(CT_DoDate +%Y%m%d.%H%M%S)
yann@599
   283
    if [ "${level}" != "ERROR" ]; then
yann@582
   284
        CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
yann@582
   285
    fi
yann@96
   286
    elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
yann@96
   287
    elapsed_min=$((elapsed/(60*1000*1000*1000)))
yann@523
   288
    elapsed_sec=$(printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000))))
yann@523
   289
    elapsed_csec=$(printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000))))
yann@145
   290
    CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
yann@96
   291
}
yann@96
   292
yann@2051
   293
# Remove entries referring to . and other relative paths
js@2044
   294
# Usage: CT_SanitizePath
js@2044
   295
CT_SanitizePath() {
js@2044
   296
    local new
yann@2051
   297
    local p
js@2044
   298
    local IFS=:
js@2044
   299
    for p in $PATH; do
yann@2051
   300
        # Only accept absolute paths;
yann@2051
   301
        # Note: as a special case the empty string in PATH is equivalent to .
yann@2051
   302
        if [ -n "${p}" -a -z "${p%%/*}" ]; then
js@2044
   303
            new="${new}${new:+:}${p}"
js@2044
   304
        fi
js@2044
   305
    done
js@2044
   306
    PATH="${new}"
js@2044
   307
}
js@2044
   308
yann@2280
   309
# Sanitise the directory name contained in the variable passed as argument:
yann@2280
   310
# - remove duplicate /
yann@2280
   311
# Usage: CT_SanitiseVarDir CT_PREFIX_DIR
yann@2280
   312
CT_SanitiseVarDir() {
yann@2280
   313
    local var
yann@2280
   314
    local old_dir
yann@2280
   315
    local new_dir
yann@2280
   316
yann@2280
   317
    for var in "$@"; do
yann@2280
   318
        eval "old_dir=\"\${${var}}\""
yann@2280
   319
        new_dir="$( printf "${old_dir}"     \
yann@2280
   320
                    |sed -r -e 's:/+:/:g;'  \
yann@2280
   321
                  )"
yann@2280
   322
        eval "${var}=\"${new_dir}\""
yann@2280
   323
        CT_DoLog DEBUG "Sanitised '${var}': '${old_dir}' -> '${new_dir}'"
yann@2280
   324
    done
yann@2280
   325
}
yann@2280
   326
yann@96
   327
# Abort the execution with an error message
yann@1
   328
# Usage: CT_Abort <message>
yann@1
   329
CT_Abort() {
yann@128
   330
    CT_DoLog ERROR "$1"
yann@3084
   331
    false
yann@1
   332
}
yann@1
   333
yann@1
   334
# Test a condition, and print a message if satisfied
yann@1
   335
# Usage: CT_Test <message> <tests>
yann@1
   336
CT_Test() {
yann@1
   337
    local ret
yann@1
   338
    local m="$1"
yann@1
   339
    shift
yann@1909
   340
    CT_DoLog DEBUG "Testing '! ( $* )'"
yann@1
   341
    test "$@" && CT_DoLog WARN "$m"
yann@1
   342
    return 0
yann@1
   343
}
yann@1
   344
yann@1
   345
# Test a condition, and abort with an error message if satisfied
yann@1
   346
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   347
CT_TestAndAbort() {
yann@1
   348
    local m="$1"
yann@1
   349
    shift
yann@1909
   350
    CT_DoLog DEBUG "Testing '! ( $* )'"
yann@1
   351
    test "$@" && CT_Abort "$m"
yann@1
   352
    return 0
yann@1
   353
}
yann@1
   354
yann@1
   355
# Test a condition, and abort with an error message if not satisfied
yann@1
   356
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   357
CT_TestOrAbort() {
yann@1
   358
    local m="$1"
yann@1
   359
    shift
yann@1909
   360
    CT_DoLog DEBUG "Testing '$*'"
yann@1
   361
    test "$@" || CT_Abort "$m"
yann@1
   362
    return 0
yann@1
   363
}
yann@1
   364
yann@1
   365
# Test the presence of a tool, or abort if not found
yann@1
   366
# Usage: CT_HasOrAbort <tool>
yann@1
   367
CT_HasOrAbort() {
yann@773
   368
    CT_TestAndAbort "'${1}' not found and needed for successful toolchain build." -z "$(CT_Which "${1}")"
yann@1
   369
    return 0
yann@1
   370
}
yann@1
   371
yann@3040
   372
# Search a program: wrap "which" for those system where "which"
yann@3040
   373
# verbosely says there is no match (such as on Mandriva).
yann@210
   374
# Usage: CT_Which <filename>
yann@210
   375
CT_Which() {
yann@210
   376
  which "$1" 2>/dev/null || true
yann@210
   377
}
yann@210
   378
yann@1
   379
# Get current date with nanosecond precision
yann@1
   380
# On those system not supporting nanosecond precision, faked with rounding down
yann@1
   381
# to the highest entire second
yann@1
   382
# Usage: CT_DoDate <fmt>
yann@1
   383
CT_DoDate() {
yann@2383
   384
    date "$1" |sed -r -e 's/%?N$/000000000/;'
yann@1
   385
}
yann@1
   386
yann@1
   387
CT_STEP_COUNT=1
yann@2807
   388
CT_STEP_MESSAGE[${CT_STEP_COUNT}]="(top-level)"
yann@1
   389
# Memorise a step being done so that any error is caught
yann@1
   390
# Usage: CT_DoStep <loglevel> <message>
yann@1
   391
CT_DoStep() {
yann@523
   392
    local start=$(CT_DoDate +%s%N)
yann@1
   393
    CT_DoLog "$1" "================================================================="
yann@1
   394
    CT_DoLog "$1" "$2"
yann@1
   395
    CT_STEP_COUNT=$((CT_STEP_COUNT+1))
yann@1
   396
    CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
yann@1
   397
    CT_STEP_START[${CT_STEP_COUNT}]="${start}"
yann@1
   398
    CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
yann@1
   399
    return 0
yann@1
   400
}
yann@1
   401
yann@1
   402
# End the step just being done
yann@1
   403
# Usage: CT_EndStep
yann@1
   404
CT_EndStep() {
yann@523
   405
    local stop=$(CT_DoDate +%s%N)
yann@523
   406
    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
   407
    local elapsed=$(printf "%02d:%02d" $((SECONDS/60)) $((SECONDS%60)))
yann@1
   408
    local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
yann@1
   409
    local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
yann@1
   410
    CT_STEP_COUNT=$((CT_STEP_COUNT-1))
yann@582
   411
    CT_DoLog "${level}" "${message}: done in ${duration}s (at ${elapsed})"
yann@1
   412
    return 0
yann@1
   413
}
yann@1
   414
yann@1
   415
# Pushes into a directory, and pops back
yann@1
   416
CT_Pushd() {
yann@3212
   417
    CT_DoLog DEBUG "Entering '$1'"
yann@1
   418
    pushd "$1" >/dev/null 2>&1
yann@1
   419
}
yann@1
   420
CT_Popd() {
yann@1
   421
    popd >/dev/null 2>&1
yann@1
   422
}
yann@1
   423
yann@2898
   424
# Create a dir and cd or pushd into it
yann@2898
   425
# Usage: CT_mkdir_cd <dir/to/create>
yann@2898
   426
#        CT_mkdir_pushd <dir/to/create>
yann@2898
   427
CT_mkdir_cd() {
yann@2898
   428
    local dir="${1}"
yann@2898
   429
yann@2898
   430
    mkdir -p "${dir}"
yann@2898
   431
    cd "${dir}"
yann@2898
   432
}
yann@2898
   433
CT_mkdir_pushd() {
yann@2898
   434
    local dir="${1}"
yann@2898
   435
yann@2898
   436
    mkdir -p "${dir}"
yann@2898
   437
    CT_Pushd "${dir}"
yann@2898
   438
}
yann@2898
   439
yann@1
   440
# Creates a temporary directory
yann@1
   441
# $1: variable to assign to
yann@1
   442
# Usage: CT_MktempDir foo
yann@1
   443
CT_MktempDir() {
yann@1
   444
    # Some mktemp do not allow more than 6 Xs
yann@1113
   445
    eval "$1"=$(mktemp -q -d "${CT_BUILD_DIR}/tmp.XXXXXX")
yann@1
   446
    CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
yann@787
   447
    CT_DoLog DEBUG "Made temporary directory '${!1}'"
yann@787
   448
    return 0
yann@1
   449
}
yann@1
   450
yann@1148
   451
# Removes one or more directories, even if it is read-only, or its parent is
yann@1138
   452
# Usage: CT_DoForceRmdir dir [...]
yann@1138
   453
CT_DoForceRmdir() {
yann@1148
   454
    local dir
yann@1148
   455
    local mode
yann@1148
   456
    for dir in "${@}"; do
yann@1148
   457
        [ -d "${dir}" ] || continue
titus@1956
   458
        case "$CT_SYS_OS" in
yann@2029
   459
            Linux|CYGWIN*)
titus@1956
   460
                mode="$(stat -c '%a' "$(dirname "${dir}")")"
titus@1956
   461
                ;;
titus@1956
   462
            Darwin|*BSD)
titus@1956
   463
                mode="$(stat -f '%Lp' "$(dirname "${dir}")")"
titus@1956
   464
                ;;
titus@1956
   465
            *)
titus@1956
   466
                CT_Abort "Unhandled host OS $CT_SYS_OS"
titus@1956
   467
                ;;
titus@1956
   468
        esac
yann@1185
   469
        CT_DoExecLog ALL chmod u+w "$(dirname "${dir}")"
yann@1185
   470
        CT_DoExecLog ALL chmod -R u+w "${dir}"
yann@1148
   471
        CT_DoExecLog ALL rm -rf "${dir}"
yann@1185
   472
        CT_DoExecLog ALL chmod ${mode} "$(dirname "${dir}")"
yann@1148
   473
    done
yann@1138
   474
}
yann@1138
   475
yann@1
   476
# Echoes the specified string on stdout until the pipe breaks.
yann@1
   477
# Doesn't fail
yann@1
   478
# $1: string to echo
yann@1
   479
# Usage: CT_DoYes "" |make oldconfig
yann@1
   480
CT_DoYes() {
yann@1
   481
    yes "$1" || true
yann@1
   482
}
yann@63
   483
yann@1391
   484
# Add the specified directory to LD_LIBRARY_PATH, and export it
yann@1391
   485
# If the specified patch is already present, just export
yann@1391
   486
# $1: path to add
yann@1391
   487
# $2: add as 'first' or 'last' path, 'first' is assumed if $2 is empty
yann@1391
   488
# Usage CT_SetLibPath /some/where/lib [first|last]
yann@1391
   489
CT_SetLibPath() {
yann@1391
   490
    local path="$1"
yann@1391
   491
    local pos="$2"
yann@1391
   492
yann@1391
   493
    case ":${LD_LIBRARY_PATH}:" in
yann@1391
   494
        *:"${path}":*)  ;;
yann@1391
   495
        *)  case "${pos}" in
yann@1391
   496
                last)
yann@1391
   497
                    CT_DoLog DEBUG "Adding '${path}' at end of LD_LIBRARY_PATH"
yann@1391
   498
                    LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${path}"
yann@1391
   499
                    ;;
yann@1391
   500
                first|"")
yann@1391
   501
                    CT_DoLog DEBUG "Adding '${path}' at start of LD_LIBRARY_PATH"
yann@1391
   502
                    LD_LIBRARY_PATH="${path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
yann@1391
   503
                    ;;
yann@1391
   504
                *)
yann@1391
   505
                    CT_Abort "Incorrect position '${pos}' to add '${path}' to LD_LIBRARY_PATH"
yann@1391
   506
                    ;;
yann@1391
   507
            esac
yann@1391
   508
            ;;
yann@1391
   509
    esac
yann@1391
   510
    CT_DoLog DEBUG "==> LD_LIBRARY_PATH='${LD_LIBRARY_PATH}'"
yann@1391
   511
    export LD_LIBRARY_PATH
yann@1391
   512
}
yann@1391
   513
yann@2608
   514
# Build up the list of allowed tarball extensions
yann@2608
   515
# Add them in the prefered order; most preferred comes first
yann@2608
   516
CT_DoListTarballExt() {
yann@2840
   517
    if [ "${CT_CONFIGURE_has_xz}" = "y" ]; then
yann@2609
   518
        printf ".tar.xz\n"
yann@2609
   519
    fi
yann@2646
   520
    if [    "${CT_CONFIGURE_has_lzma}" = "y"    \
yann@2840
   521
         -o "${CT_CONFIGURE_has_xz}" = "y" ]; then
yann@2645
   522
        printf ".tar.lzma\n"
yann@2645
   523
    fi
yann@2608
   524
    printf ".tar.bz2\n"
yann@2608
   525
    printf ".tar.gz\n.tgz\n"
yann@2608
   526
    printf ".tar\n"
martinwguy@3203
   527
    printf ".zip\n"
yann@2608
   528
}
yann@2608
   529
yann@85
   530
# Get the file name extension of a component
yann@719
   531
# Usage: CT_GetFileExtension <component_name-component_version> [extension]
yann@1690
   532
# If found, echoes the extension to stdout, and return 0
yann@1690
   533
# If not found, echoes nothing on stdout, and return !0.
yann@85
   534
CT_GetFileExtension() {
yann@85
   535
    local ext
yann@85
   536
    local file="$1"
yann@719
   537
    shift
yann@719
   538
    local first_ext="$1"
yann@85
   539
yann@160
   540
    # we need to also check for an empty extension for those very
yann@160
   541
    # peculiar components that don't have one (such as sstrip from
yann@160
   542
    # buildroot).
yann@2608
   543
    for ext in ${first_ext} $(CT_DoListTarballExt) /.git ''; do
yann@1763
   544
        if [ -e "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
yann@85
   545
            echo "${ext}"
yann@1690
   546
            exit 0
yann@85
   547
        fi
yann@85
   548
    done
yann@85
   549
yann@1690
   550
    exit 1
yann@85
   551
}
yann@85
   552
yann@2204
   553
# Try to retrieve the specified URL (HTTP or FTP)
yann@2204
   554
# Usage: CT_DoGetFile <URL>
yann@2204
   555
# This functions always returns true (0), as it can be legitimate not
yann@2204
   556
# to find the requested URL (think about snapshots, different layouts
yann@2204
   557
# for different gcc versions, etc...).
yann@2204
   558
CT_DoGetFile() {
yann@2501
   559
    local url="${1}"
yann@2501
   560
    local dest="${CT_TARBALLS_DIR}/${url##*/}"
yann@2205
   561
    local tmp="${dest}.tmp-dl"
yann@2204
   562
yann@2205
   563
    # Remove potential left-over from a previous run
yann@2205
   564
    rm -f "${tmp}"
yann@2205
   565
yann@2204
   566
    # We also retry a few times, in case there is a transient error (eg. behind
yann@2204
   567
    # a dynamic IP that changes during the transfer...)
yann@2204
   568
    # With automated download as we are doing, it can be very dangerous to
yann@2204
   569
    # continue the downloads. It's far better to simply overwrite the
yann@2204
   570
    # destination file.
yann@492
   571
    # Some company networks have firewalls to connect to the internet, but it's
yann@2660
   572
    # not easy to detect them, so force a global ${CT_CONNECT_TIMEOUT}-second
yann@2660
   573
    # timeout.
dev@3307
   574
    if [ ${CT_CONNECT_TIMEOUT} = -1 ]; then
dev@3307
   575
        T=
dev@3307
   576
    else
dev@3307
   577
        T="-T ${CT_CONNECT_TIMEOUT}"
dev@3307
   578
    fi
yann@2763
   579
    if CT_DoExecLog ALL wget --passive-ftp --tries=3 -nc    \
yann@2763
   580
                             --progress=dot:binary          \
dev@3307
   581
                             ${T}                           \
yann@2763
   582
                             -O "${tmp}"                    \
yann@2661
   583
                             "${url}"
yann@2661
   584
    then
yann@2661
   585
        # Success, we got it, good!
yann@2205
   586
        mv "${tmp}" "${dest}"
yann@3085
   587
        CT_DoLog DEBUG "Got it from: \"${url}\""
yann@2205
   588
    else
yann@2205
   589
        # Woops...
yann@2205
   590
        rm -f "${tmp}"
yann@3085
   591
        CT_DoLog DEBUG "Not at this location: \"${url}\""
yann@2205
   592
    fi
yann@63
   593
}
yann@63
   594
yann@1113
   595
# This function tries to retrieve a tarball form a local directory
yann@1113
   596
# Usage: CT_GetLocal <basename> [.extension]
yann@1113
   597
CT_GetLocal() {
yann@1113
   598
    local basename="$1"
yann@1113
   599
    local first_ext="$2"
yann@1113
   600
    local ext
yann@1113
   601
yann@1113
   602
    # Do we already have it in *our* tarballs dir?
yann@1690
   603
    if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
yann@1113
   604
        CT_DoLog DEBUG "Already have '${basename}'"
yann@1113
   605
        return 0
yann@1113
   606
    fi
yann@1113
   607
yann@1113
   608
    if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
yann@1113
   609
        CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
yann@1113
   610
        # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
yann@1113
   611
        # or, as a failover, a file without extension.
yann@2608
   612
        for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
yann@1113
   613
            CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
yann@1113
   614
            if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
yann@1113
   615
                 "${CT_FORCE_DOWNLOAD}" != "y" ]; then
yann@1113
   616
                CT_DoLog DEBUG "Got '${basename}' from local storage"
yann@1113
   617
                CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1113
   618
                return 0
yann@1113
   619
            fi
yann@1113
   620
        done
yann@1113
   621
    fi
yann@1113
   622
    return 1
yann@1113
   623
}
yann@1113
   624
david@3075
   625
# This function gets the custom source from either a tarball or directory
david@3075
   626
# Usage: CT_GetCustom <component> <custom_version> <custom_location>
david@3075
   627
CT_GetCustom() {
david@3075
   628
    local custom_component="$1"
david@3075
   629
    local custom_version="$2"
david@3075
   630
    local custom_location="$3"
david@3075
   631
    local custom_name="${custom_component}-${custom_version}"
david@3075
   632
david@3075
   633
    CT_TestAndAbort "${custom_name}: CT_CUSTOM_LOCATION_ROOT_DIR or ${custom_component}'s CUSTOM_LOCATION must be set." \
david@3075
   634
                    -z "${CT_CUSTOM_LOCATION_ROOT_DIR}" -a -z "${custom_location}"
david@3075
   635
david@3075
   636
    if [ -n "${CT_CUSTOM_LOCATION_ROOT_DIR}" \
david@3075
   637
         -a -z "${custom_location}"          ]; then
david@3075
   638
        custom_location="${CT_CUSTOM_LOCATION_ROOT_DIR}/${custom_component}"
david@3075
   639
    fi
david@3075
   640
david@3075
   641
    CT_DoLog EXTRA "Using '${custom_name}' from custom location"
david@3075
   642
    if [ ! -d "${custom_location}" ]; then
david@3075
   643
        # We need to know the custom tarball extension,
david@3075
   644
        # so we can create a properly-named symlink, which
david@3075
   645
        # we use later on in 'extract'
david@3075
   646
        case "${custom_location}" in
jerzy@3205
   647
            *.tar.xz)       custom_name="${custom_name}.tar.xz";;
david@3075
   648
            *.tar.bz2)      custom_name="${custom_name}.tar.bz2";;
david@3075
   649
            *.tar.gz|*.tgz) custom_name="${custom_name}.tar.gz";;
david@3075
   650
            *.tar)          custom_name="${custom_name}.tar";;
david@3075
   651
            *)  CT_Abort "Unknown extension for custom tarball '${custom_location}'";;
david@3075
   652
        esac
david@3075
   653
        CT_DoExecLog DEBUG ln -sf "${custom_location}"  \
david@3075
   654
                                  "${CT_TARBALLS_DIR}/${custom_name}"
david@3075
   655
    else
david@3075
   656
        CT_DoExecLog DEBUG ln -snf "${custom_location}" \
david@3075
   657
                                   "${CT_SRC_DIR}/${custom_name}"
david@3075
   658
    fi
david@3075
   659
}
david@3075
   660
yann@1113
   661
# This function saves the specified to local storage if possible,
yann@1113
   662
# and if so, symlinks it for later usage
yann@1113
   663
# Usage: CT_SaveLocal </full/path/file.name>
yann@1113
   664
CT_SaveLocal() {
yann@1113
   665
    local file="$1"
yann@1113
   666
    local basename="${file##*/}"
yann@1113
   667
yann@1113
   668
    if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
yann@1134
   669
        CT_DoLog EXTRA "Saving '${basename}' to local storage"
yann@1113
   670
        # The file may already exist if downloads are forced: remove it first
yann@1113
   671
        CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
yann@1113
   672
        CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
yann@1113
   673
        CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
yann@1113
   674
    fi
yann@1113
   675
}
yann@1113
   676
yann@63
   677
# Download the file from one of the URLs passed as argument
yann@1113
   678
# Usage: CT_GetFile <basename> [.extension] <url> [url ...]
yann@63
   679
CT_GetFile() {
yann@63
   680
    local ext
yann@2594
   681
    local -a URLS
yann@2594
   682
    local url
yann@63
   683
    local file="$1"
yann@1113
   684
    local first_ext
yann@63
   685
    shift
yann@712
   686
    # If next argument starts with a dot, then this is not an URL,
yann@712
   687
    # and we can consider that it is a preferred extension.
yann@242
   688
    case "$1" in
yann@712
   689
        .*) first_ext="$1"
yann@242
   690
            shift
yann@242
   691
            ;;
yann@242
   692
    esac
yann@63
   693
yann@1113
   694
    # Does it exist localy?
yann@2599
   695
    if CT_GetLocal "${file}" ${first_ext}; then
yann@2599
   696
        return 0
yann@2599
   697
    fi
yann@1113
   698
    # No, it does not...
yann@63
   699
austinpmorton@3048
   700
    # If not allowed to download from the Internet, don't
austinpmorton@3048
   701
    if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
austinpmorton@3048
   702
        CT_DoLog DEBUG "Not allowed to download from the Internet, aborting ${file} download"
austinpmorton@3048
   703
        return 1
austinpmorton@3048
   704
    fi
austinpmorton@3048
   705
yann@754
   706
    # Try to retrieve the file
yann@788
   707
    CT_DoLog EXTRA "Retrieving '${file}'"
yann@754
   708
yann@1022
   709
    # Add URLs on the LAN mirror
yann@1022
   710
    if [ "${CT_USE_MIRROR}" = "y" ]; then
yann@1294
   711
        CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
yann@2594
   712
        URLS+=( "${CT_MIRROR_BASE_URL}/${file%-*}" )
yann@2594
   713
        URLS+=( "${CT_MIRROR_BASE_URL}" )
yann@2593
   714
    fi
yann@695
   715
austinpmorton@3048
   716
    if [ "${CT_FORCE_MIRROR}" != "y" ]; then
yann@2595
   717
        URLS+=( "${@}" )
yann@2595
   718
    fi
yann@1022
   719
yann@1022
   720
    # Scan all URLs in turn, and try to grab a tarball from there
yann@1763
   721
    # Do *not* try git trees (ext=/.git), this is handled in a specific
yann@1763
   722
    # wrapper, below
yann@2608
   723
    for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
yann@102
   724
        # Try all urls in turn
yann@2594
   725
        for url in "${URLS[@]}"; do
yann@2589
   726
            [ -n "${url}" ] || continue
yann@523
   727
            CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
yann@265
   728
            CT_DoGetFile "${url}/${file}${ext}"
yann@2492
   729
            if [ -f "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
yann@799
   730
                CT_DoLog DEBUG "Got '${file}' from the Internet"
yann@1113
   731
                CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
yann@265
   732
                return 0
yann@265
   733
            fi
yann@102
   734
        done
yann@102
   735
    done
yann@63
   736
yann@2599
   737
    # Just return error, someone may want to catch and handle the error
yann@2492
   738
    # (eg. glibc/eglibc add-ons can be missing).
yann@2492
   739
    return 1
yann@63
   740
}
yann@63
   741
yann@1113
   742
# Checkout from CVS, and build the associated tarball
yann@1113
   743
# The tarball will be called ${basename}.tar.bz2
yann@1113
   744
# Prerequisite: either the server does not require password,
yann@1113
   745
# or the user must already be logged in.
yann@1113
   746
# 'tag' is the tag to retrieve. Must be specified, but can be empty.
yann@1113
   747
# If dirname is specified, then module will be renamed to dirname
yann@1113
   748
# prior to building the tarball.
yann@1592
   749
# Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
yann@1592
   750
# Note: if '=subdir' is given, then it is used instead of 'module'.
yann@1113
   751
CT_GetCVS() {
yann@1113
   752
    local basename="$1"
yann@1113
   753
    local uri="$2"
yann@1113
   754
    local module="$3"
yann@1113
   755
    local tag="${4:+-r ${4}}"
yann@1113
   756
    local dirname="$5"
yann@1113
   757
    local tmp_dir
yann@1113
   758
yann@2592
   759
    # First try locally, then the mirror
yann@2592
   760
    if CT_GetFile "${basename}"; then
yann@2592
   761
        # Got it! Return early! :-)
yann@2592
   762
        return 0
yann@2592
   763
    fi
yann@1113
   764
yann@2595
   765
    if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
yann@2595
   766
        CT_DoLog WARN "Downloads forbidden, not trying cvs retrieval"
yann@2595
   767
        return 1
yann@2595
   768
    fi
yann@2595
   769
yann@1113
   770
    CT_MktempDir tmp_dir
yann@1113
   771
    CT_Pushd "${tmp_dir}"
yann@1113
   772
yann@1113
   773
    CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
yann@1592
   774
    if [ -n "${dirname}" ]; then
yann@1592
   775
        case "${dirname}" in
yann@1592
   776
            *=*)
yann@1593
   777
                CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
yann@1593
   778
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
yann@1592
   779
                ;;
yann@1592
   780
            *)
yann@1592
   781
                CT_DoExecLog ALL mv "${module}" "${dirname}"
yann@1592
   782
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
yann@1592
   783
                ;;
yann@1592
   784
        esac
yann@1592
   785
    fi
yann@1113
   786
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1113
   787
yann@1113
   788
    CT_Popd
yann@1113
   789
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1113
   790
}
yann@1113
   791
yann@1244
   792
# Check out from SVN, and build the associated tarball
yann@1244
   793
# The tarball will be called ${basename}.tar.bz2
yann@1244
   794
# Prerequisite: either the server does not require password,
yann@1244
   795
# or the user must already be logged in.
yann@1244
   796
# 'rev' is the revision to retrieve
yann@1244
   797
# Usage: CT_GetSVN <basename> <url> [rev]
yann@1244
   798
CT_GetSVN() {
yann@1244
   799
    local basename="$1"
yann@1244
   800
    local uri="$2"
yann@1244
   801
    local rev="$3"
yann@1244
   802
yann@2590
   803
    # First try locally, then the mirror
yann@2590
   804
    if CT_GetFile "${basename}"; then
yann@2590
   805
        # Got it! Return early! :-)
yann@2590
   806
        return 0
yann@2590
   807
    fi
yann@1244
   808
yann@2595
   809
    if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
yann@2595
   810
        CT_DoLog WARN "Downloads forbidden, not trying svn retrieval"
yann@2595
   811
        return 1
yann@2595
   812
    fi
yann@2595
   813
yann@1244
   814
    CT_MktempDir tmp_dir
yann@1244
   815
    CT_Pushd "${tmp_dir}"
yann@1244
   816
yann@2494
   817
    if ! CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"; then
yann@2494
   818
        CT_DoLog WARN "Could not retrieve '${basename}'"
yann@2494
   819
        return 1
yann@2494
   820
    fi
yann@1244
   821
    CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
yann@1244
   822
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1244
   823
yann@1244
   824
    CT_Popd
yann@1244
   825
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1244
   826
}
yann@1244
   827
yann@1763
   828
# Clone a git tree
yann@1763
   829
# Tries the given URLs in turn until one can get cloned. No tarball will be created.
yann@1763
   830
# Prerequisites: either the server does not require password,
yann@1763
   831
# or the user has already taken any action to authenticate to the server.
yann@1763
   832
# The cloned tree will *not* be stored in the local tarballs dir!
yann@3314
   833
# Usage: CT_GetGit <basename> <cset> <url>
yann@1763
   834
CT_GetGit() {
yann@3314
   835
    local basename="${1}"
yann@3314
   836
    local cset="${2}"
yann@3314
   837
    local url="${3}"
yann@3314
   838
    local file="${basename}-${cset}.tar.gz"
yann@3314
   839
    local dir="${CT_TARBALLS_DIR}/${basename}-${cset}.git"
yann@3314
   840
    local dest="${CT_TARBALLS_DIR}/${file}"
yann@3314
   841
    local tmp="${CT_TARBALLS_DIR}/${file}.tmp-dl"
yann@3314
   842
yann@3314
   843
    # Do we alreadyhave it?
yann@3314
   844
    if CT_GetLocal "${file}"; then
yann@3314
   845
        return 0
yann@3314
   846
    fi
yann@3314
   847
    # Nope...
yann@1763
   848
yann@2595
   849
    if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
yann@2595
   850
        CT_DoLog WARN "Downloads forbidden, not trying git retrieval"
yann@2595
   851
        return 1
yann@2595
   852
    fi
yann@2595
   853
yann@3314
   854
    # Add URLs on the LAN mirror
yann@3314
   855
    # We subvert the normal download method, just to look for
yann@3314
   856
    # looking at the local mirror
yann@3314
   857
    if CT_GetFile "${basename}-${cset}" .tar.gz; then
yann@3314
   858
        return 0
yann@3314
   859
    fi
yann@3314
   860
yann@3314
   861
    CT_DoLog EXTRA "Retrieving '${basename}-${cset}' (git)"
yann@3314
   862
yann@3314
   863
    # Remove potential left-over from a previous run
yann@3314
   864
    CT_DoExecLog ALL rm -rf "${tmp}.tar.gz" "${tmp}.tar" "${tmp}" "${dir}"
yann@3314
   865
yann@3314
   866
    if CT_DoExecLog ALL git clone "${url}" "${dir}"; then
yann@3314
   867
        # Yep, cloned OK
yann@3314
   868
        CT_Pushd "${dir}"
yann@3314
   869
        CT_DoExecLog ALL git archive --format=tar                       \
yann@3314
   870
                                     --prefix="${basename}-${cset}/"    \
yann@3314
   871
                                     -o "${tmp}.tar"                    \
yann@3314
   872
                                     "${cset}"
yann@3314
   873
        CT_DoExecLog ALL gzip -9 "${tmp}.tar"
yann@3314
   874
        CT_DoExecLog ALL mv -f "${tmp}.tar.gz" "${dest}"
yann@3314
   875
        CT_SaveLocal "${dest}"
yann@3314
   876
        CT_DoExecLog ALL rm -rf "${tmp}.tar.gz" "${tmp}.tar" "${tmp}" "${dir}"
yann@1763
   877
        CT_Popd
yann@1763
   878
    else
yann@3314
   879
        # Woops...
yann@3314
   880
        CT_DoExecLog ALL rm -rf "${dir}"
yann@3314
   881
        CT_DoLog Debug "Could not clone '${basename}'"
yann@3314
   882
        return 1
yann@1763
   883
    fi
yann@1763
   884
}
yann@1763
   885
yann@1126
   886
# Extract a tarball
yann@63
   887
# Some tarballs need to be extracted in specific places. Eg.: glibc addons
yann@63
   888
# must be extracted in the glibc directory; uCLibc locales must be extracted
yann@1123
   889
# in the extra/locale sub-directory of uClibc. This is taken into account
yann@1123
   890
# by the caller, that did a 'cd' into the correct path before calling us
yann@1123
   891
# and sets nochdir to 'nochdir'.
yann@1763
   892
# Note also that this function handles the git trees!
martinwguy@3203
   893
# Usage: CT_Extract [nochdir] <basename> [options]
yann@1763
   894
# where 'options' are dependent on the source (eg. git branch/tag...)
yann@1126
   895
CT_Extract() {
yann@1761
   896
    local nochdir="$1"
yann@1761
   897
    local basename
yann@1690
   898
    local ext
yann@2646
   899
    local lzma_prog
yann@2605
   900
    local -a tar_opts
yann@1690
   901
yann@1761
   902
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
   903
        shift
yann@1761
   904
        nochdir="$(pwd)"
yann@1761
   905
    else
yann@1761
   906
        nochdir="${CT_SRC_DIR}"
yann@1761
   907
    fi
yann@1761
   908
yann@1761
   909
    basename="$1"
yann@1761
   910
    shift
yann@1761
   911
yann@1690
   912
    if ! ext="$(CT_GetFileExtension "${basename}")"; then
yann@2493
   913
        CT_DoLog WARN "'${basename}' not found in '${CT_TARBALLS_DIR}'"
yann@2493
   914
        return 1
yann@1690
   915
    fi
yann@1126
   916
    local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1126
   917
yann@1718
   918
    # Check if already extracted
yann@1718
   919
    if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
yann@1718
   920
        CT_DoLog DEBUG "Already extracted '${basename}'"
yann@1718
   921
        return 0
yann@1718
   922
    fi
yann@1718
   923
yann@1691
   924
    # Check if previously partially extracted
yann@1691
   925
    if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
yann@1691
   926
        CT_DoLog ERROR "The '${basename}' sources were partially extracted."
yann@1691
   927
        CT_DoLog ERROR "Please remove first:"
yann@1691
   928
        CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
yann@1691
   929
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
yann@1691
   930
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1691
   931
    fi
yann@1691
   932
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
yann@1691
   933
yann@1761
   934
    CT_Pushd "${nochdir}"
yann@63
   935
yann@1126
   936
    CT_DoLog EXTRA "Extracting '${basename}'"
benoit@2574
   937
    CT_DoExecLog FILE mkdir -p "${basename}"
yann@2605
   938
    tar_opts=( "--strip-components=1" )
yann@2605
   939
    tar_opts+=( "-C" "${basename}" )
yann@2605
   940
    tar_opts+=( "-xv" )
yann@2646
   941
yann@2646
   942
    # One note here:
yann@2646
   943
    # - lzma can be handled either with 'xz' or 'lzma'
yann@2646
   944
    # - we get lzma tarball only if either or both are available
yann@2646
   945
    # - so, if we get an lzma tarball, and either 'xz' or 'lzma' is
yann@2646
   946
    #   missing, we can assume the other is available
yann@2646
   947
    if [ "${CT_CONFIGURE_has_lzma}" = "y" ]; then
titus@2785
   948
        lzma_prog="lzma -fdc"
yann@2646
   949
    else
titus@2785
   950
        lzma_prog="xz -fdc"
yann@2646
   951
    fi
yann@63
   952
    case "${ext}" in
titus@2785
   953
        .tar.xz)      xz -fdc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
titus@2785
   954
        .tar.lzma)    ${lzma_prog} "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
titus@2785
   955
        .tar.bz2)     bzip2 -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
titus@2785
   956
        .tar.gz|.tgz) gzip -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
yann@2608
   957
        .tar)         CT_DoExecLog FILE tar "${tar_opts[@]}" -f "${full_file}";;
martinwguy@3203
   958
        .zip)         CT_DoExecLog FILE unzip "${@}" "${full_file}";;
yann@1763
   959
        /.git)        CT_ExtractGit "${basename}" "${@}";;
yann@2493
   960
        *)            CT_DoLog WARN "Don't know how to handle '${basename}${ext}': unknown extension"
yann@2493
   961
                      return 1
yann@2493
   962
                      ;;
yann@63
   963
    esac
yann@63
   964
yann@1763
   965
    # Don't mark as being extracted for git
yann@1763
   966
    case "${ext}" in
yann@1763
   967
        /.git)  ;;
yann@1763
   968
        *)      CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
yann@1763
   969
    esac
yann@1691
   970
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
yann@1126
   971
yann@1761
   972
    CT_Popd
yann@1126
   973
}
yann@1126
   974
esben@2721
   975
# Create a working git clone of a local git repository
yann@1763
   976
# Usage: CT_ExtractGit <basename> [ref]
yann@1763
   977
# where 'ref' is the reference to use:
yann@1763
   978
#   the full name of a branch, like "remotes/origin/branch_name"
yann@1763
   979
#   a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
yann@1763
   980
#   a tag name
esben@2721
   981
# If 'ref' is not given, the current repository HEAD will be used
yann@1763
   982
CT_ExtractGit() {
yann@1763
   983
    local basename="${1}"
yann@1763
   984
    local ref="${2}"
esben@2721
   985
    local repo
yann@1763
   986
    local ref_type
yann@1763
   987
yann@1763
   988
    # pushd now to be able to get git revlist in case ref is a date
esben@2721
   989
    repo="${CT_TARBALLS_DIR}/${basename}"
esben@2721
   990
    CT_Pushd "${repo}"
yann@1763
   991
yann@1763
   992
    # What kind of reference is ${ref} ?
yann@1763
   993
    if [ -z "${ref}" ]; then
esben@2721
   994
        ref_type=head
esben@2721
   995
        ref=$(git rev-list -n1 HEAD)
yann@1763
   996
    elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
yann@1763
   997
        ref_type=tag
yann@1763
   998
    elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
yann@1763
   999
        ref_type=branch
yann@1763
  1000
    elif date -d "${ref}" >/dev/null 2>&1; then
yann@1763
  1001
        ref_type=date
yann@1763
  1002
        ref=$(git rev-list -n1 --before="${ref}")
yann@1763
  1003
    else
yann@1763
  1004
        CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
yann@1763
  1005
    fi
yann@1763
  1006
esben@2721
  1007
    CT_Popd
yann@1763
  1008
esben@2721
  1009
    CT_DoExecLog FILE rmdir "${basename}"
yann@1763
  1010
    case "${ref_type}" in
esben@2721
  1011
        branch) CT_DoExecLog FILE git clone -b "${ref}" "${repo}" "${basename}" ;;
esben@2721
  1012
        *)      CT_DoExecLog FILE git clone "${repo}" "${basename}"
esben@2721
  1013
                CT_Pushd "${basename}"
esben@2721
  1014
                CT_DoExecLog FILE git checkout "${ref}"
esben@2721
  1015
                CT_Popd
esben@2721
  1016
                ;;
yann@1763
  1017
    esac
yann@1763
  1018
}
yann@1763
  1019
yann@1126
  1020
# Patches the specified component
yann@1761
  1021
# See CT_Extract, above, for explanations on 'nochdir'
yann@1901
  1022
# Usage: CT_Patch [nochdir] <packagename> <packageversion>
yann@1901
  1023
# If the package directory is *not* packagename-packageversion, then
yann@1901
  1024
# the caller must cd into the proper directory first, and call us
yann@1901
  1025
# with nochdir
yann@1126
  1026
CT_Patch() {
yann@1761
  1027
    local nochdir="$1"
yann@1901
  1028
    local pkgname
yann@1901
  1029
    local version
yann@1901
  1030
    local pkgdir
yann@1761
  1031
    local base_file
yann@1761
  1032
    local ver_file
yann@1507
  1033
    local d
yann@1507
  1034
    local -a patch_dirs
yann@1507
  1035
    local bundled_patch_dir
yann@1507
  1036
    local local_patch_dir
yann@1126
  1037
yann@1761
  1038
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
  1039
        shift
yann@1906
  1040
        pkgname="$1"
yann@1906
  1041
        version="$2"
yann@1906
  1042
        pkgdir="${pkgname}-${version}"
yann@1761
  1043
        nochdir="$(pwd)"
yann@1761
  1044
    else
yann@1906
  1045
        pkgname="$1"
yann@1906
  1046
        version="$2"
yann@1906
  1047
        pkgdir="${pkgname}-${version}"
yann@1901
  1048
        nochdir="${CT_SRC_DIR}/${pkgdir}"
yann@1761
  1049
    fi
yann@1761
  1050
yann@1126
  1051
    # Check if already patched
yann@1901
  1052
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
yann@1901
  1053
        CT_DoLog DEBUG "Already patched '${pkgdir}'"
yann@1126
  1054
        return 0
yann@63
  1055
    fi
yann@63
  1056
yann@1271
  1057
    # Check if already partially patched
yann@1901
  1058
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
yann@1901
  1059
        CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
yann@1271
  1060
        CT_DoLog ERROR "Please remove first:"
yann@1901
  1061
        CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
yann@1901
  1062
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
yann@1901
  1063
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
yann@1271
  1064
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1271
  1065
    fi
yann@1901
  1066
    touch "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1271
  1067
yann@1761
  1068
    CT_Pushd "${nochdir}"
yann@1123
  1069
yann@1901
  1070
    CT_DoLog EXTRA "Patching '${pkgdir}'"
yann@63
  1071
yann@1901
  1072
    bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
yann@1901
  1073
    local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
yann@1507
  1074
yann@1507
  1075
    case "${CT_PATCH_ORDER}" in
yann@1507
  1076
        bundled)        patch_dirs=("${bundled_patch_dir}");;
yann@1507
  1077
        local)          patch_dirs=("${local_patch_dir}");;
yann@1507
  1078
        bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
yann@1508
  1079
        local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
yann@1630
  1080
        none)           patch_dirs=;;
yann@1507
  1081
    esac
yann@1507
  1082
yann@1507
  1083
    for d in "${patch_dirs[@]}"; do
yann@1507
  1084
        CT_DoLog DEBUG "Looking for patches in '${d}'..."
yann@1507
  1085
        if [ -n "${d}" -a -d "${d}" ]; then
yann@1507
  1086
            for p in "${d}"/*.patch; do
yann@63
  1087
                if [ -f "${p}" ]; then
js@3096
  1088
                    CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f -i "${p}"
yann@63
  1089
                fi
yann@63
  1090
            done
yann@1509
  1091
            if [ "${CT_PATCH_SINGLE}" = "y" ]; then
yann@1509
  1092
                break
yann@1509
  1093
            fi
yann@63
  1094
        fi
yann@63
  1095
    done
yann@63
  1096
yann@508
  1097
    if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
yann@508
  1098
        CT_DoLog ALL "Overiding config.guess and config.sub"
yann@508
  1099
        for cfg in config_guess config_sub; do
yann@1101
  1100
            eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
yann@1101
  1101
            [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
yann@776
  1102
            # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
yann@508
  1103
            find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
yann@508
  1104
        done
yann@508
  1105
    fi
yann@508
  1106
yann@1903
  1107
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
yann@1903
  1108
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1126
  1109
yann@1761
  1110
    CT_Popd
yann@63
  1111
}
yann@63
  1112
yann@182
  1113
# Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
yann@182
  1114
# Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
yann@182
  1115
CT_DoConfigGuess() {
yann@1101
  1116
    if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
yann@1101
  1117
        "${CT_TOP_DIR}/scripts/config.guess"
yann@182
  1118
    else
yann@1101
  1119
        "${CT_LIB_DIR}/scripts/config.guess"
yann@182
  1120
    fi
yann@182
  1121
}
yann@182
  1122
yann@182
  1123
CT_DoConfigSub() {
yann@1101
  1124
    if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
yann@1101
  1125
        "${CT_TOP_DIR}/scripts/config.sub" "$@"
yann@182
  1126
    else
yann@1101
  1127
        "${CT_LIB_DIR}/scripts/config.sub" "$@"
yann@182
  1128
    fi
yann@182
  1129
}
yann@182
  1130
yann@335
  1131
# Compute the target tuple from what is provided by the user
yann@335
  1132
# Usage: CT_DoBuildTargetTuple
yann@63
  1133
# In fact this function takes the environment variables to build the target
yann@335
  1134
# tuple. It is needed both by the normal build sequence, as well as the
yann@63
  1135
# sample saving sequence.
yann@335
  1136
CT_DoBuildTargetTuple() {
yann@383
  1137
    # Set the endianness suffix, and the default endianness gcc option
yann@2773
  1138
    case "${CT_ARCH_ENDIAN}" in
yann@2773
  1139
        big)
yann@2773
  1140
            target_endian_eb=eb
yann@3320
  1141
            target_endian_be=be
yann@383
  1142
            target_endian_el=
yann@3320
  1143
            target_endian_le=
yann@391
  1144
            CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
yann@2967
  1145
            CT_ARCH_ENDIAN_LDFLAG="-Wl,-EB"
yann@383
  1146
            ;;
yann@2773
  1147
        little)
yann@2773
  1148
            target_endian_eb=
yann@3320
  1149
            target_endian_be=
yann@383
  1150
            target_endian_el=el
yann@3320
  1151
            target_endian_le=le
yann@391
  1152
            CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
yann@2967
  1153
            CT_ARCH_ENDIAN_LDFLAG="-Wl,-EL"
yann@383
  1154
            ;;
yann@63
  1155
    esac
yann@383
  1156
yann@965
  1157
    # Build the default architecture tuple part
w@3169
  1158
    CT_TARGET_ARCH="${CT_ARCH}${CT_ARCH_SUFFIX}"
yann@965
  1159
yann@383
  1160
    # Set defaults for the system part of the tuple. Can be overriden
yann@383
  1161
    # by architecture-specific values.
yann@383
  1162
    case "${CT_LIBC}" in
yann@787
  1163
        *glibc) CT_TARGET_SYS=gnu;;
yann@383
  1164
        uClibc) CT_TARGET_SYS=uclibc;;
yann@1591
  1165
        *)      CT_TARGET_SYS=elf;;
yann@63
  1166
    esac
yann@383
  1167
yann@391
  1168
    # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
yann@497
  1169
    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
  1170
    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
  1171
    [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
yann@391
  1172
    [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
yann@391
  1173
    [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
yann@405
  1174
    [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
yann@391
  1175
    [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
michael@2737
  1176
michael@2737
  1177
    case "${CT_ARCH_FLOAT}" in
michael@2738
  1178
        hard)
michael@2738
  1179
            CT_ARCH_FLOAT_CFLAG="-mhard-float"
michael@2738
  1180
            CT_ARCH_WITH_FLOAT="--with-float=hard"
michael@2738
  1181
            ;;
michael@2737
  1182
        soft)
michael@2737
  1183
            CT_ARCH_FLOAT_CFLAG="-msoft-float"
michael@2737
  1184
            CT_ARCH_WITH_FLOAT="--with-float=soft"
michael@2737
  1185
            ;;
michael@2739
  1186
        softfp)
michael@2739
  1187
            CT_ARCH_FLOAT_CFLAG="-mfloat-abi=softfp"
michael@2739
  1188
            CT_ARCH_WITH_FLOAT="--with-float=softfp"
michael@2739
  1189
            ;;
michael@2737
  1190
    esac
yann@391
  1191
yann@965
  1192
    # Build the default kernel tuple part
yann@965
  1193
    CT_TARGET_KERNEL="${CT_KERNEL}"
yann@964
  1194
yann@965
  1195
    # Overide the default values with the components specific settings
yann@964
  1196
    CT_DoArchTupleValues
yann@965
  1197
    CT_DoKernelTupleValues
yann@383
  1198
yann@391
  1199
    # Finish the target tuple construction
bartvdrmeulen@1896
  1200
    CT_TARGET="${CT_TARGET_ARCH}"
bartvdrmeulen@1896
  1201
    CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
bartvdrmeulen@1896
  1202
    CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
bartvdrmeulen@1896
  1203
    CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
yann@1094
  1204
yann@1094
  1205
    # Sanity checks
yann@1094
  1206
    __sed_alias=""
yann@1094
  1207
    if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
yann@1094
  1208
        __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
yann@1094
  1209
    fi
yann@1094
  1210
    case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
yann@1094
  1211
      :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
yann@1094
  1212
      :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
yann@1094
  1213
      :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
yann@1094
  1214
      :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
yann@1094
  1215
    esac
yann@1094
  1216
yann@1094
  1217
    # Canonicalise it
yann@1094
  1218
    CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
yann@391
  1219
    # Prepare the target CFLAGS
yann@767
  1220
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
yann@527
  1221
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
yann@397
  1222
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
yann@397
  1223
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
yann@397
  1224
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
yann@397
  1225
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
yann@397
  1226
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
yann@527
  1227
yann@527
  1228
    # Now on for the target LDFLAGS
yann@767
  1229
    CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
yann@63
  1230
}
yann@121
  1231
yann@121
  1232
# This function does pause the build until the user strikes "Return"
yann@121
  1233
# Usage: CT_DoPause [optional_message]
yann@121
  1234
CT_DoPause() {
yann@121
  1235
    local foo
yann@121
  1236
    local message="${1:-Pausing for your pleasure}"
yann@121
  1237
    CT_DoLog INFO "${message}"
yann@523
  1238
    read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
yann@121
  1239
    return 0
yann@121
  1240
}
yann@121
  1241
yann@1907
  1242
# This function creates a tarball of the specified directory, but
yann@1907
  1243
# only if it exists
yann@1907
  1244
# Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
yann@1907
  1245
CT_DoTarballIfExists() {
yann@1907
  1246
    local dir="$1"
yann@1907
  1247
    local tarball="$2"
yann@1907
  1248
    shift 2
yann@1907
  1249
    local -a extra_tar_opts=( "$@" )
yann@1908
  1250
    local -a compress
yann@1907
  1251
yann@1907
  1252
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
  1253
        y)  compress=( gzip -c -3 - ); tar_ext=.gz;;
yann@1908
  1254
        *)  compress=( cat - );        tar_ext=;;
yann@1907
  1255
    esac
yann@1907
  1256
yann@1907
  1257
    if [ -d "${dir}" ]; then
yann@1907
  1258
        CT_DoLog DEBUG "  Saving '${dir}'"
yann@1908
  1259
        { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" .    \
yann@1908
  1260
          |"${compress[@]}" >"${tarball}.tar${tar_ext}"         ;
anthony@2155
  1261
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
  1262
    else
anthony@2155
  1263
        CT_DoLog STATE "  Not saving '${dir}': does not exist"
yann@1907
  1264
    fi
yann@1907
  1265
}
yann@1907
  1266
yann@1907
  1267
# This function extracts a tarball to the specified directory, but
yann@1907
  1268
# only if the tarball exists
anthony@2155
  1269
# Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
yann@1907
  1270
CT_DoExtractTarballIfExists() {
yann@1907
  1271
    local tarball="$1"
yann@1907
  1272
    local dir="$2"
yann@1907
  1273
    shift 2
yann@1907
  1274
    local -a extra_tar_opts=( "$@" )
yann@1908
  1275
    local -a uncompress
yann@1907
  1276
yann@1907
  1277
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
  1278
        y)  uncompress=( gzip -c -d ); tar_ext=.gz;;
yann@1908
  1279
        *)  uncompress=( cat );        tar_ext=;;
yann@1907
  1280
    esac
yann@1907
  1281
yann@1907
  1282
    if [ -f "${tarball}.tar${tar_ext}" ]; then
yann@1907
  1283
        CT_DoLog DEBUG "  Restoring '${dir}'"
yann@1907
  1284
        CT_DoForceRmdir "${dir}"
yann@1907
  1285
        CT_DoExecLog DEBUG mkdir -p "${dir}"
yann@1908
  1286
        { "${uncompress[@]}" "${tarball}.tar${tar_ext}"     \
yann@1908
  1287
          |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
anthony@2155
  1288
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
  1289
    else
anthony@2155
  1290
        CT_DoLog STATE "  Not restoring '${dir}': does not exist"
yann@1907
  1291
    fi
yann@1907
  1292
}
yann@1907
  1293
yann@121
  1294
# This function saves the state of the toolchain to be able to restart
yann@121
  1295
# at any one point
yann@121
  1296
# Usage: CT_DoSaveState <next_step_name>
yann@121
  1297
CT_DoSaveState() {
yann@121
  1298
	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
yann@121
  1299
    local state_name="$1"
yann@121
  1300
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@121
  1301
yann@1266
  1302
    # Log this to the log level required by the user
yann@1266
  1303
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
yann@1134
  1304
yann@121
  1305
    rm -rf "${state_dir}"
yann@121
  1306
    mkdir -p "${state_dir}"
yann@121
  1307
anthony@2155
  1308
    CT_DoLog STATE "  Saving environment and aliases"
yann@738
  1309
    # We must omit shell functions, and some specific bash variables
yann@738
  1310
    # that break when restoring the environment, later. We could do
yann@1299
  1311
    # all the processing in the awk script, but a sed is easier...
yann@1299
  1312
    set |awk '
yann@1017
  1313
              BEGIN { _p = 1; }
yann@1017
  1314
              $0~/^[^ ]+ \(\)/ { _p = 0; }
yann@1017
  1315
              _p == 1
yann@1017
  1316
              $0 == "}" { _p = 1; }
yann@1017
  1317
              ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
yann@738
  1318
                           /^(UID|EUID)=/d;
yann@738
  1319
                           /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
yann@121
  1320
yann@2308
  1321
    CT_DoTarballIfExists "${CT_BUILDTOOLS_PREFIX_DIR}" "${state_dir}/buildtools_dir"
yann@1907
  1322
    CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
yann@1907
  1323
    CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
yann@121
  1324
yann@2339
  1325
    CT_DoLog STATE "  Saving log file"
yann@2339
  1326
    exec >/dev/null
yann@2339
  1327
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@2339
  1328
        y)  gzip -3 -c "${tmp_log_file}"  >"${state_dir}/log.gz";;
yann@2339
  1329
        *)  cat "${tmp_log_file}" >"${state_dir}/log";;
yann@2339
  1330
    esac
yann@2339
  1331
    exec >>"${tmp_log_file}"
yann@121
  1332
}
yann@121
  1333
yann@136
  1334
# This function restores a previously saved state
yann@121
  1335
# Usage: CT_DoLoadState <state_name>
yann@121
  1336
CT_DoLoadState(){
yann@121
  1337
    local state_name="$1"
yann@121
  1338
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@135
  1339
    local old_RESTART="${CT_RESTART}"
yann@135
  1340
    local old_STOP="${CT_STOP}"
yann@121
  1341
yann@523
  1342
    CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
yann@141
  1343
yann@121
  1344
    # We need to do something special with the log file!
yann@121
  1345
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
  1346
        exec >"${state_dir}/tail.log"
yann@121
  1347
    fi
yann@1266
  1348
yann@1266
  1349
    # Log this to the log level required by the user
yann@1266
  1350
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
yann@121
  1351
yann@1907
  1352
    CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
yann@1907
  1353
    CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
yann@2308
  1354
    CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_PREFIX_DIR}"
yann@1894
  1355
yann@121
  1356
    # Restore the environment, discarding any error message
yann@121
  1357
    # (for example, read-only bash internals)
anthony@2155
  1358
    CT_DoLog STATE "  Restoring environment"
yann@121
  1359
    . "${state_dir}/env.sh" >/dev/null 2>&1 || true
yann@121
  1360
yann@135
  1361
    # Restore the new RESTART and STOP steps
yann@135
  1362
    CT_RESTART="${old_RESTART}"
yann@135
  1363
    CT_STOP="${old_STOP}"
yann@135
  1364
    unset old_stop old_restart
yann@135
  1365
yann@2339
  1366
    CT_DoLog STATE "  Restoring log file"
yann@2339
  1367
    exec >/dev/null
yann@2339
  1368
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@3247
  1369
        y)  gzip -dc "${state_dir}/log.gz" >"${tmp_log_file}";;
yann@2339
  1370
        *)  cat "${state_dir}/log" >"${tmp_log_file}";;
yann@2339
  1371
    esac
yann@2339
  1372
    cat "${state_dir}/tail.log" >>"${tmp_log_file}"
yann@2339
  1373
    exec >>"${tmp_log_file}"
yann@2339
  1374
    rm -f "${state_dir}/tail.log"
yann@121
  1375
}