scripts/functions
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Sun May 05 00:01:05 2013 +0200 (2013-05-05)
changeset 3218 3709e61ad85b
parent 3205 30de175d3ed3
child 3247 01ef2159b12a
permissions -rw-r--r--
complibs/cloog: add support for the ISL backend

CLooG 0.18+ will use ISL instead of PPL, so we have to configure
adequately depending of which backend is in use.

The Kconfig entries will decide for us which is selected, so we
can rely on either PPL xor ISL to be selected, not both.

Reported-by: "Plotnikov Dmitry" <leitz@ispras.ru>
[Dmitry did a preliminray patch to add ISL support,
which this patch is inspired from]
Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.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@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.
yann@2204
   574
    # For curl, no good progress indicator is available. So, be silent.
yann@2763
   575
    if CT_DoExecLog ALL wget --passive-ftp --tries=3 -nc    \
yann@2763
   576
                             --progress=dot:binary          \
yann@2763
   577
                             -T ${CT_CONNECT_TIMEOUT}       \
yann@2763
   578
                             -O "${tmp}"                    \
yann@2661
   579
                             "${url}"
yann@2661
   580
    then
yann@2661
   581
        # Success, we got it, good!
yann@2205
   582
        mv "${tmp}" "${dest}"
yann@3085
   583
        CT_DoLog DEBUG "Got it from: \"${url}\""
yann@2205
   584
    else
yann@2205
   585
        # Woops...
yann@2205
   586
        rm -f "${tmp}"
yann@3085
   587
        CT_DoLog DEBUG "Not at this location: \"${url}\""
yann@2205
   588
    fi
yann@63
   589
}
yann@63
   590
yann@1113
   591
# This function tries to retrieve a tarball form a local directory
yann@1113
   592
# Usage: CT_GetLocal <basename> [.extension]
yann@1113
   593
CT_GetLocal() {
yann@1113
   594
    local basename="$1"
yann@1113
   595
    local first_ext="$2"
yann@1113
   596
    local ext
yann@1113
   597
yann@1113
   598
    # Do we already have it in *our* tarballs dir?
yann@1690
   599
    if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
yann@1113
   600
        CT_DoLog DEBUG "Already have '${basename}'"
yann@1113
   601
        return 0
yann@1113
   602
    fi
yann@1113
   603
yann@1113
   604
    if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
yann@1113
   605
        CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
yann@1113
   606
        # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
yann@1113
   607
        # or, as a failover, a file without extension.
yann@2608
   608
        for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
yann@1113
   609
            CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
yann@1113
   610
            if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
yann@1113
   611
                 "${CT_FORCE_DOWNLOAD}" != "y" ]; then
yann@1113
   612
                CT_DoLog DEBUG "Got '${basename}' from local storage"
yann@1113
   613
                CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1113
   614
                return 0
yann@1113
   615
            fi
yann@1113
   616
        done
yann@1113
   617
    fi
yann@1113
   618
    return 1
yann@1113
   619
}
yann@1113
   620
david@3075
   621
# This function gets the custom source from either a tarball or directory
david@3075
   622
# Usage: CT_GetCustom <component> <custom_version> <custom_location>
david@3075
   623
CT_GetCustom() {
david@3075
   624
    local custom_component="$1"
david@3075
   625
    local custom_version="$2"
david@3075
   626
    local custom_location="$3"
david@3075
   627
    local custom_name="${custom_component}-${custom_version}"
david@3075
   628
david@3075
   629
    CT_TestAndAbort "${custom_name}: CT_CUSTOM_LOCATION_ROOT_DIR or ${custom_component}'s CUSTOM_LOCATION must be set." \
david@3075
   630
                    -z "${CT_CUSTOM_LOCATION_ROOT_DIR}" -a -z "${custom_location}"
david@3075
   631
david@3075
   632
    if [ -n "${CT_CUSTOM_LOCATION_ROOT_DIR}" \
david@3075
   633
         -a -z "${custom_location}"          ]; then
david@3075
   634
        custom_location="${CT_CUSTOM_LOCATION_ROOT_DIR}/${custom_component}"
david@3075
   635
    fi
david@3075
   636
david@3075
   637
    CT_DoLog EXTRA "Using '${custom_name}' from custom location"
david@3075
   638
    if [ ! -d "${custom_location}" ]; then
david@3075
   639
        # We need to know the custom tarball extension,
david@3075
   640
        # so we can create a properly-named symlink, which
david@3075
   641
        # we use later on in 'extract'
david@3075
   642
        case "${custom_location}" in
jerzy@3205
   643
            *.tar.xz)       custom_name="${custom_name}.tar.xz";;
david@3075
   644
            *.tar.bz2)      custom_name="${custom_name}.tar.bz2";;
david@3075
   645
            *.tar.gz|*.tgz) custom_name="${custom_name}.tar.gz";;
david@3075
   646
            *.tar)          custom_name="${custom_name}.tar";;
david@3075
   647
            *)  CT_Abort "Unknown extension for custom tarball '${custom_location}'";;
