scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Thu Jun 11 21:47:19 2009 +0000 (2009-06-11)
branch1.4
changeset 1451 25d050084e98
parent 1294 6fe8df60cfa4
child 1391 3c28b9f917d2
permissions -rw-r--r--
populate: fix installing dynamic linker 'ld.so'

The dynamic linker, ld.so, needs the execute bit to be set.
Detect tht the library being installed is in fact ld.so and
install it with 0755 instead of 0644.

Fix detecting src == dst.

Use a simpler command to copy src -> dst.

Also change echo to printf, get rid of 'echo -n', which is
highly non-portable.


-------- diffstat follows --------
/trunk/scripts/populate.in | 76 43 33 0 +++++++++++++++++++++++++++++-----------------------
1 file changed, 43 insertions(+), 33 deletions(-)
(transplanted from d7ddcb75e0f703e2ba6d17169167356389224870)
yann@1
     1
# This file contains some usefull common functions
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@1
     7
    ret=$?
yann@726
     8
    # Bail out early in subshell, the upper level shell will act accordingly.
yann@726
     9
    [ ${BASH_SUBSHELL} -eq 0 ] || exit $ret
yann@523
    10
    CT_DoLog ERROR "Build failed in step '${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}'"
yann@1
    11
    for((step=(CT_STEP_COUNT-1); step>1; step--)); do
yann@523
    12
        CT_DoLog ERROR "      called in step '${CT_STEP_MESSAGE[${step}]}'"
yann@1
    13
    done
yann@523
    14
    CT_DoLog ERROR "Error happened in '${BASH_SOURCE[1]}' in function '${FUNCNAME[1]}' (line unknown, sorry)"
yann@1
    15
    for((depth=2; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
yann@523
    16
        CT_DoLog ERROR "      called from '${BASH_SOURCE[${depth}]}' at line # ${BASH_LINENO[${depth}-1]} in function '${FUNCNAME[${depth}]}'"
yann@1
    17
    done
yann@523
    18
    [ "${CT_LOG_TO_FILE}" = "y" ] && CT_DoLog ERROR "Look at '${CT_LOG_FILE}' for more info on this error."
yann@96
    19
    CT_STEP_COUNT=1
yann@96
    20
    CT_DoEnd ERROR
yann@1
    21
    exit $ret
yann@1
    22
}
yann@136
    23
yann@136
    24
# Install the fault handler
yann@1
    25
trap CT_OnError ERR
yann@1
    26
yann@136
    27
# Inherit the fault handler in subshells and functions
yann@1
    28
set -E
yann@136
    29
yann@136
    30
# Make pipes fail on the _first_ failed command
yann@136
    31
# Not supported on bash < 3.x, but we need it, so drop the obsoleting bash-2.x
yann@1
    32
set -o pipefail
yann@1
    33
yann@136
    34
# Don't hash commands' locations, and search every time it is requested.
yann@136
    35
# This is slow, but needed because of the static/shared core gcc which shall
yann@136
    36
# always match to shared if it exists, and only fallback to static if the
yann@136
    37
# shared is not found
yann@136
    38
set +o hashall
yann@136
    39
yann@165
    40
# Log policy:
yann@165
    41
#  - first of all, save stdout so we can see the live logs: fd #6
yann@165
    42
exec 6>&1
yann@165
    43
#  - then point stdout to the log file (temporary for now)
yann@165
    44
tmp_log_file="${CT_TOP_DIR}/log.$$"
yann@165
    45
exec >>"${tmp_log_file}"
yann@165
    46
yann@1
    47
# The different log levels:
yann@1
    48
CT_LOG_LEVEL_ERROR=0
yann@1
    49
CT_LOG_LEVEL_WARN=1
yann@1
    50
CT_LOG_LEVEL_INFO=2
yann@1
    51
CT_LOG_LEVEL_EXTRA=3
yann@1
    52
CT_LOG_LEVEL_DEBUG=4
yann@78
    53
CT_LOG_LEVEL_ALL=5
yann@1
    54
yann@1083
    55
# Make it easy to use \n and !
yann@1081
    56
CR=$(printf "\n")
yann@1083
    57
BANG='!'
yann@1081
    58
yann@1
    59
# A function to log what is happening
yann@1
    60
# Different log level are available:
yann@1
    61
#   - ERROR:   A serious, fatal error occurred
yann@1
    62
#   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
yann@1
    63
#   - INFO:    Informational messages
yann@1
    64
#   - EXTRA:   Extra informational messages
yann@1
    65
#   - DEBUG:   Debug messages
yann@78
    66
#   - ALL:     Component's build messages
yann@1
    67
# Usage: CT_DoLog <level> [message]
yann@1
    68
# If message is empty, then stdin will be logged.
yann@1
    69
CT_DoLog() {
yann@47
    70
    local max_level LEVEL level cur_l cur_L
yann@47
    71
    local l
yann@1
    72
    eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
yann@1
    73
    # Set the maximum log level to DEBUG if we have none
yann@78
    74
    [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
yann@1
    75
yann@47
    76
    LEVEL="$1"; shift
yann@1
    77
    eval level="\${CT_LOG_LEVEL_${LEVEL}}"
yann@1
    78
yann@1
    79
    if [ $# -eq 0 ]; then
yann@1
    80
        cat -
yann@1
    81
    else
yann@646
    82
        echo "${@}"
yann@1081
    83
    fi |( IFS="${CR}" # We want the full lines, even leading spaces
yann@523
    84
          _prog_bar_cpt=0
yann@523
    85
          _prog_bar[0]='/'
yann@523
    86
          _prog_bar[1]='-'
yann@523
    87
          _prog_bar[2]='\'
yann@523
    88
          _prog_bar[3]='|'
yann@1
    89
          indent=$((2*CT_STEP_COUNT))
yann@1
    90
          while read line; do
yann@47
    91
              case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
yann@47
    92
                y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@112
    93
                y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@47
    94
                *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@919
    95
                *"make["*"]: *** ["*)   cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@47
    96
                *)                      cur_L="${LEVEL}"; cur_l="${level}";;
yann@47
    97
              esac
yann@523
    98
              # There will always be a log file (stdout, fd #1), be it /dev/null
yann@523
    99
              printf "[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}"
yann@47
   100
              if [ ${cur_l} -le ${max_level} ]; then
yann@523
   101
                  # Only print to console (fd #6) if log level is high enough.
yann@523
   102
                  printf "\r[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}" >&6
yann@82
   103
              fi
yann@82
   104
              if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
yann@523
   105
                  printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${_prog_bar[$((_prog_bar_cpt/10))]}" >&6
yann@523
   106
                  _prog_bar_cpt=$(((_prog_bar_cpt+1)%40))
yann@1
   107
              fi
yann@1
   108
          done
yann@1
   109
        )
yann@1
   110
yann@1
   111
    return 0
yann@1
   112
}
yann@1
   113
yann@535
   114
# Execute an action, and log its messages
yann@1257
   115
# Usage: [VAR=val...] CT_DoExecLog <level> <command [parameters...]>
yann@535
   116
CT_DoExecLog() {
yann@535
   117
    local level="$1"
yann@535
   118
    shift
yann@657
   119
    CT_DoLog DEBUG "==> Executing: '${@}'"
yann@668
   120
    "${@}" 2>&1 |CT_DoLog "${level}"
yann@535
   121
}
yann@535
   122
yann@96
   123
# Tail message to be logged whatever happens
yann@96
   124
# Usage: CT_DoEnd <level>
yann@96
   125
CT_DoEnd()
yann@96
   126
{
yann@145
   127
    local level="$1"
yann@523
   128
    CT_STOP_DATE=$(CT_DoDate +%s%N)
yann@523
   129
    CT_STOP_DATE_HUMAN=$(CT_DoDate +%Y%m%d.%H%M%S)
yann@599
   130
    if [ "${level}" != "ERROR" ]; then
yann@582
   131
        CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
yann@582
   132
    fi
yann@96
   133
    elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
yann@96
   134
    elapsed_min=$((elapsed/(60*1000*1000*1000)))
yann@523
   135
    elapsed_sec=$(printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000))))
