scripts/functions
author Cody Schafer <dev@codyps.com>
Fri May 09 19:13:49 2014 -0700 (2014-05-09)
changeset 3312 4876ff97e039
parent 3307 d7eaba5831d5
child 3314 f3f518cafd8a
permissions -rw-r--r--
cc/gcc: allow CC_EXTRA_CONFIG_ARRAY on baremetal

The final bare-metal compiler is built using the core backend.
Currently the core uses the CC_CORE_EXTRA_CONFIG_ARRAY variable.

While this works as supposed to, this can leave the user puzzled
in the menuconfig, since all he can see is the core options, not
the final options.

Only show the core options if any of the core passes are needed,
and use the final options in the core-backend if we're issuing
the bare-metal compiler.

Signed-off-by: Cody P Schafer <dev@codyps.com>
[yann.morin.1998@free.fr: hide core options if no core pass needed;
use final option in core backend if issuing the bare-metal compiler]
Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
Message-Id: <22181e546ba746202489.1399688067@localhost>
Patchwork-Id: 347586
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@1763
   833
# Usage: CT_GetGit <basename> <url [url ...]>
yann@1763
   834
CT_GetGit() {
yann@1763
   835
    local basename="$1"; shift
yann@1763
   836
    local url
yann@1763
   837
    local cloned=0
yann@1763
   838
yann@2595
   839
    if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
yann@2595
   840
        CT_DoLog WARN "Downloads forbidden, not trying git retrieval"
yann@2595
   841
        return 1
yann@2595
   842
    fi
yann@2595
   843
yann@1763
   844
    # Do we have it in our tarballs dir?
yann@1763
   845
    if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
yann@1763
   846
        CT_DoLog EXTRA "Updating git tree '${basename}'"
yann@1763
   847
        CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   848
        CT_DoExecLog ALL git pull
yann@1763
   849
        CT_Popd
yann@1763
   850
    else
yann@1763
   851
        CT_DoLog EXTRA "Retrieving git tree '${basename}'"
yann@1763
   852
        for url in "${@}"; do
yann@1763
   853
            CT_DoLog ALL "Trying to clone from '${url}'"
yann@1763
   854
            CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   855
            if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
yann@1763
   856
                cloned=1
yann@1763
   857
                break
yann@1763
   858
            fi
yann@1763
   859
        done
yann@1763
   860
        CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
yann@1763
   861
    fi
yann@1763
   862
}
yann@1763
   863
yann@1126
   864
# Extract a tarball
yann@63
   865
# Some tarballs need to be extracted in specific places. Eg.: glibc addons
yann@63
   866
# must be extracted in the glibc directory; uCLibc locales must be extracted
yann@1123
   867
# in the extra/locale sub-directory of uClibc. This is taken into account
yann@1123
   868
# by the caller, that did a 'cd' into the correct path before calling us
yann@1123
   869
# and sets nochdir to 'nochdir'.
yann@1763
   870
# Note also that this function handles the git trees!
martinwguy@3203
   871
# Usage: CT_Extract [nochdir] <basename> [options]
yann@1763
   872
# where 'options' are dependent on the source (eg. git branch/tag...)
yann@1126
   873
