scripts/functions
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Thu Dec 27 12:53:32 2012 +0100 (2012-12-27)
changeset 3153 f6740f9e42de
parent 3097 5c67476c7342
child 3169 9d0b37f08a10
permissions -rw-r--r--
scripts/addToolsVersion: handle elf2flt

The one was missing from the list.

It is very improbable that we ever need it, as elf2flt does no release,
and we always get it from CVS head. But for the sake of consistency, we
just add it.

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