scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Fri Sep 04 17:27:16 2009 +0200 (2009-09-04)
changeset 1512 439a6b292917
parent 1508 7eeeaf4bc78a
child 1516 df99f43e9db7
permissions -rw-r--r--
TODO: update

Add TODO list for m4, autoconf, automake and libtool.
Building our own versions would remove burden from the users
who have older versions on their distributions, and are not
ready/able/allowed to upgrade.
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@1414
    82
        printf "${@}\n"
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@1391
   268
# Add the specified directory to LD_LIBRARY_PATH, and export it
yann@1391
   269
# If the specified patch is already present, just export
yann@1391
   270
# $1: path to add
yann@1391
   271
# $2: add as 'first' or 'last' path, 'first' is assumed if $2 is empty
yann@1391
   272
# Usage CT_SetLibPath /some/where/lib [first|last]
yann@1391
   273
CT_SetLibPath() {
yann@1391
   274
    local path="$1"
yann@1391
   275
    local pos="$2"
yann@1391
   276
yann@1391
   277
    case ":${LD_LIBRARY_PATH}:" in
yann@1391
   278
        *:"${path}":*)  ;;
yann@1391
   279
        *)  case "${pos}" in
yann@1391
   280
                last)
yann@1391
   281
                    CT_DoLog DEBUG "Adding '${path}' at end of LD_LIBRARY_PATH"
yann@1391
   282
                    LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${path}"
yann@1391
   283
                    ;;
yann@1391
   284
                first|"")
yann@1391
   285
                    CT_DoLog DEBUG "Adding '${path}' at start of LD_LIBRARY_PATH"
yann@1391
   286
                    LD_LIBRARY_PATH="${path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
yann@1391
   287
                    ;;
yann@1391
   288
                *)
yann@1391
   289
                    CT_Abort "Incorrect position '${pos}' to add '${path}' to LD_LIBRARY_PATH"
yann@1391
   290
                    ;;
yann@1391
   291
            esac
yann@1391
   292
            ;;
yann@1391
   293
    esac
yann@1391
   294
    CT_DoLog DEBUG "==> LD_LIBRARY_PATH='${LD_LIBRARY_PATH}'"
yann@1391
   295
    export LD_LIBRARY_PATH
yann@1391
   296
}
yann@1391
   297
yann@85
   298
# Get the file name extension of a component
yann@719
   299
# Usage: CT_GetFileExtension <component_name-component_version> [extension]
yann@85
   300
# If found, echoes the extension to stdout
yann@85
   301
# If not found, echoes nothing on stdout.
yann@85
   302
CT_GetFileExtension() {
yann@85
   303
    local ext
yann@85
   304
    local file="$1"
yann@719
   305
    shift
yann@719
   306
    local first_ext="$1"
yann@85
   307
yann@160
   308
    # we need to also check for an empty extension for those very
yann@160
   309
    # peculiar components that don't have one (such as sstrip from
yann@160
   310
    # buildroot).
yann@719
   311
    for ext in ${first_ext} .tar.gz .tar.bz2 .tgz .tar ''; do
yann@1123
   312
        if [ -f "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
yann@85
   313
            echo "${ext}"
yann@85
   314
            break
yann@85
   315
        fi
yann@85
   316
    done
yann@85
   317
yann@85
   318
    return 0
yann@85
   319
}
yann@85
   320
yann@63
   321
# Download an URL using wget
yann@63
   322
# Usage: CT_DoGetFileWget <URL>
yann@63
   323
CT_DoGetFileWget() {
yann@63
   324
    # Need to return true because it is legitimate to not find the tarball at
yann@63
   325
    # some of the provided URLs (think about snapshots, different layouts for
yann@63
   326
    # different gcc versions, etc...)
yann@63
   327
    # Some (very old!) FTP server might not support the passive mode, thus
yann@63
   328
    # retry without
yann@63
   329
    # With automated download as we are doing, it can be very dangerous to use
yann@63
   330
    # -c to continue the downloads. It's far better to simply overwrite the
yann@63
   331
    # destination file
yann@492
   332
    # Some company networks have firewalls to connect to the internet, but it's
yann@1113
   333
    # not easy to detect them, and wget does not timeout by default while
yann@492
   334
    # connecting, so force a global ${CT_CONNECT_TIMEOUT}-second timeout.
yann@1257
   335
    CT_DoExecLog ALL wget -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary --tries=3 --passive-ftp "$1"    \
yann@1257
   336
    || CT_DoExecLog ALL wget -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary --tries=3 "$1"               \
yann@439
   337
    || true
yann@63
   338
}
yann@63
   339
yann@63
   340
# Download an URL using curl
yann@63
   341
# Usage: CT_DoGetFileCurl <URL>
yann@63
   342
CT_DoGetFileCurl() {
yann@492
   343
    # Note: comments about wget method (above) are also valid here
yann@439
   344
    # Plus: no good progress indicator is available with curl,
yann@1257
   345
    #       so, be silent.
yann@1257
   346
    CT_DoExecLog ALL curl -s --ftp-pasv -O --retry 3 "$1" --connect-timeout ${CT_CONNECT_TIMEOUT}    \
yann@1257
   347
    || CT_DoExecLog ALL curl -s -O --retry 3 "$1" --connect-timeout ${CT_CONNECT_TIMEOUT}            \
yann@439
   348
    || true
yann@63
   349
}
yann@63
   350
yann@523
   351
_wget=$(CT_Which wget)
yann@523
   352
_curl=$(CT_Which curl)
yann@63
   353
# Wrapper function to call one of curl or wget
yann@63
   354
# Usage: CT_DoGetFile <URL>
yann@63
   355
CT_DoGetFile() {
yann@63
   356
    case "${_wget},${_curl}" in
yann@1120
   357
        ,)  CT_Abort "Could find neither wget nor curl";;
yann@1257
   358
        ,*) CT_DoGetFileCurl "$1";;