CT_Extract() {
yann@1761
   874
    local nochdir="$1"
yann@1761
   875
    local basename
yann@1690
   876
    local ext
yann@2646
   877
    local lzma_prog
yann@2605
   878
    local -a tar_opts
yann@1690
   879
yann@1761
   880
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
   881
        shift
yann@1761
   882
        nochdir="$(pwd)"
yann@1761
   883
    else
yann@1761
   884
        nochdir="${CT_SRC_DIR}"
yann@1761
   885
    fi
yann@1761
   886
yann@1761
   887
    basename="$1"
yann@1761
   888
    shift
yann@1761
   889
yann@1690
   890
    if ! ext="$(CT_GetFileExtension "${basename}")"; then
yann@2493
   891
        CT_DoLog WARN "'${basename}' not found in '${CT_TARBALLS_DIR}'"
yann@2493
   892
        return 1
yann@1690
   893
    fi
yann@1126
   894
    local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1126
   895
yann@1718
   896
    # Check if already extracted
yann@1718
   897
    if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
yann@1718
   898
        CT_DoLog DEBUG "Already extracted '${basename}'"
yann@1718
   899
        return 0
yann@1718
   900
    fi
yann@1718
   901
yann@1691
   902
    # Check if previously partially extracted
yann@1691
   903
    if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
yann@1691
   904
        CT_DoLog ERROR "The '${basename}' sources were partially extracted."
yann@1691
   905
        CT_DoLog ERROR "Please remove first:"
yann@1691
   906
        CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
yann@1691
   907
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
yann@1691
   908
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1691
   909
    fi
yann@1691
   910
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
yann@1691
   911
yann@1761
   912
    CT_Pushd "${nochdir}"
yann@63
   913
yann@1126
   914
    CT_DoLog EXTRA "Extracting '${basename}'"
benoit@2574
   915
    CT_DoExecLog FILE mkdir -p "${basename}"
yann@2605
   916
    tar_opts=( "--strip-components=1" )
yann@2605
   917
    tar_opts+=( "-C" "${basename}" )
yann@2605
   918
    tar_opts+=( "-xv" )
yann@2646
   919
yann@2646
   920
    # One note here:
yann@2646
   921
    # - lzma can be handled either with 'xz' or 'lzma'
yann@2646
   922
    # - we get lzma tarball only if either or both are available
yann@2646
   923
    # - so, if we get an lzma tarball, and either 'xz' or 'lzma' is
yann@2646
   924
    #   missing, we can assume the other is available
yann@2646
   925
    if [ "${CT_CONFIGURE_has_lzma}" = "y" ]; then
titus@2785
   926
        lzma_prog="lzma -fdc"
yann@2646
   927
    else
titus@2785
   928
        lzma_prog="xz -fdc"
yann@2646
   929
    fi
yann@63
   930
    case "${ext}" in
titus@2785
   931
        .tar.xz)      xz -fdc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
titus@2785
   932
        .tar.lzma)    ${lzma_prog} "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
titus@2785
   933
        .tar.bz2)     bzip2 -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
titus@2785
   934
        .tar.gz|.tgz) gzip -dc "${full_file}" | CT_DoExecLog FILE tar "${tar_opts[@]}" -f -;;
yann@2608
   935
        .tar)         CT_DoExecLog FILE tar "${tar_opts[@]}" -f "${full_file}";;
martinwguy@3203
   936
        .zip)         CT_DoExecLog FILE unzip "${@}" "${full_file}";;
yann@1763
   937
        /.git)        CT_ExtractGit "${basename}" "${@}";;
yann@2493
   938
        *)            CT_DoLog WARN "Don't know how to handle '${basename}${ext}': unknown extension"
yann@2493
   939
                      return 1
yann@2493
   940
                      ;;
yann@63
   941
    esac
yann@63
   942
yann@1763
   943
    # Don't mark as being extracted for git
yann@1763
   944
    case "${ext}" in
yann@1763
   945
        /.git)  ;;
yann@1763
   946
        *)      CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
yann@1763
   947
    esac
yann@1691
   948
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
yann@1126
   949
yann@1761
   950
    CT_Popd
yann@1126
   951
}
yann@1126
   952
esben@2721
   953
# Create a working git clone of a local git repository
yann@1763
   954
# Usage: CT_ExtractGit <basename> [ref]
yann@1763
   955
# where 'ref' is the reference to use:
yann@1763
   956
#   the full name of a branch, like "remotes/origin/branch_name"
yann@1763
   957
#   a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
yann@1763
   958
#   a tag name
esben@2721
   959
# If 'ref' is not given, the current repository HEAD will be used
yann@1763
   960