yann@523
   136
    elapsed_csec=$(printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000))))
yann@145
   137
    CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
yann@96
   138
}
yann@96
   139
yann@96
   140
# Abort the execution with an error message
yann@1
   141
# Usage: CT_Abort <message>
yann@1
   142
CT_Abort() {
yann@128
   143
    CT_DoLog ERROR "$1"
yann@1
   144
    exit 1
yann@1
   145
}
yann@1
   146
yann@1
   147
# Test a condition, and print a message if satisfied
yann@1
   148
# Usage: CT_Test <message> <tests>
yann@1
   149
CT_Test() {
yann@1
   150
    local ret
yann@1
   151
    local m="$1"
yann@1
   152
    shift
yann@1
   153
    test "$@" && CT_DoLog WARN "$m"
yann@1
   154
    return 0
yann@1
   155
}
yann@1
   156
yann@1
   157
# Test a condition, and abort with an error message if satisfied
yann@1
   158
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   159
CT_TestAndAbort() {
yann@1
   160
    local m="$1"
yann@1
   161
    shift
yann@1
   162
    test "$@" && CT_Abort "$m"
yann@1
   163
    return 0
yann@1
   164
}
yann@1
   165
yann@1
   166
# Test a condition, and abort with an error message if not satisfied
yann@1
   167
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   168
CT_TestOrAbort() {
yann@1
   169
    local m="$1"
yann@1
   170
    shift
yann@1
   171
    test "$@" || CT_Abort "$m"
yann@1
   172
    return 0
yann@1
   173
}
yann@1
   174
yann@1
   175
# Test the presence of a tool, or abort if not found
yann@1
   176
# Usage: CT_HasOrAbort <tool>
yann@1
   177
CT_HasOrAbort() {
yann@773
   178
    CT_TestAndAbort "'${1}' not found and needed for successful toolchain build." -z "$(CT_Which "${1}")"
yann@1
   179
    return 0
yann@1
   180
}
yann@1
   181
yann@210
   182
# Search a program: wrap "which" for those system where
yann@1226
   183
# "which" verbosely says there is no match (Mandriva is
yann@1226
   184
# such a sucker...)
yann@210
   185
# Usage: CT_Which <filename>
yann@210
   186
CT_Which() {
yann@210
   187
  which "$1" 2>/dev/null || true
yann@210
   188
}
yann@210
   189
yann@1
   190
# Get current date with nanosecond precision
yann@1
   191
# On those system not supporting nanosecond precision, faked with rounding down
yann@1
   192
# to the highest entire second
yann@1
   193
# Usage: CT_DoDate <fmt>
yann@1
   194
CT_DoDate() {
yann@1
   195
    date "$1" |sed -r -e 's/%N$/000000000/;'
yann@1
   196
}
yann@1
   197
yann@1
   198
CT_STEP_COUNT=1
yann@1
   199
CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
yann@1
   200
# Memorise a step being done so that any error is caught
yann@1
   201
# Usage: CT_DoStep <loglevel> <message>
yann@1
   202
CT_DoStep() {
yann@523
   203
    local start=$(CT_DoDate +%s%N)
yann@1
   204
    CT_DoLog "$1" "================================================================="
yann@1
   205
    CT_DoLog "$1" "$2"
yann@1
   206
    CT_STEP_COUNT=$((CT_STEP_COUNT+1))
yann@1
   207
    CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
yann@1
   208
    CT_STEP_START[${CT_STEP_COUNT}]="${start}"
yann@1
   209
    CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
yann@1
   210
    return 0
yann@1
   211
}
yann@1
   212