yann@1257
   359
        *)  CT_DoGetFileWget "$1";;
yann@63
   360
    esac
yann@63
   361
}
yann@63
   362
yann@1113
   363
# This function tries to retrieve a tarball form a local directory
yann@1113
   364
# Usage: CT_GetLocal <basename> [.extension]
yann@1113
   365
CT_GetLocal() {
yann@1113
   366
    local basename="$1"
yann@1113
   367
    local first_ext="$2"
yann@1113
   368
    local ext
yann@1113
   369
yann@1113
   370
    # Do we already have it in *our* tarballs dir?
yann@1113
   371
    ext=$(CT_GetFileExtension "${basename}" ${first_ext})
yann@1113
   372
    if [ -n "${ext}" ]; then
yann@1113
   373
        CT_DoLog DEBUG "Already have '${basename}'"
yann@1113
   374
        return 0
yann@1113
   375
    fi
yann@1113
   376
yann@1113
   377
    if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
yann@1113
   378
        CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
yann@1113
   379
        # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
yann@1113
   380
        # or, as a failover, a file without extension.
yann@1113
   381
        for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@1113
   382
            CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
yann@1113
   383
            if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
yann@1113
   384
                 "${CT_FORCE_DOWNLOAD}" != "y" ]; then
yann@1113
   385
                CT_DoLog DEBUG "Got '${basename}' from local storage"
yann@1113
   386
                CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1113
   387
                return 0
yann@1113
   388
            fi
yann@1113
   389
        done
yann@1113
   390
    fi
yann@1113
   391
    return 1
yann@1113
   392
}
yann@1113
   393
yann@1113
   394
# This function saves the specified to local storage if possible,
yann@1113
   395
# and if so, symlinks it for later usage
yann@1113
   396
# Usage: CT_SaveLocal </full/path/file.name>
yann@1113
   397
CT_SaveLocal() {
yann@1113
   398
    local file="$1"
yann@1113
   399
    local basename="${file##*/}"
yann@1113
   400
yann@1113
   401
    if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
yann@1134
   402
        CT_DoLog EXTRA "Saving '${basename}' to local storage"
yann@1113
   403
        # The file may already exist if downloads are forced: remove it first
yann@1113
   404
        CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
yann@1113
   405
        CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
yann@1113
   406
        CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
yann@1113
   407
    fi
yann@1113
   408
}
yann@1113
   409
yann@63
   410
# Download the file from one of the URLs passed as argument
yann@1113
   411
# Usage: CT_GetFile <basename> [.extension] <url> [url ...]
yann@63
   412