CT_ExtractGit() {
yann@1763
   961
    local basename="${1}"
yann@1763
   962
    local ref="${2}"
esben@2721
   963
    local repo
yann@1763
   964
    local ref_type
yann@1763
   965
yann@1763
   966
    # pushd now to be able to get git revlist in case ref is a date
esben@2721
   967
    repo="${CT_TARBALLS_DIR}/${basename}"
esben@2721
   968
    CT_Pushd "${repo}"
yann@1763
   969
yann@1763
   970
    # What kind of reference is ${ref} ?
yann@1763
   971
    if [ -z "${ref}" ]; then
esben@2721
   972
        ref_type=head
esben@2721
   973
        ref=$(git rev-list -n1 HEAD)
yann@1763
   974
    elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
yann@1763
   975
        ref_type=tag
yann@1763
   976
    elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
yann@1763
   977
        ref_type=branch
yann@1763
   978
    elif date -d "${ref}" >/dev/null 2>&1; then
yann@1763
   979
        ref_type=date
yann@1763
   980
        ref=$(git rev-list -n1 --before="${ref}")
yann@1763
   981
    else
yann@1763
   982
        CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
yann@1763
   983
    fi
yann@1763
   984
esben@2721
   985
    CT_Popd
yann@1763
   986
esben@2721
   987
    CT_DoExecLog FILE rmdir "${basename}"
yann@1763
   988
    case "${ref_type}" in
esben@2721
   989
        branch) CT_DoExecLog FILE git clone -b "${ref}" "${repo}" "${basename}" ;;
esben@2721
   990
        *)      CT_DoExecLog FILE git clone "${repo}" "${basename}"
esben@2721
   991
                CT_Pushd "${basename}"
esben@2721
   992
                CT_DoExecLog FILE git checkout "${ref}"
esben@2721
   993
                CT_Popd
esben@2721
   994
                ;;
yann@1763
   995
    esac
yann@1763
   996
}
yann@1763
   997
yann@1126
   998
# Patches the specified component
yann@1761
   999
# See CT_Extract, above, for explanations on 'nochdir'
yann@1901
  1000
# Usage: CT_Patch [nochdir] <packagename> <packageversion>
yann@1901
  1001
# If the package directory is *not* packagename-packageversion, then
yann@1901
  1002
# the caller must cd into the proper directory first, and call us
yann@1901
  1003
# with nochdir
yann@1126
  1004
CT_Patch() {
yann@1761
  1005
    local nochdir="$1"
yann@1901
  1006
    local pkgname
yann@1901
  1007
    local version
yann@1901
  1008
    local pkgdir
yann@1761
  1009
    local base_file
yann@1761
  1010
    local ver_file
yann@1507
  1011
    local d
yann@1507
  1012
    local -a patch_dirs
yann@1507
  1013
    local bundled_patch_dir
yann@1507
  1014
    local local_patch_dir
yann@1126
  1015
yann@1761
  1016
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
  1017
        shift
yann@1906
  1018
        pkgname="$1"
yann@1906
  1019
        version="$2"
yann@1906
  1020
        pkgdir="${pkgname}-${version}"
yann@1761
  1021
        nochdir="$(pwd)"
yann@1761
  1022
    else
yann@1906
  1023
        pkgname="$1"
yann@1906
  1024
        version="$2"
yann@1906
  1025
        pkgdir="${pkgname}-${version}"
yann@1901
  1026
        nochdir="${CT_SRC_DIR}/${pkgdir}"
yann@1761
  1027
    fi
yann@1761
  1028
yann@1126
  1029
    # Check if already patched
yann@1901
  1030
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
yann@1901
  1031
        CT_DoLog DEBUG "Already patched '${pkgdir}'"
yann@1126
  1032
        return 0
yann@63
  1033
    fi
yann@63
  1034
yann@1271
  1035
    # Check if already partially patched
yann@1901
  1036
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
yann@1901
  1037
        CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
yann@1271
  1038
        CT_DoLog ERROR "Please remove first:"
yann@1901
  1039
        CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
yann@1901
  1040
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
yann@1901
  1041
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
yann@1271
  1042
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1271
  1043
    fi
yann@1901
  1044
    touch "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1271
  1045
yann@1761
  1046
    CT_Pushd "${nochdir}"
yann@1123
  1047
yann@1901
  1048
    CT_DoLog EXTRA "Patching '${pkgdir}'"
yann@63
  1049
yann@1901
  1050
    bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
yann@1901
  1051
    local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
yann@1507
  1052
yann@1507
  1053
    case "${CT_PATCH_ORDER}" in
yann@1507
  1054
        bundled)        patch_dirs=("${bundled_patch_dir}");;