yann@1
   213
# End the step just being done
yann@1
   214
# Usage: CT_EndStep
yann@1
   215
CT_EndStep() {
yann@523
   216
    local stop=$(CT_DoDate +%s%N)
yann@523
   217
    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
   218
    local elapsed=$(printf "%02d:%02d" $((SECONDS/60)) $((SECONDS%60)))
yann@1
   219
    local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
yann@1
   220
    local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
yann@1
   221
    CT_STEP_COUNT=$((CT_STEP_COUNT-1))
yann@582
   222
    CT_DoLog "${level}" "${message}: done in ${duration}s (at ${elapsed})"
yann@1
   223
    return 0
yann@1
   224
}
yann@1
   225
yann@1
   226
# Pushes into a directory, and pops back
yann@1
   227
CT_Pushd() {
yann@1
   228
    pushd "$1" >/dev/null 2>&1
yann@1
   229
}
yann@1
   230
CT_Popd() {
yann@1
   231
    popd >/dev/null 2>&1
yann@1
   232
}
yann@1
   233
yann@1
   234
# Creates a temporary directory
yann@1
   235
# $1: variable to assign to
yann@1
   236
# Usage: CT_MktempDir foo
yann@1
   237
CT_MktempDir() {
yann@1
   238
    # Some mktemp do not allow more than 6 Xs
yann@1113
   239
    eval "$1"=$(mktemp -q -d "${CT_BUILD_DIR}/tmp.XXXXXX")
yann@1
   240
    CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
yann@787
   241
    CT_DoLog DEBUG "Made temporary directory '${!1}'"
yann@787
   242
    return 0
yann@1
   243
}
yann@1
   244
yann@1148
   245
# Removes one or more directories, even if it is read-only, or its parent is
yann@1138
   246
# Usage: CT_DoForceRmdir dir [...]
yann@1138
   247
CT_DoForceRmdir() {
yann@1148
   248
    local dir
yann@1148
   249
    local mode
yann@1148
   250
    for dir in "${@}"; do
yann@1148
   251
        [ -d "${dir}" ] || continue
yann@1185
   252
        mode="$(stat -c '%a' "$(dirname "${dir}")")"
yann@1185
   253
        CT_DoExecLog ALL chmod u+w "$(dirname "${dir}")"
yann@1185
   254
        CT_DoExecLog ALL chmod -R u+w "${dir}"
yann@1148
   255
        CT_DoExecLog ALL rm -rf "${dir}"
yann@1185
   256
        CT_DoExecLog ALL chmod ${mode} "$(dirname "${dir}")"
yann@1148
   257
    done
yann@1138
   258
}
yann@1138
   259
yann@1
   260
# Echoes the specified string on stdout until the pipe breaks.
yann@1
   261
# Doesn't fail
yann@1
   262
# $1: string to echo
yann@1
   263
# Usage: CT_DoYes "" |make oldconfig
yann@1
   264
CT_DoYes() {
yann@1
   265
    yes "$1" || true
yann@1
   266
}
yann@63
   267
yann@85
   268
# Get the file name extension of a component
yann@719
   269
# Usage: CT_GetFileExtension <component_name-component_version> [extension]
yann@85
   270
# If found, echoes the extension to stdout
yann@85
   271
# If not found, echoes nothing on stdout.
yann@85
   272
CT_GetFileExtension() {
yann@85
   273
    local ext
yann@85
   274
    local file="$1"
yann@719
   275
    shift
yann@719
   276
    local first_ext="$1"
yann@85
   277
yann@160
   278
    # we need to also check for an empty extension for those very
yann@160
   279
    # peculiar components that don't have one (such as sstrip from
yann@160
   280
    # buildroot).
yann@719
   281
    for ext in ${first_ext} .tar.gz .tar.bz2 .tgz .tar ''; do
yann@1123
   282
        if [ -f "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
yann@85
   283
            echo "${ext}"
yann@85
   284
            break
yann@85
   285
        fi
yann@85
   286
    done
yann@85
   287
yann@85
   288
    return 0
yann@85
   289
}
yann@85
   290
yann@63
   291
# Download an URL using wget
yann@63
   292
# Usage: CT_DoGetFileWget <URL>
yann@63
   293
CT_DoGetFileWget() {
yann@63
   294
    # Need to return true because it is legitimate to not find the tarball at
yann@63
   295
    # some of the provided URLs (think about snapshots, different layouts for
yann@63
   296
    # different gcc versions, etc...)
yann@63
   297
    # Some (very old!) FTP server might not support the passive mode, thus
yann@63
   298
    # retry without
yann@63
   299
    # With automated download as we are doing, it can be very dangerous to use
yann@63
   300
    # -c to continue the downloads. It's far better to simply overwrite the
yann@63
   301
    # destination file
yann@492
   302
    # Some company networks have firewalls to connect to the internet, but it's
yann@1113
   303
    # not easy to detect them, and wget does not timeout by default while
yann@492
   304
    # connecting, so force a global ${CT_CONNECT_TIMEOUT}-second timeout.
yann@1257
   305
    CT_DoExecLog ALL wget -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary --tries=3 --passive-ftp "$1"    \
yann@1257
   306
    || CT_DoExecLog ALL wget -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary --tries=3 "$1"               \
yann@439
   307
    || true
yann@63
   308
}
yann@63
   309
yann@63
   310
# Download an URL using curl
yann@63
   311
# Usage: CT_DoGetFileCurl <URL>
yann@63
   312
CT_DoGetFileCurl() {
yann@492
   313
    # Note: comments about wget method (above) are also valid here
yann@439
   314
    # Plus: no good progress indicator is available with curl,
yann@1257
   315
    #       so, be silent.
yann@1257
   316
    CT_DoExecLog ALL curl -s --ftp-pasv -O --retry 3 "$1" --connect-timeout ${CT_CONNECT_TIMEOUT}    \
yann@1257
   317
    || CT_DoExecLog ALL curl -s -O --retry 3 "$1" --connect-timeout ${CT_CONNECT_TIMEOUT}            \
yann@439
   318
    || true
yann@63
   319
}
yann@63
   320
yann@523
   321
_wget=$(CT_Which wget)
yann@523
   322
_curl=$(CT_Which curl)
yann@63
   323
# Wrapper function to call one of curl or wget
yann@63
   324
# Usage: CT_DoGetFile <URL>
yann@63
   325
CT_DoGetFile() {
yann@63
   326
    case "${_wget},${_curl}" in
yann@1120
   327
        ,)  CT_Abort "Could find neither wget nor curl";;
yann@1257
   328
        ,*) CT_DoGetFileCurl "$1";;