CT_GetFile() {
yann@63
   413
    local ext
yann@1179
   414
    local url URLS LAN_URLS
yann@63
   415
    local file="$1"
yann@1113
   416
    local first_ext
yann@63
   417
    shift
yann@712
   418
    # If next argument starts with a dot, then this is not an URL,
yann@712
   419
    # and we can consider that it is a preferred extension.
yann@242
   420
    case "$1" in
yann@712
   421
        .*) first_ext="$1"
yann@242
   422
            shift
yann@242
   423
            ;;
yann@242
   424
    esac
yann@63
   425
yann@1113
   426
    # Does it exist localy?
yann@1113
   427
    CT_GetLocal "${file}" ${first_ext} && return 0 || true
yann@1113
   428
    # No, it does not...
yann@63
   429
yann@1131
   430
    # Are downloads allowed ?
yann@1131
   431
    CT_TestAndAbort "File '${file}' not present locally, and downloads are not allowed" "${CT_FORBID_DOWNLOAD}" = "y"
yann@1131
   432
yann@754
   433
    # Try to retrieve the file
yann@788
   434
    CT_DoLog EXTRA "Retrieving '${file}'"
yann@63
   435
    CT_Pushd "${CT_TARBALLS_DIR}"
yann@754
   436
yann@1179
   437
    URLS="$@"
yann@1179
   438
yann@1022
   439
    # Add URLs on the LAN mirror
yann@1022
   440
    LAN_URLS=
yann@1022
   441
    if [ "${CT_USE_MIRROR}" = "y" ]; then
yann@1294
   442
        CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
yann@1294
   443
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}/${file%-*}"
yann@1294
   444
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}"
yann@695
   445
yann@1134
   446
        if [ "${CT_PREFER_MIRROR}" = "y" ]; then
yann@1134
   447
            CT_DoLog DEBUG "Pre-pending LAN mirror URLs"
yann@1179
   448
            URLS="${LAN_URLS} ${URLS}"
yann@1134
   449
        else
yann@1134
   450
            CT_DoLog DEBUG "Appending LAN mirror URLs"
yann@1179
   451
            URLS="${URLS} ${LAN_URLS}"
yann@1134
   452
        fi
yann@1022
   453
    fi
yann@1022
   454
yann@1022
   455
    # Scan all URLs in turn, and try to grab a tarball from there
yann@242
   456
    for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@102
   457
        # Try all urls in turn
yann@1022
   458
        for url in ${URLS}; do
yann@523
   459
            CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
yann@265
   460
            CT_DoGetFile "${url}/${file}${ext}"
yann@265
   461
            if [ -f "${file}${ext}" ]; then
yann@799
   462
                CT_DoLog DEBUG "Got '${file}' from the Internet"
yann@1113
   463
                CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
yann@265
   464
                return 0
yann@265
   465
            fi
yann@102
   466
        done
yann@102
   467
    done
yann@63
   468
    CT_Popd
yann@63
   469
yann@754
   470
    CT_Abort "Could not retrieve '${file}'."
yann@63
   471
}
yann@63
   472
yann@1113
   473
# Checkout from CVS, and build the associated tarball
yann@1113
   474
# The tarball will be called ${basename}.tar.bz2
yann@1113
   475
# Prerequisite: either the server does not require password,
yann@1113
   476
# or the user must already be logged in.
yann@1113
   477
# 'tag' is the tag to retrieve. Must be specified, but can be empty.
yann@1113
   478
# If dirname is specified, then module will be renamed to dirname
yann@1113
   479
# prior to building the tarball.
yann@1113
   480
# Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname]
yann@1113
   481
CT_GetCVS() {
yann@1113
   482
    local basename="$1"
yann@1113
   483
    local uri="$2"
yann@1113
   484
    local module="$3"
yann@1113
   485
    local tag="${4:+-r ${4}}"
yann@1113
   486
    local dirname="$5"
yann@1113
   487
    local tmp_dir
yann@1113
   488
yann@1113
   489
    # Does it exist localy?
yann@1113
   490
    CT_GetLocal "${basename}" && return 0 || true
yann@1113
   491
    # No, it does not...
yann@1113
   492
yann@1131
   493
    # Are downloads allowed ?
yann@1244
   494
    CT_TestAndAbort "File '${basename}' not present locally, and downloads are not allowed" "${CT_FORBID_DOWNLOAD}" = "y"
yann@1131
   495
yann@1113
   496
    CT_DoLog EXTRA "Retrieving '${basename}'"
yann@1113
   497
yann@1113
   498
    CT_MktempDir tmp_dir
yann@1113
   499
    CT_Pushd "${tmp_dir}"
yann@1113
   500
yann@1113
   501
    CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
yann@1113
   502
    [ -n "${dirname}" ] && CT_DoExecLog ALL mv "${module}" "${dirname}"
yann@1113
   503
    CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
yann@1113
   504
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1113
   505
yann@1113
   506
    CT_Popd
yann@1113
   507
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1113
   508
}
yann@1113
   509