david@3075
   648
        esac
david@3075
   649
        CT_DoExecLog DEBUG ln -sf "${custom_location}"  \
david@3075
   650
                                  "${CT_TARBALLS_DIR}/${custom_name}"
david@3075
   651
    else
david@3075
   652
        CT_DoExecLog DEBUG ln -snf "${custom_location}" \
david@3075
   653
                                   "${CT_SRC_DIR}/${custom_name}"
david@3075
   654
    fi
david@3075
   655
}
david@3075
   656
yann@1113
   657
# This function saves the specified to local storage if possible,
yann@1113
   658
# and if so, symlinks it for later usage
yann@1113
   659
# Usage: CT_SaveLocal </full/path/file.name>
yann@1113
   660
CT_SaveLocal() {
yann@1113
   661
    local file="$1"
yann@1113
   662
    local basename="${file##*/}"
yann@1113
   663
yann@1113
   664
    if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
yann@1134
   665
        CT_DoLog EXTRA "Saving '${basename}' to local storage"
yann@1113
   666
        # The file may already exist if downloads are forced: remove it first
yann@1113
   667
        CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
yann@1113
   668
        CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
yann@1113
   669
        CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
yann@1113
   670
    fi
yann@1113
   671
}
yann@1113
   672
yann@63
   673
# Download the file from one of the URLs passed as argument
yann@1113
   674
# Usage: CT_GetFile <basename> [.extension] <url> [url ...]
yann@63
   675
CT_GetFile() {
yann@63
   676
    local ext
yann@2594
   677
    local -a URLS
yann@2594
   678
    local url
yann@63
   679
    local file="$1"
yann@1113
   680
    local first_ext
yann@63
   681
    shift
yann@712
   682
    # If next argument starts with a dot, then this is not an URL,
yann@712
   683
    # and we can consider that it is a preferred extension.
yann@242
   684
    case "$1" in
yann@712
   685
        .*) first_ext="$1"
yann@242
   686
            shift
yann@242
   687
            ;;
yann@242
   688
    esac
yann@63
   689
yann@1113
   690
    # Does it exist localy?
yann@2599
   691
    if CT_GetLocal "${file}" ${first_ext}; then
yann@2599
   692
        return 0
yann@2599
   693
    fi
yann@1113
   694
    # No, it does not...
yann@63
   695
austinpmorton@3048
   696
    # If not allowed to download from the Internet, don't
austinpmorton@3048
   697
    if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
austinpmorton@3048
   698
        CT_DoLog DEBUG "Not allowed to download from the Internet, aborting ${file} download"
austinpmorton@3048
   699
        return 1
austinpmorton@3048
   700
    fi
austinpmorton@3048
   701
yann@754
   702
    # Try to retrieve the file
yann@788
   703
    CT_DoLog EXTRA "Retrieving '${file}'"
yann@754
   704
yann@1022
   705
    # Add URLs on the LAN mirror
yann@1022
   706
    if [ "${CT_USE_MIRROR}" = "y" ]; then
yann@1294
   707
        CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
yann@2594
   708
        URLS+=( "${CT_MIRROR_BASE_URL}/${file%-*}" )
yann@2594
   709
        URLS+=( "${CT_MIRROR_BASE_URL}" )
yann@2593
   710
    fi
yann@695
   711
austinpmorton@3048
   712
    if [ "${CT_FORCE_MIRROR}" != "y" ]; then
yann@2595
   713
        URLS+=( "${@}" )
yann@2595
   714
    fi
yann@1022
   715
yann@1022
   716
    # Scan all URLs in turn, and try to grab a tarball from there
yann@1763
   717
    # Do *not* try git trees (ext=/.git), this is handled in a specific
yann@1763
   718
    # wrapper, below
yann@2608
   719
    for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
yann@102
   720
        # Try all urls in turn
yann@2594
   721
        for url in "${URLS[@]}"; do
yann@2589
   722
            [ -n "${url}" ] || continue
yann@523
   723
            CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
yann@265
   724
            CT_DoGetFile "${url}/${file}${ext}"
yann@2492
   725
            if [ -f "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
yann@799
   726
                CT_DoLog DEBUG "Got '${file}' from the Internet"
yann@1113
   727
                CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
yann@265
   728
                return 0
yann@265
   729
            fi
yann@102
   730
        done
yann@102
   731
    done
yann@63
   732
yann@2599
   733
    # Just return error, someone may want to catch and handle the error
yann@2492
   734
    # (eg. glibc/eglibc add-ons can be missing).
yann@2492
   735
    return 1
yann@63
   736
}
yann@63
   737
yann@1113
   738
# Checkout from CVS, and build the associated tarball
yann@1113
   739
# The tarball will be called ${basename}.tar.bz2
yann@1113
   740
# Prerequisite: either the server does not require password,
yann@1113
   741
# or the user must already be logged in.
yann@1113
   742
# 'tag' is the tag to retrieve. Must be specified, but can be empty.
yann@1113
   743
# If dirname is specified, then module will be renamed to dirname
yann@1113
   744