yann@1257
   329
        *)  CT_DoGetFileWget "$1";;
yann@63
   330
    esac
yann@63
   331
}
yann@63
   332
yann@1113
   333
# This function tries to retrieve a tarball form a local directory
yann@1113
   334
# Usage: CT_GetLocal <basename> [.extension]
yann@1113
   335
CT_GetLocal() {
yann@1113
   336
    local basename="$1"
yann@1113
   337
    local first_ext="$2"
yann@1113
   338
    local ext
yann@1113
   339
yann@1113
   340
    # Do we already have it in *our* tarballs dir?
yann@1113
   341
    ext=$(CT_GetFileExtension "${basename}" ${first_ext})
yann@1113
   342
    if [ -n "${ext}" ]; then
yann@1113
   343
        CT_DoLog DEBUG "Already have '${basename}'"
yann@1113
   344
        return 0
yann@1113
   345
    fi
yann@1113
   346
yann@1113
   347
    if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
yann@1113
   348
        CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
yann@1113
   349
        # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
yann@1113
   350
        # or, as a failover, a file without extension.
yann@1113
   351
        for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@1113
   352
            CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
yann@1113
   353
            if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
yann@1113
   354
                 "${CT_FORCE_DOWNLOAD}" != "y" ]; then
yann@1113
   355
                CT_DoLog DEBUG "Got '${basename}' from local storage"
yann@1113
   356
                CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1113
   357
                return 0
yann@1113
   358
            fi
yann@1113
   359
        done
yann@1113
   360
    fi
yann@1113
   361
    return 1
yann@1113
   362
}
yann@1113
   363
yann@1113
   364
# This function saves the specified to local storage if possible,
yann@1113
   365
# and if so, symlinks it for later usage
yann@1113
   366
# Usage: CT_SaveLocal </full/path/file.name>
yann@1113
   367
CT_SaveLocal() {
yann@1113
   368
    local file="$1"
yann@1113
   369
    local basename="${file##*/}"
yann@1113
   370
yann@1113
   371
    if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
yann@1134
   372
        CT_DoLog EXTRA "Saving '${basename}' to local storage"
yann@1113
   373
        # The file may already exist if downloads are forced: remove it first
yann@1113
   374
        CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
yann@1113
   375
        CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
yann@1113
   376
        CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
yann@1113
   377
    fi
yann@1113
   378
}
yann@1113
   379
yann@63
   380
# Download the file from one of the URLs passed as argument
yann@1113
   381
# Usage: CT_GetFile <basename> [.extension] <url> [url ...]
yann@63
   382
CT_GetFile() {
yann@63
   383
    local ext
yann@1179
   384
    local url URLS LAN_URLS
yann@63
   385
    local file="$1"
yann@1113
   386
    local first_ext
yann@63
   387
    shift
yann@712
   388
    # If next argument starts with a dot, then this is not an URL,
yann@712
   389
    # and we can consider that it is a preferred extension.
yann@242
   390
    case "$1" in
yann@712
   391
        .*) first_ext="$1"
yann@242
   392
            shift
yann@242
   393
            ;;
yann@242
   394
    esac
yann@63
   395
yann@1113
   396
    # Does it exist localy?
yann@1113
   397
    CT_GetLocal "${file}" ${first_ext} && return 0 || true
yann@1113
   398
    # No, it does not...
yann@63
   399
yann@1131
   400
    # Are downloads allowed ?
yann@1131
   401
    CT_TestAndAbort "File '${file}' not present locally, and downloads are not allowed" "${CT_FORBID_DOWNLOAD}" = "y"
yann@1131
   402
yann@754
   403
    # Try to retrieve the file
yann@788
   404
    CT_DoLog EXTRA "Retrieving '${file}'"
yann@63
   405
    CT_Pushd "${CT_TARBALLS_DIR}"
yann@754
   406
yann@1179
   407
    URLS="$@"
yann@1179
   408
yann@1022
   409
    # Add URLs on the LAN mirror
yann@1022
   410
    LAN_URLS=
yann@1022
   411
    if [ "${CT_USE_MIRROR}" = "y" ]; then
yann@1294
   412
        CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
yann@1294
   413
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}/${file%-*}"
yann@1294
   414
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}"
yann@695
   415
yann@1134
   416
        if [ "${CT_PREFER_MIRROR}" = "y" ]; then
yann@1134
   417
            CT_DoLog DEBUG "Pre-pending LAN mirror URLs"
yann@1179
   418
            URLS="${LAN_URLS} ${URLS}"
yann@1134
   419
        else
yann@1134
   420
            CT_DoLog DEBUG "Appending LAN mirror URLs"
yann@1179
   421
            URLS="${URLS} ${LAN_URLS}"
yann@1134
   422
        fi
yann@1022
   423
    fi
yann@1022
   424
yann@1022
   425
    # Scan all URLs in turn, and try to grab a tarball from there