yann@1244
   510
# Check out from SVN, and build the associated tarball
yann@1244
   511
# The tarball will be called ${basename}.tar.bz2
yann@1244
   512
# Prerequisite: either the server does not require password,
yann@1244
   513
# or the user must already be logged in.
yann@1244
   514
# 'rev' is the revision to retrieve
yann@1244
   515
# Usage: CT_GetSVN <basename> <url> [rev]
yann@1244
   516
CT_GetSVN() {
yann@1244
   517
    local basename="$1"
yann@1244
   518
    local uri="$2"
yann@1244
   519
    local rev="$3"
yann@1244
   520
yann@1244
   521
    # Does it exist localy?
yann@1244
   522
    CT_GetLocal "${basename}" && return 0 || true
yann@1244
   523
    # No, it does not...
yann@1244
   524
yann@1244
   525
    # Are downloads allowed ?
yann@1244
   526
    CT_TestAndAbort "File '${basename}' not present locally, and downloads are not allowed" "${CT_FORBID_DOWNLOAD}" = "y"
yann@1244
   527
yann@1244
   528
    CT_DoLog EXTRA "Retrieving '${basename}'"
yann@1244
   529
yann@1244
   530
    CT_MktempDir tmp_dir
yann@1244
   531
    CT_Pushd "${tmp_dir}"
yann@1244
   532
yann@1244
   533
    CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"
yann@1244
   534
    CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
yann@1244
   535
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1244
   536
yann@1244
   537
    CT_Popd
yann@1244
   538
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1244
   539
}
yann@1244
   540
yann@1126
   541
# Extract a tarball
yann@63
   542
# Some tarballs need to be extracted in specific places. Eg.: glibc addons
yann@63
   543
# must be extracted in the glibc directory; uCLibc locales must be extracted
yann@1123
   544
# in the extra/locale sub-directory of uClibc. This is taken into account
yann@1123
   545
# by the caller, that did a 'cd' into the correct path before calling us
yann@1123
   546
# and sets nochdir to 'nochdir'.
yann@1126
   547
# Usage: CT_Extract <basename> [nochdir]
yann@1126
   548
CT_Extract() {
yann@1126
   549
    local basename="$1"
yann@1123
   550
    local nochdir="$2"
yann@1126
   551
    local ext=$(CT_GetFileExtension "${basename}")
yann@1126
   552
    CT_TestAndAbort "'${basename}' not found in '${CT_TARBALLS_DIR}'" -z "${ext}"
yann@1126
   553
    local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1126
   554
yann@1126
   555
    # Check if already extracted
yann@1126
   556
    if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
yann@1126
   557
        CT_DoLog DEBUG "Already extracted '${basename}'"
yann@1126
   558
        return 0
yann@1126
   559
    fi
yann@63
   560
yann@1123
   561
    [ "${nochdir}" = "nochdir" ] || CT_Pushd "${CT_SRC_DIR}"
yann@63
   562
yann@1126
   563
    CT_DoLog EXTRA "Extracting '${basename}'"
yann@63
   564
    case "${ext}" in
yann@776
   565
        .tar.bz2)     CT_DoExecLog ALL tar xvjf "${full_file}";;
yann@776
   566
        .tar.gz|.tgz) CT_DoExecLog ALL tar xvzf "${full_file}";;
yann@776
   567
        .tar)         CT_DoExecLog ALL tar xvf  "${full_file}";;
yann@1126
   568
        *)            CT_Abort "Don't know how to handle '${basename}${ext}': unknown extension" ;;
yann@63
   569
    esac
yann@63
   570
yann@1208
   571
    # Some tarballs have read-only files... :-(
yann@1258
   572
    # Because of nochdir, we don't know where we are, so chmod all
yann@1258
   573
    # the src tree
yann@1271
   574
    CT_DoExecLog DEBUG chmod -R u+w "${CT_SRC_DIR}"
yann@1208
   575