yann@1507
  1055
        local)          patch_dirs=("${local_patch_dir}");;
yann@1507
  1056
        bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
yann@1508
  1057
        local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
yann@1630
  1058
        none)           patch_dirs=;;
yann@1507
  1059
    esac
yann@1507
  1060
yann@1507
  1061
    for d in "${patch_dirs[@]}"; do
yann@1507
  1062
        CT_DoLog DEBUG "Looking for patches in '${d}'..."
yann@1507
  1063
        if [ -n "${d}" -a -d "${d}" ]; then
yann@1507
  1064
            for p in "${d}"/*.patch; do
yann@63
  1065
                if [ -f "${p}" ]; then
js@3096
  1066
                    CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f -i "${p}"
yann@63
  1067
                fi
yann@63
  1068
            done
yann@1509
  1069
            if [ "${CT_PATCH_SINGLE}" = "y" ]; then
yann@1509
  1070
                break
yann@1509
  1071
            fi
yann@63
  1072
        fi
yann@63
  1073
    done
yann@63
  1074
yann@508
  1075
    if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
yann@508
  1076
        CT_DoLog ALL "Overiding config.guess and config.sub"
yann@508
  1077
        for cfg in config_guess config_sub; do
yann@1101
  1078
            eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
yann@1101
  1079
            [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
yann@776
  1080
            # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
yann@508
  1081
            find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
yann@508
  1082
        done
yann@508
  1083
    fi
yann@508
  1084
yann@1903
  1085
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
yann@1903
  1086
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1126
  1087
yann@1761
  1088
    CT_Popd
yann@63
  1089
}
yann@63
  1090
yann@182
  1091
# Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
yann@182
  1092
# Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
yann@182
  1093
CT_DoConfigGuess() {
yann@1101
  1094
    if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
yann@1101
  1095
        "${CT_TOP_DIR}/scripts/config.guess"
yann@182
  1096
    else
yann@1101
  1097
        "${CT_LIB_DIR}/scripts/config.guess"
yann@182
  1098
    fi
yann@182
  1099
}
yann@182
  1100
yann@182
  1101
CT_DoConfigSub() {
yann@1101
  1102
    if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
yann@1101
  1103
        "${CT_TOP_DIR}/scripts/config.sub" "$@"
yann@182
  1104
    else
yann@1101
  1105
        "${CT_LIB_DIR}/scripts/config.sub" "$@"
yann@182
  1106
    fi
yann@182
  1107
}
yann@182
  1108
yann@335
  1109
# Compute the target tuple from what is provided by the user
yann@335
  1110
# Usage: CT_DoBuildTargetTuple
yann@63
  1111
# In fact this function takes the environment variables to build the target
yann@335
  1112
# tuple. It is needed both by the normal build sequence, as well as the
yann@63
  1113
# sample saving sequence.
yann@335
  1114
CT_DoBuildTargetTuple() {
yann@383
  1115
    # Set the endianness suffix, and the default endianness gcc option
yann@2773
  1116
    case "${CT_ARCH_ENDIAN}" in
yann@2773
  1117
        big)
yann@2773
  1118
            target_endian_eb=eb
yann@383
  1119
            target_endian_el=
yann@391
  1120
            CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
yann@2967
  1121
            CT_ARCH_ENDIAN_LDFLAG="-Wl,-EB"
yann@383
  1122
            ;;
yann@2773
  1123
        little)
yann@2773
  1124
            target_endian_eb=
yann@383
  1125
            target_endian_el=el
yann@391
  1126
            CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
yann@2967
  1127
            CT_ARCH_ENDIAN_LDFLAG="-Wl,-EL"
yann@383
  1128
            ;;
yann@63
  1129
    esac
yann@383
  1130
yann@965
  1131
    # Build the default architecture tuple part
w@3169
  1132
    CT_TARGET_ARCH="${CT_ARCH}${CT_ARCH_SUFFIX}"
yann@965
  1133
yann@383
  1134
    # Set defaults for the system part of the tuple. Can be overriden
yann@383
  1135
    # by architecture-specific values.
yann@383
  1136
    case "${CT_LIBC}" in
yann@787
  1137
        *glibc) CT_TARGET_SYS=gnu;;
yann@383
  1138
        uClibc) CT_TARGET_SYS=uclibc;;
yann@1591
  1139
        *)      CT_TARGET_SYS=elf;;
yann@63
  1140
    esac
yann@383
  1141
yann@391
  1142
    # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
yann@497
  1143
    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
  1144
    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
  1145
    [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
yann@391
  1146
    [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
yann@391
  1147
    [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
yann@405
  1148
    [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
yann@391
  1149
    [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
michael@2737
  1150
michael@2737
  1151
    case "${CT_ARCH_FLOAT}" in
michael@2738
  1152
        hard)
michael@2738
  1153
            CT_ARCH_FLOAT_CFLAG="-mhard-float"
michael@2738
  1154
            CT_ARCH_WITH_FLOAT="--with-float=hard"
michael@2738
  1155
            ;;
michael@2737
  1156
        soft)
michael@2737
  1157
            CT_ARCH_FLOAT_CFLAG="-msoft-float"
michael@2737
  1158
            CT_ARCH_WITH_FLOAT="--with-float=soft"
michael@2737
  1159
            ;;
michael@2739
  1160
        softfp)
michael@2739
  1161
            CT_ARCH_FLOAT_CFLAG="-mfloat-abi=softfp"
michael@2739
  1162
            CT_ARCH_WITH_FLOAT="--with-float=softfp"
michael@2739
  1163
            ;;
michael@2737
  1164
    esac
yann@391
  1165
yann@965
  1166
    # Build the default kernel tuple part
yann@965
  1167
    CT_TARGET_KERNEL="${CT_KERNEL}"
yann@964
  1168
yann@965
  1169
    # Overide the default values with the components specific settings
yann@964
  1170
    CT_DoArchTupleValues
yann@965
  1171
    CT_DoKernelTupleValues
yann@383
  1172
yann@391
  1173
    # Finish the target tuple construction
bartvdrmeulen@1896
  1174
    CT_TARGET="${CT_TARGET_ARCH}"
bartvdrmeulen@1896
  1175
    CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
bartvdrmeulen@1896
  1176
    CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
bartvdrmeulen@1896
  1177
    CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
yann@1094
  1178
yann@1094
  1179
    # Sanity checks
yann@1094
  1180
    __sed_alias=""
yann@1094
  1181
    if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
yann@1094
  1182
        __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
yann@1094
  1183
    fi
yann@1094
  1184
    case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
yann@1094
  1185
      :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
yann@1094
  1186
      :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
yann@1094
  1187
      :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
yann@1094
  1188
      :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
yann@1094
  1189
    esac
yann@1094
  1190
yann@1094
  1191
    # Canonicalise it
yann@1094
  1192
    CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
yann@391
  1193
    # Prepare the target CFLAGS
yann@767
  1194
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
yann@527
  1195
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
yann@397
  1196
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
yann@397
  1197
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
yann@397
  1198
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
yann@397
  1199
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
yann@397
  1200
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
yann@527
  1201
yann@527
  1202
    # Now on for the target LDFLAGS
yann@767
  1203
    CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
yann@63
  1204
}
yann@121
  1205
yann@121
  1206
# This function does pause the build until the user strikes "Return"
yann@121
  1207
# Usage: CT_DoPause [optional_message]
yann@121
  1208
CT_DoPause() {
yann@121
  1209
    local foo
yann@121
  1210
    local message="${1:-Pausing for your pleasure}"
yann@121
  1211
    CT_DoLog INFO "${message}"
yann@523
  1212
    read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
yann@121
  1213
    return 0
yann@121
  1214
}
yann@121
  1215
yann@1907
  1216
# This function creates a tarball of the specified directory, but
yann@1907
  1217
# only if it exists
yann@1907
  1218
# Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
yann@1907
  1219
CT_DoTarballIfExists() {
yann@1907
  1220
    local dir="$1"
yann@1907
  1221
    local tarball="$2"
yann@1907
  1222
    shift 2
yann@1907
  1223
    local -a extra_tar_opts=( "$@" )
yann@1908
  1224
    local -a compress
yann@1907
  1225
yann@1907
  1226
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
  1227
        y)  compress=( gzip -c -3 - ); tar_ext=.gz;;
yann@1908
  1228
        *)  compress=( cat - );        tar_ext=;;
yann@1907
  1229
    esac
yann@1907
  1230
yann@1907
  1231
    if [ -d "${dir}" ]; then
yann@1907
  1232
        CT_DoLog DEBUG "  Saving '${dir}'"
yann@1908
  1233
        { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" .    \
yann@1908
  1234
          |"${compress[@]}" >"${tarball}.tar${tar_ext}"         ;
anthony@2155
  1235
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
  1236
    else
anthony@2155
  1237
        CT_DoLog STATE "  Not saving '${dir}': does not exist"
yann@1907
  1238
    fi
yann@1907
  1239
}
yann@1907
  1240
yann@1907
  1241
# This function extracts a tarball to the specified directory, but
yann@1907
  1242
# only if the tarball exists
anthony@2155
  1243
# Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
yann@1907
  1244
CT_DoExtractTarballIfExists() {
yann@1907
  1245
    local tarball="$1"
yann@1907
  1246
    local dir="$2"
yann@1907
  1247
    shift 2
yann@1907
  1248
    local -a extra_tar_opts=( "$@" )
yann@1908
  1249
    local -a uncompress
yann@1907
  1250
yann@1907
  1251
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
  1252
        y)  uncompress=( gzip -c -d ); tar_ext=.gz;;
yann@1908
  1253
        *)  uncompress=( cat );        tar_ext=;;
yann@1907
  1254
    esac
yann@1907
  1255
yann@1907
  1256
    if [ -f "${tarball}.tar${tar_ext}" ]; then
yann@1907
  1257
        CT_DoLog DEBUG "  Restoring '${dir}'"
yann@1907
  1258
        CT_DoForceRmdir "${dir}"
yann@1907
  1259
        CT_DoExecLog DEBUG mkdir -p "${dir}"
yann@1908
  1260
        { "${uncompress[@]}" "${tarball}.tar${tar_ext}"     \
yann@1908
  1261
          |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
anthony@2155
  1262
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
  1263
    else
anthony@2155
  1264
        CT_DoLog STATE "  Not restoring '${dir}': does not exist"
yann@1907
  1265
    fi
yann@1907
  1266
}
yann@1907
  1267
yann@121
  1268
# This function saves the state of the toolchain to be able to restart
yann@121
  1269
# at any one point
yann@121
  1270
# Usage: CT_DoSaveState <next_step_name>
yann@121
  1271
CT_DoSaveState() {
yann@121
  1272
	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
yann@121
  1273
    local state_name="$1"
yann@121
  1274
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@121
  1275
yann@1266
  1276
    # Log this to the log level required by the user
yann@1266
  1277
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
yann@1134
  1278
yann@121
  1279
    rm -rf "${state_dir}"
yann@121
  1280
    mkdir -p "${state_dir}"
yann@121
  1281
anthony@2155
  1282
    CT_DoLog STATE "  Saving environment and aliases"
yann@738
  1283
    # We must omit shell functions, and some specific bash variables
yann@738
  1284
    # that break when restoring the environment, later. We could do
yann@1299
  1285
    # all the processing in the awk script, but a sed is easier...
yann@1299
  1286
    set |awk '
yann@1017
  1287
              BEGIN { _p = 1; }
yann@1017
  1288
              $0~/^[^ ]+ \(\)/ { _p = 0; }
yann@1017
  1289
              _p == 1
yann@1017
  1290
              $0 == "}" { _p = 1; }
yann@1017
  1291
              ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
yann@738
  1292
                           /^(UID|EUID)=/d;
yann@738
  1293
                           /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
yann@121
  1294
yann@2308
  1295
    CT_DoTarballIfExists "${CT_BUILDTOOLS_PREFIX_DIR}" "${state_dir}/buildtools_dir"
yann@1907
  1296
    CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
yann@1907
  1297
    CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
yann@121
  1298
yann@2339
  1299
    CT_DoLog STATE "  Saving log file"
yann@2339
  1300
    exec >/dev/null
yann@2339
  1301
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@2339
  1302
        y)  gzip -3 -c "${tmp_log_file}"  >"${state_dir}/log.gz";;
yann@2339
  1303
        *)  cat "${tmp_log_file}" >"${state_dir}/log";;
yann@2339
  1304
    esac
yann@2339
  1305
    exec >>"${tmp_log_file}"
yann@121
  1306
}
yann@121
  1307
yann@136
  1308
# This function restores a previously saved state
yann@121
  1309
# Usage: CT_DoLoadState <state_name>
yann@121
  1310
CT_DoLoadState(){
yann@121
  1311
    local state_name="$1"
yann@121
  1312
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@135
  1313
    local old_RESTART="${CT_RESTART}"
yann@135
  1314
    local old_STOP="${CT_STOP}"
yann@121
  1315
yann@523
  1316
    CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
yann@141
  1317
yann@121
  1318
    # We need to do something special with the log file!
yann@121
  1319
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
  1320
        exec >"${state_dir}/tail.log"
yann@121
  1321
    fi
yann@1266
  1322
yann@1266
  1323
    # Log this to the log level required by the user
yann@1266
  1324
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
yann@121
  1325
yann@1907
  1326
    CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
yann@1907
  1327
    CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
yann@2308
  1328
    CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_PREFIX_DIR}"
yann@1894
  1329
yann@121
  1330
    # Restore the environment, discarding any error message
yann@121
  1331
    # (for example, read-only bash internals)
anthony@2155
  1332
    CT_DoLog STATE "  Restoring environment"
yann@121
  1333
    . "${state_dir}/env.sh" >/dev/null 2>&1 || true
yann@121
  1334
yann@135
  1335
    # Restore the new RESTART and STOP steps
yann@135
  1336
    CT_RESTART="${old_RESTART}"
yann@135
  1337
    CT_STOP="${old_STOP}"
yann@135
  1338
    unset old_stop old_restart
yann@135
  1339
yann@2339
  1340
    CT_DoLog STATE "  Restoring log file"
yann@2339
  1341
    exec >/dev/null
yann@2339
  1342
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@3247
  1343
        y)  gzip -dc "${state_dir}/log.gz" >"${tmp_log_file}";;
yann@2339
  1344
        *)  cat "${state_dir}/log" >"${tmp_log_file}";;
yann@2339
  1345
    esac
yann@2339
  1346
    cat "${state_dir}/tail.log" >>"${tmp_log_file}"
yann@2339
  1347
    exec >>"${tmp_log_file}"
yann@2339
  1348
    rm -f "${state_dir}/tail.log"
yann@121
  1349
}