yann@242
   426
    for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@102
   427
        # Try all urls in turn
yann@1022
   428
        for url in ${URLS}; do
yann@523
   429
            CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
yann@265
   430
            CT_DoGetFile "${url}/${file}${ext}"
yann@265
   431
            if [ -f "${file}${ext}" ]; then
yann@799
   432
                CT_DoLog DEBUG "Got '${file}' from the Internet"
yann@1113
   433
                CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
yann@265
   434
                return 0
yann@265
   435
            fi
yann@102
   436
        done
yann@102
   437
    done
yann@63
   438
    CT_Popd
yann@63
   439
yann@754
   440
    CT_Abort "Could not retrieve '${file}'."
yann@63
   441
}
yann@63
   442
yann@1113
   443
# Checkout from CVS, and build the associated tarball
yann@1113
   444
# The tarball will be called ${basename}.tar.bz2
yann@1113
   445
# Prerequisite: either the server does not require password,
yann@1113
   446
# or the user must already be logged in.
yann@1113
   447
# 'tag' is the tag to retrieve. Must be specified, but can be empty.
yann@1113
   448
# If dirname is specified, then module will be renamed to dirname
yann@1113
   449
# prior to building the tarball.
yann@1113
   450
# Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname]
yann@1113
   451
CT_GetCVS() {
yann@1113
   452
    local basename="$1"
yann@1113
   453
    local uri="$2"
yann@1113
   454
    local module="$3"
yann@1113
   455
    local tag="${4:+-r ${4}}"
yann@1113
   456
    local dirname="$5"
yann@1113
   457
    local tmp_dir
yann@1113
   458
yann@1113
   459
    # Does it exist localy?
yann@1113
   460
    CT_GetLocal "${basename}" && return 0 || true
yann@1113
   461
    # No, it does not...
yann@1113
   462
yann@1131
   463
    # Are downloads allowed ?
yann@1244
   464
    CT_TestAndAbort "File '${basename}' not present locally, and downloads are not allowed" "${CT_FORBID_DOWNLOAD}" = "y"
yann@1131
   465
yann@1113
   466
    CT_DoLog EXTRA "Retrieving '${basename}'"
yann@1113
   467
yann@1113
   468
    CT_MktempDir tmp_dir
yann@1113
   469
    CT_Pushd "${tmp_dir}"
yann@1113
   470
yann@1113
   471
    CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
yann@1113
   472
    [ -n "${dirname}" ] && CT_DoExecLog ALL mv "${module}" "${dirname}"
yann@1113
   473
    CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
yann@1113
   474
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1113
   475
yann@1113
   476
    CT_Popd
yann@1113
   477
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1113
   478
}
yann@1113
   479
yann@1244
   480
# Check out from SVN, and build the associated tarball
yann@1244
   481
# The tarball will be called ${basename}.tar.bz2
yann@1244
   482
# Prerequisite: either the server does not require password,
yann@1244
   483
# or the user must already be logged in.
yann@1244
   484
# 'rev' is the revision to retrieve
yann@1244
   485
# Usage: CT_GetSVN <basename> <url> [rev]
yann@1244
   486
CT_GetSVN() {
yann@1244
   487
    local basename="$1"
yann@1244
   488
    local uri="$2"
yann@1244
   489
    local rev="$3"
yann@1244
   490
yann@1244
   491
    # Does it exist localy?
yann@1244
   492
    CT_GetLocal "${basename}" && return 0 || true
yann@1244
   493
    # No, it does not...
yann@1244
   494
yann@1244
   495
    # Are downloads allowed ?
yann@1244
   496
    CT_TestAndAbort "File '${basename}' not present locally, and downloads are not allowed" "${CT_FORBID_DOWNLOAD}" = "y"
yann@1244
   497
yann@1244
   498
    CT_DoLog EXTRA "Retrieving '${basename}'"
yann@1244
   499
yann@1244
   500
    CT_MktempDir tmp_dir
yann@1244
   501
    CT_Pushd "${tmp_dir}"
yann@1244
   502
yann@1244
   503
    CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"
yann@1244
   504
    CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
yann@1244
   505
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1244
   506
yann@1244
   507
    CT_Popd
yann@1244
   508
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1244
   509
}
yann@1244
   510
yann@1126
   511
# Extract a tarball
yann@63
   512
# Some tarballs need to be extracted in specific places. Eg.: glibc addons
yann@63
   513
# must be extracted in the glibc directory; uCLibc locales must be extracted
yann@1123
   514
# in the extra/locale sub-directory of uClibc. This is taken into account
yann@1123
   515
# by the caller, that did a 'cd' into the correct path before calling us
yann@1123
   516
# and sets nochdir to 'nochdir'.
yann@1126
   517
# Usage: CT_Extract <basename> [nochdir]
yann@1126
   518
CT_Extract() {
yann@1126
   519
    local basename="$1"
yann@1123
   520
    local nochdir="$2"
yann@1126
   521
    local ext=$(CT_GetFileExtension "${basename}")
yann@1126
   522
    CT_TestAndAbort "'${basename}' not found in '${CT_TARBALLS_DIR}'" -z "${ext}"
yann@1126
   523
    local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1126
   524
yann@1126
   525
    # Check if already extracted
yann@1126
   526
    if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
yann@1126
   527
        CT_DoLog DEBUG "Already extracted '${basename}'"
yann@1126
   528
        return 0
yann@1126
   529
    fi
yann@63
   530
yann@1123
   531
    [ "${nochdir}" = "nochdir" ] || CT_Pushd "${CT_SRC_DIR}"
yann@63
   532
yann@1126
   533
    CT_DoLog EXTRA "Extracting '${basename}'"
yann@63
   534
    case "${ext}" in
yann@776
   535
        .tar.bz2)     CT_DoExecLog ALL tar xvjf "${full_file}";;