# prior to building the tarball.
yann@1592
   745
# Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
yann@1592
   746
# Note: if '=subdir' is given, then it is used instead of 'module'.
yann@1113
   747
CT_GetCVS() {
yann@1113
   748
    local basename="$1"
yann@1113
   749
    local uri="$2"
yann@1113
   750
    local module="$3"
yann@1113
   751
    local tag="${4:+-r ${4}}"
yann@1113
   752
    local dirname="$5"
yann@1113
   753
    local tmp_dir
yann@1113
   754
yann@2592
   755
    # First try locally, then the mirror
yann@2592
   756
    if CT_GetFile "${basename}"; then
yann@2592
   757
        # Got it! Return early! :-)
yann@2592
   758
        return 0
yann@2592
   759
    fi
yann@1113
   760
yann@2595
   761
    if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
yann@2595
   762
        CT_DoLog WARN "Downloads forbidden, not trying cvs retrieval"
yann@2595
   763
        return 1
yann@2595
   764
    fi
yann@2595
   765
yann@1113
   766
    CT_MktempDir tmp_dir
yann@1113
   767
    CT_Pushd "${tmp_dir}"
yann@1113
   768
yann@1113
   769
    CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
yann@1592
   770
    if [ -n "${dirname}" ]; then
yann@1592
   771
        case "${dirname}" in
yann@1592
   772
            *=*)
yann@1593
   773
                CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
yann@1593
   774
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
yann@1592
   775
                ;;
yann@1592
   776
            *)
yann@1592
   777
                CT_DoExecLog ALL mv "${module}" "${dirname}"
yann@1592
   778
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
yann@1592
   779
                ;;
yann@1592
   780
        esac
yann@1592
   781
    fi
yann@1113
   782
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1113
   783
yann@1113
   784
    CT_Popd
yann@1113
   785
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1113
   786
}
yann@1113
   787
yann@1244
   788
# Check out from SVN, and build the associated tarball
yann@1244
   789
# The tarball will be called ${basename}.tar.bz2
yann@1244
   790
# Prerequisite: either the server does not require password,
yann@1244
   791
# or the user must already be logged in.
yann@1244
   792
# 'rev' is the revision to retrieve
yann@1244
   793
# Usage: CT_GetSVN <basename> <url> [rev]
yann@1244
   794
CT_GetSVN() {
yann@1244
   795
    local basename="$1"
yann@1244
   796
    local uri="$2"
yann@1244
   797
    local rev="$3"
yann@1244
   798
yann@2590
   799
    # First try locally, then the mirror
yann@2590
   800
    if CT_GetFile "${basename}"; then
yann@2590
   801
        # Got it! Return early! :-)
yann@2590
   802
        return 0
yann@2590
   803
    fi
yann@1244
   804
yann@2595
   805
    if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
yann@2595
   806
        CT_DoLog WARN "Downloads forbidden, not trying svn retrieval"
yann@2595
   807
        return 1
yann@2595
   808
    fi
yann@2595
   809
yann@1244
   810
    CT_MktempDir tmp_dir
yann@1244
   811
    CT_Pushd "${tmp_dir}"
yann@1244
   812
yann@2494
   813
    if ! CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"; then
yann@2494
   814
        CT_DoLog WARN "Could not retrieve '${basename}'"
yann@2494
   815
        return 1
yann@2494
   816
    fi
yann@1244
   817
    CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
yann@1244
   818
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1244
   819
yann@1244
   820
    CT_Popd
yann@1244
   821
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1244
   822
}
yann@1244
   823
yann@1763
   824
# Clone a git tree
yann@1763
   825
# Tries the given URLs in turn until one can get cloned. No tarball will be created.
yann@1763
   826
# Prerequisites: either the server does not require password,
yann@1763
   827
# or the user has already taken any action to authenticate to the server.
yann@1763
   828
# The cloned tree will *not* be stored in the local tarballs dir!
yann@1763
   829
# Usage: CT_GetGit <basename> <url [url ...]>
yann@1763
   830
CT_GetGit() {
yann@1763
   831
    local basename="$1"; shift
yann@1763
   832
    local url
yann@1763
   833
    local cloned=0
yann@1763
   834
yann@2595
   835
    if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
yann@2595
   836
        CT_DoLog WARN "Downloads forbidden, not trying git retrieval"
yann@2595
   837
        return 1
yann@2595
   838
    fi
yann@2595
   839
yann@1763
   840
    # Do we have it in our tarballs dir?
yann@1763
   841
    if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
yann@1763
   842
        CT_DoLog EXTRA "Updating git tree '${basename}'"
yann@1763
   843
        CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   844
        CT_DoExecLog ALL git pull
yann@1763
   845
        CT_Popd
yann@1763
   846
    else
yann@1763
   847
        CT_DoLog EXTRA "Retrieving git tree '${basename}'"
yann@1763
   848
        for url in "${@}"; do
yann@1763
   849
            CT_DoLog ALL "Trying to clone from '${url}'"
yann@1763
   850
            CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   851
            if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
yann@1763
   852
                cloned=1
yann@1763
   853
                break
yann@1763
   854
            fi
yann@1763
   855
        done
yann@1763
   856
        CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
yann@1763
   857
    fi
yann@1763
   858
}
yann@1763
   859
