scripts/functions
author Daniel Price <daniel.price@gmail.com>
Tue Nov 20 16:59:17 2012 -0800 (2012-11-20)
changeset 3126 333d3e40cbd1
parent 3096 d1766c2273d1
child 3127 2af20cfd210b
permissions -rw-r--r--
scripts: refine static linking check to better guide the user

The current mechanism to check if static linking is possible, and the mesage
displayed on failure, can be puzzling to the unsuspecting user.

Also, the current implementation is not using the existing infrastructure,
and is thus difficult to enhance with new tests.

So, switch to using the standard CT_DoExecLog infra, and use four tests to
check for the host compiler:
- check we can run it
- check it can build a trivial program
- check it can statically link that program
- check if it statically link with libstdc++

That should cover most of the problems. Hopefully.

(At the same time, fix a typo in a comment)

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