yann@776
   536
        .tar.gz|.tgz) CT_DoExecLog ALL tar xvzf "${full_file}";;
yann@776
   537
        .tar)         CT_DoExecLog ALL tar xvf  "${full_file}";;
yann@1126
   538
        *)            CT_Abort "Don't know how to handle '${basename}${ext}': unknown extension" ;;
yann@63
   539
    esac
yann@63
   540
yann@1208
   541
    # Some tarballs have read-only files... :-(
yann@1258
   542
    # Because of nochdir, we don't know where we are, so chmod all
yann@1258
   543
    # the src tree
yann@1271
   544
    CT_DoExecLog DEBUG chmod -R u+w "${CT_SRC_DIR}"
yann@1208
   545
yann@1271
   546
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted"
yann@1126
   547
yann@1126
   548
    [ "${nochdir}" = "nochdir" ] || CT_Popd
yann@1126
   549
}
yann@1126
   550
yann@1126
   551
# Patches the specified component
yann@1126
   552
# Usage: CT_Patch <basename> [nochdir]
yann@1126
   553
CT_Patch() {
yann@1126
   554
    local basename="$1"
yann@1126
   555
    local nochdir="$2"
yann@1126
   556
    local base_file="${basename%%-*}"
yann@1126
   557
    local ver_file="${basename#*-}"
yann@1126
   558
    local official_patch_dir
yann@1126
   559
    local custom_patch_dir
yann@1126
   560
yann@1126
   561
    # Check if already patched
yann@1126
   562
    if [ -e "${CT_SRC_DIR}/.${basename}.patched" ]; then
yann@1126
   563
        CT_DoLog DEBUG "Already patched '${basename}'"
yann@1126
   564
        return 0
yann@63
   565
    fi
yann@63
   566
yann@1271
   567
    # Check if already partially patched
yann@1271
   568
    if [ -e "${CT_SRC_DIR}/.${basename}.patching" ]; then
yann@1271
   569
        CT_DoLog ERROR "The '${basename}' sources were partially patched."
yann@1271
   570
        CT_DoLog ERROR "Please remove first:"
yann@1271
   571
        CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
yann@1271
   572
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracted'"
yann@1271
   573
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.patching'"
yann@1271
   574
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1271
   575
    fi
yann@1271
   576
    touch "${CT_SRC_DIR}/.${basename}.patching"
yann@1271
   577
yann@1126
   578
    [ "${nochdir}" = "nochdir" ] || CT_Pushd "${CT_SRC_DIR}/${basename}"
yann@1123
   579
yann@1126
   580
    CT_DoLog EXTRA "Patching '${basename}'"
yann@63
   581
yann@182
   582
    official_patch_dir=
yann@182
   583
    custom_patch_dir=
yann@956
   584
    [ "${CT_CUSTOM_PATCH_ONLY}" = "y" ] || official_patch_dir="${CT_LIB_DIR}/patches/${base_file}/${ver_file}"
yann@63
   585
    [ "${CT_CUSTOM_PATCH}" = "y" ] && custom_patch_dir="${CT_CUSTOM_PATCH_DIR}/${base_file}/${ver_file}"
yann@63
   586
    for patch_dir in "${official_patch_dir}" "${custom_patch_dir}"; do
yann@63
   587
        if [ -n "${patch_dir}" -a -d "${patch_dir}" ]; then
yann@63
   588
            for p in "${patch_dir}"/*.patch; do
yann@63
   589
                if [ -f "${p}" ]; then
yann@523
   590
                    CT_DoLog DEBUG "Applying patch '${p}'"
yann@776
   591
                    CT_DoExecLog ALL patch -g0 -F1 -p1 -f <"${p}"
yann@523
   592
                    CT_TestAndAbort "Failed while applying patch file '${p}'" ${PIPESTATUS[0]} -ne 0
yann@63
   593
                fi
yann@63
   594
            done
yann@63
   595
        fi
yann@63
   596
    done
yann@63
   597
yann@508
   598
    if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
yann@508
   599
        CT_DoLog ALL "Overiding config.guess and config.sub"
yann@508
   600
        for cfg in config_guess config_sub; do
yann@1101
   601
            eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
yann@1101
   602
            [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
yann@776
   603
            # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
yann@508
   604
            find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
yann@508
   605
        done
yann@508
   606
    fi
yann@508
   607
yann@1271
   608
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.patching"
yann@1271
   609
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.patched"
yann@1126
   610
yann@1123
   611
    [ "${nochdir}" = "nochdir" ] || CT_Popd
yann@63
   612
}
yann@63
   613
yann@182
   614
# Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
yann@182
   615
# Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
yann@182
   616
CT_DoConfigGuess() {
yann@1101
   617
    if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
yann@1101
   618
        "${CT_TOP_DIR}/scripts/config.guess"
yann@182
   619
    else
yann@1101
   620
        "${CT_LIB_DIR}/scripts/config.guess"
yann@182
   621
    fi
yann@182
   622
}
yann@182
   623
yann@182
   624
CT_DoConfigSub() {
yann@1101
   625
    if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
yann@1101
   626
        "${CT_TOP_DIR}/scripts/config.sub" "$@"
yann@182
   627
    else
yann@1101
   628
        "${CT_LIB_DIR}/scripts/config.sub" "$@"
yann@182
   629
    fi
yann@182
   630
}
yann@182
   631
yann@335
   632
# Compute the target tuple from what is provided by the user
yann@335
   633
# Usage: CT_DoBuildTargetTuple
yann@63
   634
# In fact this function takes the environment variables to build the target
yann@335
   635
# tuple. It is needed both by the normal build sequence, as well as the
yann@63
   636
# sample saving sequence.
yann@335
   637
CT_DoBuildTargetTuple() {
yann@383
   638
    # Set the endianness suffix, and the default endianness gcc option
yann@63
   639
    case "${CT_ARCH_BE},${CT_ARCH_LE}" in
yann@383
   640
        y,) target_endian_eb=eb
yann@383
   641
            target_endian_el=
yann@391
   642
            CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
yann@527
   643
            CT_ARCH_ENDIAN_LDFLAG="-EB"
yann@383
   644
            ;;
yann@383
   645
        ,y) target_endian_eb=
yann@383
   646
            target_endian_el=el
yann@391
   647
            CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
yann@527
   648
            CT_ARCH_ENDIAN_LDFLAG="-EL"
yann@383
   649
            ;;
yann@63
   650
    esac
yann@383
   651
yann@965
   652
    # Build the default architecture tuple part
yann@965
   653
    CT_TARGET_ARCH="${CT_ARCH}"
yann@965
   654
yann@383
   655
    # Set defaults for the system part of the tuple. Can be overriden
yann@383
   656
    # by architecture-specific values.
yann@383
   657
    case "${CT_LIBC}" in
yann@850
   658
        none)   CT_TARGET_SYS=elf;;
yann@787
   659
        *glibc) CT_TARGET_SYS=gnu;;
yann@383
   660
        uClibc) CT_TARGET_SYS=uclibc;;
yann@63
   661
    esac
yann@383
   662
yann@387
   663
    # Transform the ARCH into a kernel-understandable ARCH
yann@387
   664
    CT_KERNEL_ARCH="${CT_ARCH}"
yann@387
   665
yann@391
   666
    # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
yann@497
   667
    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
   668
    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
   669
    [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
yann@391
   670
    [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
yann@391
   671
    [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
yann@405
   672
    [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
yann@391
   673
    [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
yann@412
   674
    [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float";           CT_ARCH_WITH_FLOAT="--with-float=soft";          }
yann@391
   675
yann@965
   676
    # Build the default kernel tuple part
yann@965
   677
    CT_TARGET_KERNEL="${CT_KERNEL}"
yann@964
   678
yann@965
   679
    # Overide the default values with the components specific settings
yann@964
   680
    CT_DoArchTupleValues
yann@965
   681
    CT_DoKernelTupleValues
yann@383
   682
yann@391
   683
    # Finish the target tuple construction
yann@1094
   684
    CT_TARGET="${CT_TARGET_ARCH}-${CT_TARGET_VENDOR:-unknown}-${CT_TARGET_KERNEL}${CT_TARGET_KERNEL:+-}${CT_TARGET_SYS}"
yann@1094
   685
yann@1094
   686
    # Sanity checks
yann@1094
   687
    __sed_alias=""
yann@1094
   688
    if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
yann@1094
   689
        __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
yann@1094
   690
    fi
yann@1094
   691
    case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
yann@1094
   692
      :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
yann@1094
   693
      :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
yann@1094
   694
      :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
yann@1094
   695
      :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
yann@1094
   696
    esac
yann@1094
   697
yann@1094
   698
    # Canonicalise it
yann@1094
   699
    CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
yann@391
   700
yann@391
   701
    # Prepare the target CFLAGS
yann@767
   702
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
yann@527
   703
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
yann@397
   704
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
yann@397
   705
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
yann@397
   706
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
yann@397
   707
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
yann@397
   708
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
yann@527
   709
yann@527
   710
    # Now on for the target LDFLAGS
yann@767
   711
    CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
yann@63
   712
}
yann@121
   713
yann@121
   714
# This function does pause the build until the user strikes "Return"
yann@121
   715
# Usage: CT_DoPause [optional_message]
yann@121
   716
CT_DoPause() {
yann@121
   717
    local foo
yann@121
   718
    local message="${1:-Pausing for your pleasure}"
yann@121
   719
    CT_DoLog INFO "${message}"
yann@523
   720
    read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
yann@121
   721
    return 0
yann@121
   722
}
yann@121
   723
yann@121
   724
# This function saves the state of the toolchain to be able to restart
yann@121
   725
# at any one point
yann@121
   726
# Usage: CT_DoSaveState <next_step_name>
yann@121
   727
CT_DoSaveState() {
yann@121
   728
	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
yann@121
   729
    local state_name="$1"
yann@121
   730
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@121
   731
yann@1266
   732
    # Log this to the log level required by the user
yann@1266
   733
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
yann@1134
   734
yann@121
   735
    rm -rf "${state_dir}"
yann@121
   736
    mkdir -p "${state_dir}"
yann@121
   737
yann@121
   738
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@327
   739
        y)  tar_opt=z; tar_ext=.gz;;
yann@327
   740
        *)  tar_opt=;  tar_ext=;;
yann@121
   741
    esac
yann@121
   742
yann@121
   743
    CT_DoLog DEBUG "  Saving environment and aliases"
yann@738
   744
    # We must omit shell functions, and some specific bash variables
yann@738
   745
    # that break when restoring the environment, later. We could do
yann@1299
   746
    # all the processing in the awk script, but a sed is easier...
yann@1299
   747
    set |awk '
yann@1017
   748
              BEGIN { _p = 1; }
yann@1017
   749
              $0~/^[^ ]+ \(\)/ { _p = 0; }
yann@1017
   750
              _p == 1
yann@1017
   751
              $0 == "}" { _p = 1; }
yann@1017
   752
              ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
yann@738
   753
                           /^(UID|EUID)=/d;
yann@738
   754
                           /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
yann@121
   755
yann@1272
   756
    CT_DoLog DEBUG "  Saving CT_CONFIG_DIR='${CT_CONFIG_DIR}'"
yann@1272
   757
    CT_Pushd "${CT_CONFIG_DIR}"
yann@1272
   758
    CT_DoExecLog DEBUG tar cv${tar_opt}f "${state_dir}/config_dir.tar${tar_ext}" .
yann@1272
   759
    CT_Popd
yann@1272
   760
yann@523
   761
    CT_DoLog DEBUG "  Saving CT_CC_CORE_STATIC_PREFIX_DIR='${CT_CC_CORE_STATIC_PREFIX_DIR}'"
yann@136
   762
    CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@776
   763
    CT_DoExecLog DEBUG tar cv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" .
yann@136
   764
    CT_Popd
yann@136
   765
yann@523
   766
    CT_DoLog DEBUG "  Saving CT_CC_CORE_SHARED_PREFIX_DIR='${CT_CC_CORE_SHARED_PREFIX_DIR}'"
yann@136
   767
    CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
yann@776
   768
    CT_DoExecLog DEBUG tar cv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" .
yann@121
   769
    CT_Popd
yann@121
   770
yann@523
   771
    CT_DoLog DEBUG "  Saving CT_PREFIX_DIR='${CT_PREFIX_DIR}'"
yann@121
   772
    CT_Pushd "${CT_PREFIX_DIR}"
yann@776
   773
    CT_DoExecLog DEBUG tar cv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" --exclude '*.log' .
yann@121
   774
    CT_Popd
yann@121
   775
yann@121
   776
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
   777
        CT_DoLog DEBUG "  Saving log file"
yann@121
   778
        exec >/dev/null
yann@121
   779
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
   780
            y)  gzip -3 -c "${CT_LOG_FILE}"  >"${state_dir}/log.gz";;
yann@121
   781
            *)  cat "${CT_LOG_FILE}" >"${state_dir}/log";;
yann@121
   782
        esac
yann@121
   783
        exec >>"${CT_LOG_FILE}"
yann@121
   784
    fi
yann@121
   785
}
yann@121
   786
yann@136
   787
# This function restores a previously saved state
yann@121
   788
# Usage: CT_DoLoadState <state_name>
yann@121
   789
CT_DoLoadState(){
yann@121
   790
    local state_name="$1"
yann@121
   791
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@135
   792
    local old_RESTART="${CT_RESTART}"
yann@135
   793
    local old_STOP="${CT_STOP}"
yann@121
   794
yann@523
   795
    CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
yann@141
   796
yann@121
   797
    # We need to do something special with the log file!
yann@121
   798
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
   799
        exec >"${state_dir}/tail.log"
yann@121
   800
    fi
yann@1266
   801
yann@1266
   802
    # Log this to the log level required by the user
yann@1266
   803
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
yann@121
   804
yann@121
   805
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@327
   806
        y)  tar_opt=z; tar_ext=.gz;;
yann@327
   807
        *)  tar_opt=;  tar_ext=;;
yann@121
   808
    esac
yann@121
   809
yann@121
   810
    CT_DoLog DEBUG "  Removing previous build directories"
yann@1272
   811
    CT_DoForceRmdir             "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}" "${CT_CONFIG_DIR}"
yann@1272
   812
    CT_DoExecLog DEBUG mkdir -p "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}" "${CT_CONFIG_DIR}"
yann@121
   813
yann@523
   814
    CT_DoLog DEBUG "  Restoring CT_PREFIX_DIR='${CT_PREFIX_DIR}'"
yann@121
   815
    CT_Pushd "${CT_PREFIX_DIR}"
yann@776
   816
    CT_DoExecLog DEBUG tar xv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}"
yann@121
   817
    CT_Popd
yann@121
   818
yann@523
   819
    CT_DoLog DEBUG "  Restoring CT_CC_CORE_SHARED_PREFIX_DIR='${CT_CC_CORE_SHARED_PREFIX_DIR}'"
yann@136
   820
    CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
yann@776
   821
    CT_DoExecLog DEBUG tar xv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}"
yann@136
   822
    CT_Popd
yann@136
   823
yann@523
   824
    CT_DoLog DEBUG "  Restoring CT_CC_CORE_STATIC_PREFIX_DIR='${CT_CC_CORE_STATIC_PREFIX_DIR}'"
yann@136
   825
    CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@776
   826
    CT_DoExecLog DEBUG tar xv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}"
yann@121
   827
    CT_Popd
yann@121
   828
yann@1272
   829
    CT_DoLog DEBUG "  Restoring CT_CONFIG_DIR='${CT_CONFIG_DIR}'"
yann@1272
   830
    CT_Pushd "${CT_CONFIG_DIR}"
yann@1272
   831
    CT_DoExecLog DEBUG tar xv${tar_opt}f "${state_dir}/config_dir.tar${tar_ext}"
yann@1272
   832
    CT_Popd
yann@1272
   833
yann@121
   834
    # Restore the environment, discarding any error message
yann@121
   835
    # (for example, read-only bash internals)
yann@121
   836
    CT_DoLog DEBUG "  Restoring environment"
yann@121
   837
    . "${state_dir}/env.sh" >/dev/null 2>&1 || true
yann@121
   838
yann@135
   839
    # Restore the new RESTART and STOP steps
yann@135
   840
    CT_RESTART="${old_RESTART}"
yann@135
   841
    CT_STOP="${old_STOP}"
yann@135
   842
    unset old_stop old_restart
yann@135
   843
yann@121
   844
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
   845
        CT_DoLog DEBUG "  Restoring log file"
yann@121
   846
        exec >/dev/null
yann@121
   847
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
   848
            y)  zcat "${state_dir}/log.gz" >"${CT_LOG_FILE}";;
yann@121
   849
            *)  cat "${state_dir}/log" >"${CT_LOG_FILE}";;
yann@121
   850
        esac
yann@121
   851
        cat "${state_dir}/tail.log" >>"${CT_LOG_FILE}"
yann@121
   852
        exec >>"${CT_LOG_FILE}"
yann@121
   853
        rm -f "${state_dir}/tail.log"
yann@121
   854
    fi
yann@121
   855
}