yann@1126
   860
# Extract a tarball
yann@63
   861
# Some tarballs need to be extracted in specific places. Eg.: glibc addons
yann@63
   862
# must be extracted in the glibc directory; uCLibc locales must be extracted
yann@1123
   863
# in the extra/locale sub-directory of uClibc. This is taken into account
yann@1123
   864
# by the caller, that did a 'cd' into the correct path before calling us
yann@1123
   865
# and sets nochdir to 'nochdir'.
yann@1763
   866
# Note also that this function handles the git trees!
martinwguy@3203
   867
# Usage: CT_Extract [nochdir] <basename> [options]
yann@1763
   868
# where 'options' are dependent on the source (eg. git branch/tag...)
yann@1126
   869
CT_Extract() {
yann@1761
   870
    local nochdir="$1"
yann@1761
   871
    local basename
yann@1690
   872
    local ext
yann@2646
   873
    local lzma_prog
yann@2605
   874
    local -a tar_opts
yann@1690
   875
yann@1761
   876
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
   877
        shift
yann@1761
   878
        nochdir="$(pwd)"
yann@1761
   879
    else
yann@1761
   880
        nochdir="${CT_SRC_DIR}"
yann@1761
   881
    fi
yann@1761
   882
yann@1761
   883
    basename="$1"
yann@1761
   884
    shift
yann@1761
   885
yann@1690
   886
    if ! ext="$(CT_GetFileExtension "${basename}")"; then
yann@2493
   887
        CT_DoLog WARN "'${basename}' not found in '${CT_TARBALLS_DIR}'"
yann@2493
   888
        return 1
yann@1690
   889
    fi
yann@1126
   890
    local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1126
   891
yann@1718
   892
    # Check if already extracted
yann@1718
   893
    if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
yann@1718
   894
        CT_DoLog DEBUG "Already extracted '${basename}'"
yann@1718
   895
        return 0
yann@1718
   896
    fi
yann@1718
   897
yann@1691
   898
    # Check if previously partially extracted
yann@1691
   899
    if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
yann@1691
   900
        CT_DoLog ERROR "The '${basename}' sources were partially extracted."
yann@1691
   901
        CT_DoLog ERROR "Please remove first:"
yann@1691
   902
        CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
yann@1691
   903
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
yann@1691
   904
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1691
   905
    fi
yann@1691
   906
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
yann@1691
   907
yann@1761
   908
    CT_Pushd "${nochdir}"
yann@63
   909
yann@1126
   910
    CT_DoLog EXTRA "Extracting '${basename}'"
benoit@2574
   911
    CT_DoExecLog FILE mkdir -p "${basename}"
yann@2605
   912
    tar_opts=( "--strip-components=1" )
yann@2605
   913
    tar_opts+=( "-C" "${basename}" )
yann@2605
   914
    tar_opts+=( "-xv" )
yann@2646
   915
yann@2646
   916
    # One note here:
yann@2646
   917
    # - lzma can be handled either with 'xz' or 'lzma'
yann@2646
   918
    # - we get lzma tarball only if either or both are available
yann@2646
   919
    # - so, if we get an lzma tarball, and either 'xz' or 'lzma' is
yann@2646
   920
    #   missing, we can assume the other is available
yann@2646
   921
    if [ "${CT_CONFIGURE_has_lzma}" = "y" ]; then
titus@2785
   922
        lzma_prog="lzma -fdc"
yann@2646
   923
    else
titus@2785
   924
        lzma_prog="xz -fdc"
yann@2646
   925
    fi
yann@63
   926
    case "${ext}" in
titus@2785
   927
        .tar.xz)      xz -fdc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
titus@2785
   928
        .tar.lzma)    ${lzma_prog} "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
titus@2785
   929
        .tar.bz2)     bzip2 -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
titus@2785
   930
        .tar.gz|.tgz) gzip -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
yann@2608
   931
        .tar)         CT_DoExecLog FILE tar "${tar_opts[@]}" -f "${full_file}";;
martinwguy@3203
   932
        .zip)         CT_DoExecLog FILE unzip "${@}" "${full_file}";;
yann@1763
   933
        /.git)        CT_ExtractGit "${basename}" "${@}";;
yann@2493
   934
        *)            CT_DoLog WARN "Don't know how to handle '${basename}${ext}': unknown extension"
yann@2493
   935
                      return 1
yann@2493
   936
                      ;;
yann@63
   937
    esac
yann@63
   938
yann@1763
   939
    # Don't mark as being extracted for git
yann@1763
   940
    case "${ext}" in
yann@1763
   941
        /.git)  ;;
yann@1763
   942
        *)      CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
yann@1763
   943
    esac
yann@1691
   944
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
yann@1126
   945
yann@1761
   946
    CT_Popd
yann@1126
   947
}
yann@1126
   948