yann@1271
   576
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted"
yann@1126
   577
yann@1126
   578
    [ "${nochdir}" = "nochdir" ] || CT_Popd
yann@1126
   579
}
yann@1126
   580
yann@1126
   581
# Patches the specified component
yann@1126
   582
# Usage: CT_Patch <basename> [nochdir]
yann@1126
   583
CT_Patch() {
yann@1126
   584
    local basename="$1"
yann@1126
   585
    local nochdir="$2"
yann@1126
   586
    local base_file="${basename%%-*}"
yann@1126
   587
    local ver_file="${basename#*-}"
yann@1507
   588
    local d
yann@1507
   589
    local -a patch_dirs
yann@1507
   590
    local bundled_patch_dir
yann@1507
   591
    local local_patch_dir
yann@1126
   592
yann@1126
   593
    # Check if already patched
yann@1126
   594
    if [ -e "${CT_SRC_DIR}/.${basename}.patched" ]; then
yann@1126
   595
        CT_DoLog DEBUG "Already patched '${basename}'"
yann@1126
   596
        return 0
yann@63
   597
    fi
yann@63
   598
yann@1271
   599
    # Check if already partially patched
yann@1271
   600
    if [ -e "${CT_SRC_DIR}/.${basename}.patching" ]; then
yann@1271
   601
        CT_DoLog ERROR "The '${basename}' sources were partially patched."
yann@1271
   602
        CT_DoLog ERROR "Please remove first:"
yann@1271
   603
        CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
yann@1271
   604
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracted'"
yann@1271
   605
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.patching'"
yann@1271
   606
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1271
   607
    fi
yann@1271
   608
    touch "${CT_SRC_DIR}/.${basename}.patching"
yann@1271
   609
yann@1126
   610
    [ "${nochdir}" = "nochdir" ] || CT_Pushd "${CT_SRC_DIR}/${basename}"
yann@1123
   611
yann@1126
   612
    CT_DoLog EXTRA "Patching '${basename}'"
yann@63
   613
yann@1507
   614
    bundled_patch_dir="${CT_LIB_DIR}/patches/${base_file}/${ver_file}"
yann@1507
   615
    local_patch_dir="${CT_CUSTOM_PATCH_DIR}/${base_file}/${ver_file}"
yann@1507
   616
yann@1507
   617
    case "${CT_PATCH_ORDER}" in
yann@1507
   618
        bundled)        patch_dirs=("${bundled_patch_dir}");;
yann@1507
   619
        local)          patch_dirs=("${local_patch_dir}");;
yann@1507
   620
        bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
yann@1508
   621
        local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
yann@1507
   622
    esac
yann@1507
   623
yann@1507
   624
    for d in "${patch_dirs[@]}"; do
yann@1507
   625
        CT_DoLog DEBUG "Looking for patches in '${d}'..."
yann@1507
   626
        if [ -n "${d}" -a -d "${d}" ]; then