esben@2721
   949
# Create a working git clone of a local git repository
yann@1763
   950
# Usage: CT_ExtractGit <basename> [ref]
yann@1763
   951
# where 'ref' is the reference to use:
yann@1763
   952
#   the full name of a branch, like "remotes/origin/branch_name"
yann@1763
   953
#   a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
yann@1763
   954
#   a tag name
esben@2721
   955
# If 'ref' is not given, the current repository HEAD will be used
yann@1763
   956
CT_ExtractGit() {
yann@1763
   957
    local basename="${1}"
yann@1763
   958
    local ref="${2}"
esben@2721
   959
    local repo
yann@1763
   960
    local ref_type
yann@1763
   961
yann@1763
   962
    # pushd now to be able to get git revlist in case ref is a date
esben@2721
   963
    repo="${CT_TARBALLS_DIR}/${basename}"
esben@2721
   964
    CT_Pushd "${repo}"
yann@1763
   965
yann@1763
   966
    # What kind of reference is ${ref} ?
yann@1763
   967
    if [ -z "${ref}" ]; then
esben@2721
   968
        ref_type=head
esben@2721
   969
        ref=$(git rev-list -n1 HEAD)
yann@1763
   970
    elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
yann@1763
   971
        ref_type=tag
yann@1763
   972
    elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
yann@1763
   973
        ref_type=branch
yann@1763
   974
    elif date -d "${ref}" >/dev/null 2>&1; then
yann@1763
   975
        ref_type=date
yann@1763
   976
        ref=$(git rev-list -n1 --before="${ref}")
yann@1763
   977
    else
yann@1763
   978
        CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
yann@1763
   979
    fi
yann@1763
   980
esben@2721
   981
    CT_Popd
yann@1763
   982
esben@2721
   983
    CT_DoExecLog FILE rmdir "${basename}"
yann@1763
   984
    case "${ref_type}" in
esben@2721
   985
        branch) CT_DoExecLog FILE git clone -b "${ref}" "${repo}" "${basename}" ;;
esben@2721
   986
        *)      CT_DoExecLog FILE git clone "${repo}" "${basename}"
esben@2721
   987
                CT_Pushd "${basename}"
esben@2721
   988
                CT_DoExecLog FILE git checkout "${ref}"
esben@2721
   989
                CT_Popd
esben@2721
   990
                ;;
yann@1763
   991
    esac
yann@1763
   992
}
yann@1763
   993
yann@1126
   994
# Patches the specified component
yann@1761
   995
# See CT_Extract, above, for explanations on 'nochdir'
yann@1901
   996
# Usage: CT_Patch [nochdir] <packagename> <packageversion>
yann@1901
   997
# If the package directory is *not* packagename-packageversion, then
yann@1901
   998
# the caller must cd into the proper directory first, and call us
yann@1901
   999
# with nochdir
yann@1126
  1000
CT_Patch() {
yann@1761
  1001
    local nochdir="$1"
yann@1901
  1002
    local pkgname
yann@1901
  1003
    local version
yann@1901
  1004
    local pkgdir
yann@1761
  1005
    local base_file
yann@1761
  1006
    local ver_file
yann@1507
  1007
    local d
yann@1507
  1008
    local -a patch_dirs
yann@1507
  1009
    local bundled_patch_dir
yann@1507
  1010
    local local_patch_dir
yann@1126
  1011
yann@1761
  1012
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
  1013
        shift
yann@1906
  1014
        pkgname="$1"
yann@1906
  1015
        version="$2"
yann@1906
  1016
        pkgdir="${pkgname}-${version}"
yann@1761
  1017
        nochdir="$(pwd)"
yann@1761
  1018
    else
yann@1906
  1019
        pkgname="$1"
yann@1906
  1020
        version="$2"
yann@1906
  1021
        pkgdir="${pkgname}-${version}"
yann@1901
  1022
        nochdir="${CT_SRC_DIR}/${pkgdir}"
yann@1761
  1023
    fi
yann@1761
  1024
yann@1126
  1025
    # Check if already patched
yann@1901
  1026
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
yann@1901
  1027
        CT_DoLog DEBUG "Already patched '${pkgdir}'"
yann@1126
  1028
        return 0
yann@63
  1029
    fi
yann@63
  1030
yann@1271
  1031
    # Check if already partially patched
yann@1901
  1032
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
yann@1901
  1033
        CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
yann@1271
  1034
        CT_DoLog ERROR "Please remove first:"
yann@1901
  1035
        CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
yann@1901
  1036
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
yann@1901
  1037
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
yann@1271
  1038
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1271
  1039
    fi
yann@1901
  1040
    touch "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1271
  1041
yann@1761
  1042
    CT_Pushd "${nochdir}"
yann@1123
  1043
yann@1901
  1044
    CT_DoLog EXTRA "Patching '${pkgdir}'"
yann@63
  1045
yann@1901
  1046
    bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
yann@1901
  1047
    local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
yann@1507
  1048
yann@1507
  1049
    case "${CT_PATCH_ORDER}" in
yann@1507
  1050
        bundled)        patch_dirs=("${bundled_patch_dir}");;
yann@1507
  1051
        local)          patch_dirs=("${local_patch_dir}");;
yann@1507
  1052
        bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
yann@1508
  1053
        local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
yann@1630
  1054
        none)           patch_dirs=;;
yann@1507
  1055
    esac
yann@1507
  1056
yann@1507
  1057
    for d in "${patch_dirs[@]}"; do
yann@1507
  1058
        CT_DoLog DEBUG "Looking for patches in '${d}'..."
yann@1507
  1059
        if [ -n "${d}" -a -d "${d}" ]; then
yann@1507
  1060
            for p in "${d}"/*.patch; do
yann@63
  1061
                if [ -f "${p}" ]; then
js@3096
  1062
                    CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f -i "${p}"
yann@63
  1063
                fi
yann@63
  1064
            done
yann@1509
  1065
            if [ "${CT_PATCH_SINGLE}" = "y" ]; then
yann@1509
  1066
                break
yann@1509
  1067
            fi
yann@63
  1068
        fi
yann@63
  1069
    done
yann@63
  1070
yann@508
  1071
    if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
yann@508
  1072
        CT_DoLog ALL "Overiding config.guess and config.sub"
yann@508
  1073
        for cfg in config_guess config_sub; do
yann@1101
  1074
            eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
yann@1101
  1075
            [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
yann@776
  1076
            # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
yann@508
  1077
            find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
yann@508
  1078
        done
yann@508
  1079
    fi
yann@508
  1080
yann@1903
  1081
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
yann@1903
  1082
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1126
  1083
yann@1761
  1084
    CT_Popd
yann@63
  1085
}
yann@63
  1086
yann@182
  1087
# Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
yann@182
  1088
# Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
yann@182
  1089
CT_DoConfigGuess() {
yann@1101
  1090
    if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
yann@1101
  1091
        "${CT_TOP_DIR}/scripts/config.guess"
yann@182
  1092
    else
yann@1101
  1093
        "${CT_LIB_DIR}/scripts/config.guess"
yann@182
  1094
    fi
yann@182
  1095
}
yann@182
  1096
yann@182
  1097
CT_DoConfigSub() {
yann@1101
  1098
    if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
yann@1101
  1099
        "${CT_TOP_DIR}/scripts/config.sub" "$@"
yann@182
  1100
    else
yann@1101
  1101
        "${CT_LIB_DIR}/scripts/config.sub" "$@"
yann@182
  1102
    fi
yann@182
  1103
}
yann@182
  1104
yann@335
  1105
# Compute the target tuple from what is provided by the user
yann@335
  1106
# Usage: CT_DoBuildTargetTuple
yann@63
  1107
# In fact this function takes the environment variables to build the target
yann@335
  1108
# tuple. It is needed both by the normal build sequence, as well as the
yann@63
  1109
# sample saving sequence.
yann@335
  1110
CT_DoBuildTargetTuple() {
yann@383
  1111
    # Set the endianness suffix, and the default endianness gcc option
yann@2773
  1112
    case "${CT_ARCH_ENDIAN}" in
yann@2773
  1113
        big)
yann@2773
  1114
            target_endian_eb=eb
yann@383
  1115
            target_endian_el=
yann@391
  1116
            CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
yann@2967
  1117
            CT_ARCH_ENDIAN_LDFLAG="-Wl,-EB"
yann@383
  1118
            ;;
yann@2773
  1119
        little)
yann@2773
  1120
            target_endian_eb=
yann@383
  1121
            target_endian_el=el
yann@391
  1122
            CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
yann@2967
  1123
            CT_ARCH_ENDIAN_LDFLAG="-Wl,-EL"
yann@383
  1124
            ;;
yann@63
  1125
    esac
yann@383
  1126
yann@965
  1127
    # Build the default architecture tuple part
w@3169
  1128
    CT_TARGET_ARCH="${CT_ARCH}${CT_ARCH_SUFFIX}"
yann@965
  1129
yann@383
  1130
    # Set defaults for the system part of the tuple. Can be overriden
yann@383
  1131
    # by architecture-specific values.
yann@383
  1132
    case "${CT_LIBC}" in
yann@787
  1133
        *glibc) CT_TARGET_SYS=gnu;;
yann@383
  1134
        uClibc) CT_TARGET_SYS=uclibc;;
yann@1591
  1135
        *)      CT_TARGET_SYS=elf;;
yann@63
  1136
    esac
yann@383
  1137
yann@391
  1138
    # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
yann@497
  1139
    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
  1140
    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
  1141
    [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
yann@391
  1142
    [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
yann@391
  1143
    [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
yann@405
  1144
    [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
yann@391
  1145
    [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
michael@2737
  1146
michael@2737
  1147
    case "${CT_ARCH_FLOAT}" in
michael@2738
  1148
        hard)
michael@2738
  1149
            CT_ARCH_FLOAT_CFLAG="-mhard-float"
michael@2738
  1150
            CT_ARCH_WITH_FLOAT="--with-float=hard"
michael@2738
  1151
            ;;
michael@2737
  1152
        soft)
michael@2737
  1153
            CT_ARCH_FLOAT_CFLAG="-msoft-float"
michael@2737
  1154
            CT_ARCH_WITH_FLOAT="--with-float=soft"
michael@2737
  1155
            ;;
michael@2739
  1156
        softfp)
michael@2739
  1157
            CT_ARCH_FLOAT_CFLAG="-mfloat-abi=softfp"
michael@2739
  1158
            CT_ARCH_WITH_FLOAT="--with-float=softfp"
michael@2739
  1159
            ;;
michael@2737
  1160
    esac
yann@391
  1161
yann@965
  1162
    # Build the default kernel tuple part
yann@965
  1163
    CT_TARGET_KERNEL="${CT_KERNEL}"
yann@964
  1164
yann@965
  1165
    # Overide the default values with the components specific settings
yann@964
  1166
    CT_DoArchTupleValues
yann@965
  1167
    CT_DoKernelTupleValues
yann@383
  1168
yann@391
  1169
    # Finish the target tuple construction
bartvdrmeulen@1896
  1170
    CT_TARGET="${CT_TARGET_ARCH}"
bartvdrmeulen@1896
  1171
    CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
bartvdrmeulen@1896
  1172
    CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
bartvdrmeulen@1896
  1173
    CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
yann@1094
  1174
yann@1094
  1175
    # Sanity checks
yann@1094
  1176
    __sed_alias=""
yann@1094
  1177
    if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
yann@1094
  1178
        __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
yann@1094
  1179
    fi
yann@1094
  1180
    case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
yann@1094
  1181
      :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
yann@1094
  1182
      :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
yann@1094
  1183
      :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
yann@1094
  1184
      :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
yann@1094
  1185
    esac
yann@1094
  1186
yann@1094
  1187
    # Canonicalise it
yann@1094
  1188
    CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
yann@391
  1189
    # Prepare the target CFLAGS
yann@767
  1190
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
yann@527
  1191
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
yann@397
  1192
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
yann@397
  1193
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
yann@397
  1194
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
yann@397
  1195
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
yann@397
  1196
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
yann@527
  1197
yann@527
  1198
    # Now on for the target LDFLAGS
yann@767
  1199
    CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
yann@63
  1200
}
yann@121
  1201
yann@121
  1202
# This function does pause the build until the user strikes "Return"
yann@121
  1203
# Usage: CT_DoPause [optional_message]
yann@121
  1204
CT_DoPause() {
yann@121
  1205
    local foo
yann@121
  1206
    local message="${1:-Pausing for your pleasure}"
yann@121
  1207
    CT_DoLog INFO "${message}"
yann@523
  1208
    read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
yann@121
  1209
    return 0
yann@121
  1210
}
yann@121
  1211
yann@1907
  1212
# This function creates a tarball of the specified directory, but
yann@1907
  1213
# only if it exists
yann@1907
  1214
# Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
yann@1907
  1215
CT_DoTarballIfExists() {
yann@1907
  1216
    local dir="$1"
yann@1907
  1217
    local tarball="$2"
yann@1907
  1218
    shift 2
yann@1907
  1219
    local -a extra_tar_opts=( "$@" )
yann@1908
  1220
    local -a compress
yann@1907
  1221
yann@1907
  1222
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
  1223
        y)  compress=( gzip -c -3 - ); tar_ext=.gz;;
yann@1908
  1224
        *)  compress=( cat - );        tar_ext=;;
yann@1907
  1225
    esac
yann@1907
  1226
yann@1907
  1227
    if [ -d "${dir}" ]; then
yann@1907
  1228
        CT_DoLog DEBUG "  Saving '${dir}'"
yann@1908
  1229
        { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" .    \
yann@1908
  1230
          |"${compress[@]}" >"${tarball}.tar${tar_ext}"         ;
anthony@2155
  1231
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
  1232
    else
anthony@2155
  1233
        CT_DoLog STATE "  Not saving '${dir}': does not exist"
yann@1907
  1234
    fi
yann@1907
  1235
}
yann@1907
  1236
yann@1907
  1237
# This function extracts a tarball to the specified directory, but
yann@1907
  1238
# only if the tarball exists
anthony@2155
  1239
# Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
yann@1907
  1240
CT_DoExtractTarballIfExists() {
yann@1907
  1241
    local tarball="$1"
yann@1907
  1242
    local dir="$2"
yann@1907
  1243
    shift 2
yann@1907
  1244
    local -a extra_tar_opts=( "$@" )
yann@1908
  1245
    local -a uncompress
yann@1907
  1246
yann@1907
  1247
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
  1248
        y)  uncompress=( gzip -c -d ); tar_ext=.gz;;
yann@1908
  1249
        *)  uncompress=( cat );        tar_ext=;;
yann@1907
  1250
    esac
yann@1907
  1251
yann@1907
  1252
    if [ -f "${tarball}.tar${tar_ext}" ]; then
yann@1907
  1253
        CT_DoLog DEBUG "  Restoring '${dir}'"
yann@1907
  1254
        CT_DoForceRmdir "${dir}"
yann@1907
  1255
        CT_DoExecLog DEBUG mkdir -p "${dir}"
yann@1908
  1256
        { "${uncompress[@]}" "${tarball}.tar${tar_ext}"     \
yann@1908
  1257
          |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
anthony@2155
  1258
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
  1259
    else
anthony@2155
  1260
        CT_DoLog STATE "  Not restoring '${dir}': does not exist"
yann@1907
  1261
    fi
yann@1907
  1262
}
yann@1907
  1263
yann@121
  1264
# This function saves the state of the toolchain to be able to restart
yann@121
  1265
# at any one point
yann@121
  1266
# Usage: CT_DoSaveState <next_step_name>
yann@121
  1267
CT_DoSaveState() {
yann@121
  1268
	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
yann@121
  1269
    local state_name="$1"
yann@121
  1270
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@121
  1271
yann@1266
  1272
    # Log this to the log level required by the user
yann@1266
  1273
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
yann@1134
  1274
yann@121
  1275
    rm -rf "${state_dir}"
yann@121
  1276
    mkdir -p "${state_dir}"
yann@121
  1277
anthony@2155
  1278
    CT_DoLog STATE "  Saving environment and aliases"
yann@738
  1279
    # We must omit shell functions, and some specific bash variables
yann@738
  1280
    # that break when restoring the environment, later. We could do
yann@1299
  1281
    # all the processing in the awk script, but a sed is easier...
yann@1299
  1282
    set |awk '
yann@1017
  1283
              BEGIN { _p = 1; }
yann@1017
  1284
              $0~/^[^ ]+ \(\)/ { _p = 0; }
yann@1017
  1285
              _p == 1
yann@1017
  1286
              $0 == "}" { _p = 1; }
yann@1017
  1287
              ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
yann@738
  1288
                           /^(UID|EUID)=/d;
yann@738
  1289
                           /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
yann@121
  1290
yann@2308
  1291
    CT_DoTarballIfExists "${CT_BUILDTOOLS_PREFIX_DIR}" "${state_dir}/buildtools_dir"
yann@1907
  1292
    CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
yann@1907
  1293
    CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
yann@121
  1294
yann@2339
  1295
    CT_DoLog STATE "  Saving log file"
yann@2339
  1296
    exec >/dev/null
yann@2339
  1297
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@2339
  1298
        y)  gzip -3 -c "${tmp_log_file}"  >"${state_dir}/log.gz";;
yann@2339
  1299
        *)  cat "${tmp_log_file}" >"${state_dir}/log";;
yann@2339
  1300
    esac
yann@2339
  1301
    exec >>"${tmp_log_file}"
yann@121
  1302
}
yann@121
  1303
yann@136
  1304
# This function restores a previously saved state
yann@121
  1305
# Usage: CT_DoLoadState <state_name>
yann@121
  1306
CT_DoLoadState(){
yann@121
  1307
    local state_name="$1"
yann@121
  1308
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@135
  1309
    local old_RESTART="${CT_RESTART}"
yann@135
  1310
    local old_STOP="${CT_STOP}"
yann@121
  1311
yann@523
  1312
    CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
yann@141
  1313
yann@121
  1314
    # We need to do something special with the log file!
yann@121
  1315
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
  1316
        exec >"${state_dir}/tail.log"
yann@121
  1317
    fi
yann@1266
  1318
yann@1266
  1319
    # Log this to the log level required by the user
yann@1266
  1320
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
yann@121
  1321
yann@1907
  1322
    CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
yann@1907
  1323
    CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
yann@2308
  1324
    CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_PREFIX_DIR}"
yann@1894
  1325
yann@121
  1326
    # Restore the environment, discarding any error message
yann@121
  1327
    # (for example, read-only bash internals)
anthony@2155
  1328
    CT_DoLog STATE "  Restoring environment"
yann@121
  1329
    . "${state_dir}/env.sh" >/dev/null 2>&1 || true
yann@121
  1330
yann@135
  1331
    # Restore the new RESTART and STOP steps
yann@135
  1332
    CT_RESTART="${old_RESTART}"
yann@135
  1333
    CT_STOP="${old_STOP}"
yann@135
  1334
    unset old_stop old_restart
yann@135
  1335
yann@2339
  1336
    CT_DoLog STATE "  Restoring log file"
yann@2339
  1337
    exec >/dev/null
yann@2339
  1338
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@2339
  1339
        y)  zcat "${state_dir}/log.gz" >"${tmp_log_file}";;
yann@2339
  1340
        *)  cat "${state_dir}/log" >"${tmp_log_file}";;
yann@2339
  1341
    esac
yann@2339
  1342
    cat "${state_dir}/tail.log" >>"${tmp_log_file}"
yann@2339
  1343
    exec >>"${tmp_log_file}"
yann@2339
  1344
    rm -f "${state_dir}/tail.log"
yann@121
  1345
}