yann@1507
   627
            for p in "${d}"/*.patch; do
yann@63
   628
                if [ -f "${p}" ]; then
yann@523
   629
                    CT_DoLog DEBUG "Applying patch '${p}'"
yann@776
   630
                    CT_DoExecLog ALL patch -g0 -F1 -p1 -f <"${p}"
yann@63
   631
                fi
yann@63
   632
            done
yann@1509
   633
            if [ "${CT_PATCH_SINGLE}" = "y" ]; then
yann@1509
   634
                break
yann@1509
   635
            fi
yann@63
   636
        fi
yann@63
   637
    done
yann@63
   638
yann@508
   639
    if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
yann@508
   640
        CT_DoLog ALL "Overiding config.guess and config.sub"
yann@508
   641
        for cfg in config_guess config_sub; do
yann@1101
   642
            eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
yann@1101
   643
            [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
yann@776
   644
            # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
yann@508
   645
            find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
yann@508
   646
        done
yann@508
   647
    fi
yann@508
   648
yann@1271
   649
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.patching"
yann@1271
   650
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.patched"
yann@1126
   651
yann@1123
   652
    [ "${nochdir}" = "nochdir" ] || CT_Popd
yann@63
   653
}
yann@63
   654
yann@182
   655
# Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
yann@182
   656
# Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
yann@182
   657
CT_DoConfigGuess() {
yann@1101
   658
    if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
yann@1101
   659
        "${CT_TOP_DIR}/scripts/config.guess"
yann@182
   660
    else
yann@1101
   661
        "${CT_LIB_DIR}/scripts/config.guess"
yann@182
   662
    fi
yann@182
   663
}
yann@182
   664
yann@182
   665
CT_DoConfigSub() {
yann@1101
   666
    if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
yann@1101
   667
        "${CT_TOP_DIR}/scripts/config.sub" "$@"
yann@182
   668
    else
yann@1101
   669
        "${CT_LIB_DIR}/scripts/config.sub" "$@"
yann@182
   670
    fi
yann@182
   671
}
yann@182
   672
yann@335
   673
# Compute the target tuple from what is provided by the user
yann@335
   674
# Usage: CT_DoBuildTargetTuple
yann@63
   675
# In fact this function takes the environment variables to build the target
yann@335
   676
# tuple. It is needed both by the normal build sequence, as well as the
yann@63
   677
# sample saving sequence.
yann@335
   678
CT_DoBuildTargetTuple() {
yann@383
   679
    # Set the endianness suffix, and the default endianness gcc option
yann@63
   680
    case "${CT_ARCH_BE},${CT_ARCH_LE}" in
yann@383
   681
        y,) target_endian_eb=eb
yann@383
   682
            target_endian_el=
yann@391
   683
            CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
yann@527
   684
            CT_ARCH_ENDIAN_LDFLAG="-EB"
yann@383
   685
            ;;
yann@383
   686
        ,y) target_endian_eb=
yann@383
   687
            target_endian_el=el
yann@391
   688
            CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
yann@527
   689
            CT_ARCH_ENDIAN_LDFLAG="-EL"
yann@383
   690
            ;;
yann@63
   691
    esac
yann@383
   692
yann@965
   693
    # Build the default architecture tuple part
yann@965
   694
    CT_TARGET_ARCH="${CT_ARCH}"
yann@965
   695
yann@383
   696
    # Set defaults for the system part of the tuple. Can be overriden
yann@383
   697
    # by architecture-specific values.
yann@383
   698
    case "${CT_LIBC}" in
yann@850
   699
        none)   CT_TARGET_SYS=elf;;
yann@787
   700
        *glibc) CT_TARGET_SYS=gnu;;
yann@383
   701
        uClibc) CT_TARGET_SYS=uclibc;;
yann@63
   702
    esac
yann@383
   703
yann@387
   704
    # Transform the ARCH into a kernel-understandable ARCH
yann@387
   705
    CT_KERNEL_ARCH="${CT_ARCH}"
yann@387
   706
yann@391
   707
    # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
yann@497
   708
    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
   709
    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
   710
    [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
yann@391
   711
    [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
yann@391
   712
    [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
yann@405
   713
    [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
yann@391
   714
    [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
yann@412
   715
    [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float";           CT_ARCH_WITH_FLOAT="--with-float=soft";          }
yann@391
   716
yann@965
   717
    # Build the default kernel tuple part
yann@965
   718
    CT_TARGET_KERNEL="${CT_KERNEL}"
yann@964
   719
yann@965
   720
    # Overide the default values with the components specific settings
yann@964
   721
    CT_DoArchTupleValues
yann@965
   722
    CT_DoKernelTupleValues
yann@383
   723
yann@391
   724
    # Finish the target tuple construction
yann@1094
   725
    CT_TARGET="${CT_TARGET_ARCH}-${CT_TARGET_VENDOR:-unknown}-${CT_TARGET_KERNEL}${CT_TARGET_KERNEL:+-}${CT_TARGET_SYS}"
yann@1094
   726
yann@1094
   727
    # Sanity checks
yann@1094
   728
    __sed_alias=""
yann@1094
   729
    if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
yann@1094
   730
        __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
yann@1094
   731
    fi
yann@1094
   732
    case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
yann@1094
   733
      :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
yann@1094
   734
      :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
yann@1094
   735
      :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
yann@1094
   736
      :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
yann@1094
   737
    esac
yann@1094
   738
yann@1094
   739
    # Canonicalise it
yann@1094
   740
    CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
yann@391
   741
yann@391
   742
    # Prepare the target CFLAGS
yann@767
   743
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
yann@527
   744
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
yann@397
   745
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
yann@397
   746
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
yann@397
   747
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
yann@397
   748
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
yann@397
   749
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
yann@527
   750
yann@527
   751
    # Now on for the target LDFLAGS
yann@767
   752
    CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
yann@63
   753
}
yann@121
   754
yann@121
   755
# This function does pause the build until the user strikes "Return"
yann@121
   756
# Usage: CT_DoPause [optional_message]
yann@121
   757
CT_DoPause() {
yann@121
   758
    local foo
yann@121
   759
    local message="${1:-Pausing for your pleasure}"
yann@121
   760
    CT_DoLog INFO "${message}"
yann@523
   761
    read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
yann@121
   762
    return 0
yann@121
   763
}
yann@121
   764
yann@121
   765
# This function saves the state of the toolchain to be able to restart
yann@121
   766
# at any one point
yann@121
   767
# Usage: CT_DoSaveState <next_step_name>
yann@121
   768
CT_DoSaveState() {
yann@121
   769
	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
yann@121
   770
    local state_name="$1"
yann@121
   771
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@121
   772
yann@1266
   773
    # Log this to the log level required by the user
yann@1266
   774
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
yann@1134
   775
yann@121
   776
    rm -rf "${state_dir}"
yann@121
   777
    mkdir -p "${state_dir}"
yann@121
   778
yann@121
   779
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@327
   780
        y)  tar_opt=z; tar_ext=.gz;;
yann@327
   781
        *)  tar_opt=;  tar_ext=;;
yann@121
   782
    esac
yann@121
   783
yann@121
   784
    CT_DoLog DEBUG "  Saving environment and aliases"
yann@738
   785
    # We must omit shell functions, and some specific bash variables
yann@738
   786
    # that break when restoring the environment, later. We could do
yann@1299
   787
    # all the processing in the awk script, but a sed is easier...
yann@1299
   788
    set |awk '
yann@1017
   789
              BEGIN { _p = 1; }
yann@1017
   790
              $0~/^[^ ]+ \(\)/ { _p = 0; }
yann@1017
   791
              _p == 1
yann@1017
   792
              $0 == "}" { _p = 1; }
yann@1017
   793
              ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
yann@738
   794
                           /^(UID|EUID)=/d;
yann@738
   795
                           /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
yann@121
   796
yann@1272
   797
    CT_DoLog DEBUG "  Saving CT_CONFIG_DIR='${CT_CONFIG_DIR}'"
yann@1272
   798
    CT_Pushd "${CT_CONFIG_DIR}"
yann@1272
   799
    CT_DoExecLog DEBUG tar cv${tar_opt}f "${state_dir}/config_dir.tar${tar_ext}" .
yann@1272
   800
    CT_Popd
yann@1272
   801
yann@523
   802
    CT_DoLog DEBUG "  Saving CT_CC_CORE_STATIC_PREFIX_DIR='${CT_CC_CORE_STATIC_PREFIX_DIR}'"
yann@136
   803
    CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@776
   804
    CT_DoExecLog DEBUG tar cv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}" .
yann@136
   805
    CT_Popd
yann@136
   806
yann@523
   807
    CT_DoLog DEBUG "  Saving CT_CC_CORE_SHARED_PREFIX_DIR='${CT_CC_CORE_SHARED_PREFIX_DIR}'"
yann@136
   808
    CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
yann@776
   809
    CT_DoExecLog DEBUG tar cv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}" .
yann@121
   810
    CT_Popd
yann@121
   811
yann@523
   812
    CT_DoLog DEBUG "  Saving CT_PREFIX_DIR='${CT_PREFIX_DIR}'"
yann@121
   813
    CT_Pushd "${CT_PREFIX_DIR}"
yann@776
   814
    CT_DoExecLog DEBUG tar cv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}" --exclude '*.log' .
yann@121
   815
    CT_Popd
yann@121
   816
yann@121
   817
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
   818
        CT_DoLog DEBUG "  Saving log file"
yann@121
   819
        exec >/dev/null
yann@121
   820
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
   821
            y)  gzip -3 -c "${CT_LOG_FILE}"  >"${state_dir}/log.gz";;
yann@121
   822
            *)  cat "${CT_LOG_FILE}" >"${state_dir}/log";;
yann@121
   823
        esac
yann@121
   824
        exec >>"${CT_LOG_FILE}"
yann@121
   825
    fi
yann@121
   826
}
yann@121
   827
yann@136
   828
# This function restores a previously saved state
yann@121
   829
# Usage: CT_DoLoadState <state_name>
yann@121
   830
CT_DoLoadState(){
yann@121
   831
    local state_name="$1"
yann@121
   832
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@135
   833
    local old_RESTART="${CT_RESTART}"
yann@135
   834
    local old_STOP="${CT_STOP}"
yann@121
   835
yann@523
   836
    CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
yann@141
   837
yann@121
   838
    # We need to do something special with the log file!
yann@121
   839
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
   840
        exec >"${state_dir}/tail.log"
yann@121
   841
    fi
yann@1266
   842
yann@1266
   843
    # Log this to the log level required by the user
yann@1266
   844
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
yann@121
   845
yann@121
   846
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@327
   847
        y)  tar_opt=z; tar_ext=.gz;;
yann@327
   848
        *)  tar_opt=;  tar_ext=;;
yann@121
   849
    esac
yann@121
   850
yann@121
   851
    CT_DoLog DEBUG "  Removing previous build directories"
yann@1272
   852
    CT_DoForceRmdir             "${CT_PREFIX_DIR}" "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${CT_CC_CORE_STATIC_PREFIX_DIR}" "${CT_CONFIG_DIR}"
yann@1272
   853
    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
   854
yann@523
   855
    CT_DoLog DEBUG "  Restoring CT_PREFIX_DIR='${CT_PREFIX_DIR}'"
yann@121
   856
    CT_Pushd "${CT_PREFIX_DIR}"
yann@776
   857
    CT_DoExecLog DEBUG tar xv${tar_opt}f "${state_dir}/prefix_dir.tar${tar_ext}"
yann@121
   858
    CT_Popd
yann@121
   859
yann@523
   860
    CT_DoLog DEBUG "  Restoring CT_CC_CORE_SHARED_PREFIX_DIR='${CT_CC_CORE_SHARED_PREFIX_DIR}'"
yann@136
   861
    CT_Pushd "${CT_CC_CORE_SHARED_PREFIX_DIR}"
yann@776
   862
    CT_DoExecLog DEBUG tar xv${tar_opt}f "${state_dir}/cc_core_shared_prefix_dir.tar${tar_ext}"
yann@136
   863
    CT_Popd
yann@136
   864
yann@523
   865
    CT_DoLog DEBUG "  Restoring CT_CC_CORE_STATIC_PREFIX_DIR='${CT_CC_CORE_STATIC_PREFIX_DIR}'"
yann@136
   866
    CT_Pushd "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@776
   867
    CT_DoExecLog DEBUG tar xv${tar_opt}f "${state_dir}/cc_core_static_prefix_dir.tar${tar_ext}"
yann@121
   868
    CT_Popd
yann@121
   869
yann@1272
   870
    CT_DoLog DEBUG "  Restoring CT_CONFIG_DIR='${CT_CONFIG_DIR}'"
yann@1272
   871
    CT_Pushd "${CT_CONFIG_DIR}"
yann@1272
   872
    CT_DoExecLog DEBUG tar xv${tar_opt}f "${state_dir}/config_dir.tar${tar_ext}"
yann@1272
   873
    CT_Popd
yann@1272
   874
yann@121
   875
    # Restore the environment, discarding any error message
yann@121
   876
    # (for example, read-only bash internals)
yann@121
   877
    CT_DoLog DEBUG "  Restoring environment"
yann@121
   878
    . "${state_dir}/env.sh" >/dev/null 2>&1 || true
yann@121
   879
yann@135
   880
    # Restore the new RESTART and STOP steps
yann@135
   881
    CT_RESTART="${old_RESTART}"
yann@135
   882
    CT_STOP="${old_STOP}"
yann@135
   883
    unset old_stop old_restart
yann@135
   884
yann@121
   885
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
   886
        CT_DoLog DEBUG "  Restoring log file"
yann@121
   887
        exec >/dev/null
yann@121
   888
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
   889
            y)  zcat "${state_dir}/log.gz" >"${CT_LOG_FILE}";;
yann@121
   890
            *)  cat "${state_dir}/log" >"${CT_LOG_FILE}";;
yann@121
   891
        esac
yann@121
   892
        cat "${state_dir}/tail.log" >>"${CT_LOG_FILE}"
yann@121
   893
        exec >>"${CT_LOG_FILE}"
yann@121
   894
        rm -f "${state_dir}/tail.log"
yann@121
   895
    fi
yann@121
   896
}