scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Mon Jan 03 23:40:22 2011 +0100 (2011-01-03)
changeset 2267 7af68e6083aa
parent 2204 ea1c9143e1e3
child 2280 3d480d12124e
permissions -rw-r--r--
libc-glibc: remove 2.3.6

This is an obsolete version which is no longer used by any sample (the only
user, the ia64 sample, has been removed).

It also makes the code path a bit complex, with twists just to accomodate
that version. Removing the version will make those twists go away, and
will ease commonalisation of glibc and eglibc in the future (hopefully!).

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
anthony@2155
     1
# This file contains some usefull common functions -*- sh -*-
yann@1
     2
# Copyright 2007 Yann E. MORIN
yann@1
     3
# Licensed under the GPL v2. See COPYING in the root of this package
yann@1
     4
yann@136
     5
# Prepare the fault handler
yann@1
     6
CT_OnError() {
yann@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
anthony@2154
    52
CT_LOG_LEVEL_CFG=4
anthony@2154
    53
CT_LOG_LEVEL_FILE=5
anthony@2155
    54
CT_LOG_LEVEL_STATE=6
anthony@2155
    55
CT_LOG_LEVEL_ALL=7
anthony@2155
    56
CT_LOG_LEVEL_DEBUG=8
yann@1
    57
yann@1083
    58
# Make it easy to use \n and !
yann@1081
    59
CR=$(printf "\n")
yann@1083
    60
BANG='!'
yann@1081
    61
yann@1
    62
# A function to log what is happening
yann@1
    63
# Different log level are available:
yann@1
    64
#   - ERROR:   A serious, fatal error occurred
yann@1
    65
#   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
yann@1
    66
#   - INFO:    Informational messages
yann@1
    67
#   - EXTRA:   Extra informational messages
anthony@2154
    68
#   - CFG:     Output of various "./configure"-type scripts
anthony@2154
    69
#   - FILE:    File / archive unpacking.
anthony@2155
    70
#   - STATE:   State save & restore
yann@78
    71
#   - ALL:     Component's build messages
anthony@2155
    72
#   - DEBUG:   Internal debug messages
yann@1
    73
# Usage: CT_DoLog <level> [message]
yann@1
    74
# If message is empty, then stdin will be logged.
yann@1
    75
CT_DoLog() {
yann@47
    76
    local max_level LEVEL level cur_l cur_L
yann@47
    77
    local l
yann@1
    78
    eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
yann@1
    79
    # Set the maximum log level to DEBUG if we have none
yann@78
    80
    [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
yann@1
    81
yann@47
    82
    LEVEL="$1"; shift
yann@1
    83
    eval level="\${CT_LOG_LEVEL_${LEVEL}}"
yann@1
    84
yann@1
    85
    if [ $# -eq 0 ]; then
yann@1
    86
        cat -
yann@1
    87
    else
yann@2096
    88
        printf "%s\n" "${*}"
yann@1081
    89
    fi |( IFS="${CR}" # We want the full lines, even leading spaces
yann@523
    90
          _prog_bar_cpt=0
yann@523
    91
          _prog_bar[0]='/'
yann@523
    92
          _prog_bar[1]='-'
yann@523
    93
          _prog_bar[2]='\'
yann@523
    94
          _prog_bar[3]='|'
yann@1
    95
          indent=$((2*CT_STEP_COUNT))
yann@1
    96
          while read line; do
yann@47
    97
              case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
yann@47
    98
                y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@112
    99
                y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@47
   100
                *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@919
   101
                *"make["*"]: *** ["*)   cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@47
   102
                *)                      cur_L="${LEVEL}"; cur_l="${level}";;
yann@47
   103
              esac
yann@523
   104
              # There will always be a log file (stdout, fd #1), be it /dev/null
yann@523
   105
              printf "[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}"
yann@47
   106
              if [ ${cur_l} -le ${max_level} ]; then
yann@523
   107
                  # Only print to console (fd #6) if log level is high enough.
yann@523
   108
                  printf "\r[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}" >&6
yann@82
   109
              fi
yann@82
   110
              if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
yann@523
   111
                  printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${_prog_bar[$((_prog_bar_cpt/10))]}" >&6
yann@523
   112
                  _prog_bar_cpt=$(((_prog_bar_cpt+1)%40))
yann@1
   113
              fi
yann@1
   114
          done
yann@1
   115
        )
yann@1
   116
yann@1
   117
    return 0
yann@1
   118
}
yann@1
   119
yann@535
   120
# Execute an action, and log its messages
yann@1257
   121
# Usage: [VAR=val...] CT_DoExecLog <level> <command [parameters...]>
yann@535
   122
CT_DoExecLog() {
yann@535
   123
    local level="$1"
yann@535
   124
    shift
yann@1516
   125
    CT_DoLog DEBUG "==> Executing: '${*}'"
yann@668
   126
    "${@}" 2>&1 |CT_DoLog "${level}"
yann@535
   127
}
yann@535
   128
yann@96
   129
# Tail message to be logged whatever happens
yann@96
   130
# Usage: CT_DoEnd <level>
yann@96
   131
CT_DoEnd()
yann@96
   132
{
yann@145
   133
    local level="$1"
yann@523
   134
    CT_STOP_DATE=$(CT_DoDate +%s%N)
yann@523
   135
    CT_STOP_DATE_HUMAN=$(CT_DoDate +%Y%m%d.%H%M%S)
yann@599
   136
    if [ "${level}" != "ERROR" ]; then
yann@582
   137
        CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
yann@582
   138
    fi
yann@96
   139
    elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
yann@96
   140
    elapsed_min=$((elapsed/(60*1000*1000*1000)))
yann@523
   141
    elapsed_sec=$(printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000))))
yann@523
   142
    elapsed_csec=$(printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000))))
yann@145
   143
    CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
yann@96
   144
}
yann@96
   145
yann@2051
   146
# Remove entries referring to . and other relative paths
js@2044
   147
# Usage: CT_SanitizePath
js@2044
   148
CT_SanitizePath() {
js@2044
   149
    local new
yann@2051
   150
    local p
js@2044
   151
    local IFS=:
js@2044
   152
    for p in $PATH; do
yann@2051
   153
        # Only accept absolute paths;
yann@2051
   154
        # Note: as a special case the empty string in PATH is equivalent to .
yann@2051
   155
        if [ -n "${p}" -a -z "${p%%/*}" ]; then
js@2044
   156
            new="${new}${new:+:}${p}"
js@2044
   157
        fi
js@2044
   158
    done
js@2044
   159
    PATH="${new}"
js@2044
   160
}
js@2044
   161
yann@96
   162
# Abort the execution with an error message
yann@1
   163
# Usage: CT_Abort <message>
yann@1
   164
CT_Abort() {
yann@128
   165
    CT_DoLog ERROR "$1"
yann@1
   166
    exit 1
yann@1
   167
}
yann@1
   168
yann@1
   169
# Test a condition, and print a message if satisfied
yann@1
   170
# Usage: CT_Test <message> <tests>
yann@1
   171
CT_Test() {
yann@1
   172
    local ret
yann@1
   173
    local m="$1"
yann@1
   174
    shift
yann@1909
   175
    CT_DoLog DEBUG "Testing '! ( $* )'"
yann@1
   176
    test "$@" && CT_DoLog WARN "$m"
yann@1
   177
    return 0
yann@1
   178
}
yann@1
   179
yann@1
   180
# Test a condition, and abort with an error message if satisfied
yann@1
   181
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   182
CT_TestAndAbort() {
yann@1
   183
    local m="$1"
yann@1
   184
    shift
yann@1909
   185
    CT_DoLog DEBUG "Testing '! ( $* )'"
yann@1
   186
    test "$@" && CT_Abort "$m"
yann@1
   187
    return 0
yann@1
   188
}
yann@1
   189
yann@1
   190
# Test a condition, and abort with an error message if not satisfied
yann@1
   191
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   192
CT_TestOrAbort() {
yann@1
   193
    local m="$1"
yann@1
   194
    shift
yann@1909
   195
    CT_DoLog DEBUG "Testing '$*'"
yann@1
   196
    test "$@" || CT_Abort "$m"
yann@1
   197
    return 0
yann@1
   198
}
yann@1
   199
yann@1
   200
# Test the presence of a tool, or abort if not found
yann@1
   201
# Usage: CT_HasOrAbort <tool>
yann@1
   202
CT_HasOrAbort() {
yann@773
   203
    CT_TestAndAbort "'${1}' not found and needed for successful toolchain build." -z "$(CT_Which "${1}")"
yann@1
   204
    return 0
yann@1
   205
}
yann@1
   206
yann@210
   207
# Search a program: wrap "which" for those system where
yann@1226
   208
# "which" verbosely says there is no match (Mandriva is
yann@1226
   209
# such a sucker...)
yann@210
   210
# Usage: CT_Which <filename>
yann@210
   211
CT_Which() {
yann@210
   212
  which "$1" 2>/dev/null || true
yann@210
   213
}
yann@210
   214
yann@1
   215
# Get current date with nanosecond precision
yann@1
   216
# On those system not supporting nanosecond precision, faked with rounding down
yann@1
   217
# to the highest entire second
yann@1
   218
# Usage: CT_DoDate <fmt>
yann@1
   219
CT_DoDate() {
tvb377@1798
   220
    date "$1" |sed -r -e 's/N$/000000000/;'
yann@1
   221
}
yann@1
   222
yann@1
   223
CT_STEP_COUNT=1
yann@1
   224
CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
yann@1
   225
# Memorise a step being done so that any error is caught
yann@1
   226
# Usage: CT_DoStep <loglevel> <message>
yann@1
   227
CT_DoStep() {
yann@523
   228
    local start=$(CT_DoDate +%s%N)
yann@1
   229
    CT_DoLog "$1" "================================================================="
yann@1
   230
    CT_DoLog "$1" "$2"
yann@1
   231
    CT_STEP_COUNT=$((CT_STEP_COUNT+1))
yann@1
   232
    CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
yann@1
   233
    CT_STEP_START[${CT_STEP_COUNT}]="${start}"
yann@1
   234
    CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
yann@1
   235
    return 0
yann@1
   236
}
yann@1
   237
yann@1
   238
# End the step just being done
yann@1
   239
# Usage: CT_EndStep
yann@1
   240
CT_EndStep() {
yann@523
   241
    local stop=$(CT_DoDate +%s%N)
yann@523
   242
    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
   243
    local elapsed=$(printf "%02d:%02d" $((SECONDS/60)) $((SECONDS%60)))
yann@1
   244
    local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
yann@1
   245
    local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
yann@1
   246
    CT_STEP_COUNT=$((CT_STEP_COUNT-1))
yann@582
   247
    CT_DoLog "${level}" "${message}: done in ${duration}s (at ${elapsed})"
yann@1
   248
    return 0
yann@1
   249
}
yann@1
   250
yann@1
   251
# Pushes into a directory, and pops back
yann@1
   252
CT_Pushd() {
yann@1
   253
    pushd "$1" >/dev/null 2>&1
yann@1
   254
}
yann@1
   255
CT_Popd() {
yann@1
   256
    popd >/dev/null 2>&1
yann@1
   257
}
yann@1
   258
yann@1
   259
# Creates a temporary directory
yann@1
   260
# $1: variable to assign to
yann@1
   261
# Usage: CT_MktempDir foo
yann@1
   262
CT_MktempDir() {
yann@1
   263
    # Some mktemp do not allow more than 6 Xs
yann@1113
   264
    eval "$1"=$(mktemp -q -d "${CT_BUILD_DIR}/tmp.XXXXXX")
yann@1
   265
    CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
yann@787
   266
    CT_DoLog DEBUG "Made temporary directory '${!1}'"
yann@787
   267
    return 0
yann@1
   268
}
yann@1
   269
yann@1148
   270
# Removes one or more directories, even if it is read-only, or its parent is
yann@1138
   271
# Usage: CT_DoForceRmdir dir [...]
yann@1138
   272
CT_DoForceRmdir() {
yann@1148
   273
    local dir
yann@1148
   274
    local mode
yann@1148
   275
    for dir in "${@}"; do
yann@1148
   276
        [ -d "${dir}" ] || continue
titus@1956
   277
        case "$CT_SYS_OS" in
yann@2029
   278
            Linux|CYGWIN*)
titus@1956
   279
                mode="$(stat -c '%a' "$(dirname "${dir}")")"
titus@1956
   280
                ;;
titus@1956
   281
            Darwin|*BSD)
titus@1956
   282
                mode="$(stat -f '%Lp' "$(dirname "${dir}")")"
titus@1956
   283
                ;;
titus@1956
   284
            *)
titus@1956
   285
                CT_Abort "Unhandled host OS $CT_SYS_OS"
titus@1956
   286
                ;;
titus@1956
   287
        esac
yann@1185
   288
        CT_DoExecLog ALL chmod u+w "$(dirname "${dir}")"
yann@1185
   289
        CT_DoExecLog ALL chmod -R u+w "${dir}"
yann@1148
   290
        CT_DoExecLog ALL rm -rf "${dir}"
yann@1185
   291
        CT_DoExecLog ALL chmod ${mode} "$(dirname "${dir}")"
yann@1148
   292
    done
yann@1138
   293
}
yann@1138
   294
yann@1
   295
# Echoes the specified string on stdout until the pipe breaks.
yann@1
   296
# Doesn't fail
yann@1
   297
# $1: string to echo
yann@1
   298
# Usage: CT_DoYes "" |make oldconfig
yann@1
   299
CT_DoYes() {
yann@1
   300
    yes "$1" || true
yann@1
   301
}
yann@63
   302
yann@1391
   303
# Add the specified directory to LD_LIBRARY_PATH, and export it
yann@1391
   304
# If the specified patch is already present, just export
yann@1391
   305
# $1: path to add
yann@1391
   306
# $2: add as 'first' or 'last' path, 'first' is assumed if $2 is empty
yann@1391
   307
# Usage CT_SetLibPath /some/where/lib [first|last]
yann@1391
   308
CT_SetLibPath() {
yann@1391
   309
    local path="$1"
yann@1391
   310
    local pos="$2"
yann@1391
   311
yann@1391
   312
    case ":${LD_LIBRARY_PATH}:" in
yann@1391
   313
        *:"${path}":*)  ;;
yann@1391
   314
        *)  case "${pos}" in
yann@1391
   315
                last)
yann@1391
   316
                    CT_DoLog DEBUG "Adding '${path}' at end of LD_LIBRARY_PATH"
yann@1391
   317
                    LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${path}"
yann@1391
   318
                    ;;
yann@1391
   319
                first|"")
yann@1391
   320
                    CT_DoLog DEBUG "Adding '${path}' at start of LD_LIBRARY_PATH"
yann@1391
   321
                    LD_LIBRARY_PATH="${path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
yann@1391
   322
                    ;;
yann@1391
   323
                *)
yann@1391
   324
                    CT_Abort "Incorrect position '${pos}' to add '${path}' to LD_LIBRARY_PATH"
yann@1391
   325
                    ;;
yann@1391
   326
            esac
yann@1391
   327
            ;;
yann@1391
   328
    esac
yann@1391
   329
    CT_DoLog DEBUG "==> LD_LIBRARY_PATH='${LD_LIBRARY_PATH}'"
yann@1391
   330
    export LD_LIBRARY_PATH
yann@1391
   331
}
yann@1391
   332
yann@85
   333
# Get the file name extension of a component
yann@719
   334
# Usage: CT_GetFileExtension <component_name-component_version> [extension]
yann@1690
   335
# If found, echoes the extension to stdout, and return 0
yann@1690
   336
# If not found, echoes nothing on stdout, and return !0.
yann@85
   337
CT_GetFileExtension() {
yann@85
   338
    local ext
yann@85
   339
    local file="$1"
yann@719
   340
    shift
yann@719
   341
    local first_ext="$1"
yann@85
   342
yann@160
   343
    # we need to also check for an empty extension for those very
yann@160
   344
    # peculiar components that don't have one (such as sstrip from
yann@160
   345
    # buildroot).
yann@1763
   346
    for ext in ${first_ext} .tar.gz .tar.bz2 .tgz .tar /.git ''; do
yann@1763
   347
        if [ -e "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
yann@85
   348
            echo "${ext}"
yann@1690
   349
            exit 0
yann@85
   350
        fi
yann@85
   351
    done
yann@85
   352
yann@1690
   353
    exit 1
yann@85
   354
}
yann@85
   355
yann@2204
   356
# Try to retrieve the specified URL (HTTP or FTP)
yann@2204
   357
# Usage: CT_DoGetFile <URL>
yann@2204
   358
# This functions always returns true (0), as it can be legitimate not
yann@2204
   359
# to find the requested URL (think about snapshots, different layouts
yann@2204
   360
# for different gcc versions, etc...).
yann@2204
   361
CT_DoGetFile() {
yann@2205
   362
    local dest="${1##*/}"
yann@2205
   363
    local tmp="${dest}.tmp-dl"
yann@2204
   364
    # OK, just look if we have them...
yann@2204
   365
    # We are sure at least one is available, ./configure checked for it.
yann@2204
   366
    local _curl=$(CT_Which curl)
yann@2204
   367
    local _wget=$(CT_Which wget)
yann@2204
   368
    _curl="${_curl:-false}"
yann@2204
   369
    _wget="${_wget:-false}"
yann@2204
   370
yann@2205
   371
    # Remove potential left-over from a previous run
yann@2205
   372
    rm -f "${tmp}"
yann@2205
   373
yann@63
   374
    # Some (very old!) FTP server might not support the passive mode, thus
yann@2204
   375
    # retry without.
yann@2204
   376
    # We also retry a few times, in case there is a transient error (eg. behind
yann@2204
   377
    # a dynamic IP that changes during the transfer...)
yann@2204
   378
    # With automated download as we are doing, it can be very dangerous to
yann@2204
   379
    # continue the downloads. It's far better to simply overwrite the
yann@2204
   380
    # destination file.
yann@492
   381
    # Some company networks have firewalls to connect to the internet, but it's
yann@1113
   382
    # not easy to detect them, and wget does not timeout by default while
yann@492
   383
    # connecting, so force a global ${CT_CONNECT_TIMEOUT}-second timeout.
yann@2204
   384
    # For curl, no good progress indicator is available. So, be silent.
yann@2205
   385
    if CT_DoExecLog ALL "${_curl}" --ftp-pasv    --retry 3 --connect-timeout ${CT_CONNECT_TIMEOUT} -L -f -s -o "${tmp}"   "$1"  \
yann@2205
   386
    || CT_DoExecLog ALL "${_curl}"               --retry 3 --connect-timeout ${CT_CONNECT_TIMEOUT} -L -f -s -o "${tmp}"   "$1"  \
yann@2205
   387
    || CT_DoExecLog ALL "${_wget}" --passive-ftp --tries=3 -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary -O "${tmp}" "$1"  \
yann@2205
   388
    || CT_DoExecLog ALL "${_wget}"               --tries=3 -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary -O "${tmp}" "$1"  \
yann@2205
   389
    ; then
yann@2205
   390
        # One of them succeeded, good!
yann@2205
   391
        mv "${tmp}" "${dest}"
yann@2205
   392
    else
yann@2205
   393
        # Woops...
yann@2205
   394
        rm -f "${tmp}"
yann@2205
   395
    fi
yann@63
   396
}
yann@63
   397
yann@1113
   398
# This function tries to retrieve a tarball form a local directory
yann@1113
   399
# Usage: CT_GetLocal <basename> [.extension]
yann@1113
   400
CT_GetLocal() {
yann@1113
   401
    local basename="$1"
yann@1113
   402
    local first_ext="$2"
yann@1113
   403
    local ext
yann@1113
   404
yann@1113
   405
    # Do we already have it in *our* tarballs dir?
yann@1690
   406
    if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
yann@1113
   407
        CT_DoLog DEBUG "Already have '${basename}'"
yann@1113
   408
        return 0
yann@1113
   409
    fi
yann@1113
   410
yann@1113
   411
    if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
yann@1113
   412
        CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
yann@1113
   413
        # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
yann@1113
   414
        # or, as a failover, a file without extension.
yann@1113
   415
        for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@1113
   416
            CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
yann@1113
   417
            if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
yann@1113
   418
                 "${CT_FORCE_DOWNLOAD}" != "y" ]; then
yann@1113
   419
                CT_DoLog DEBUG "Got '${basename}' from local storage"
yann@1113
   420
                CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1113
   421
                return 0
yann@1113
   422
            fi
yann@1113
   423
        done
yann@1113
   424
    fi
yann@1113
   425
    return 1
yann@1113
   426
}
yann@1113
   427
yann@1113
   428
# This function saves the specified to local storage if possible,
yann@1113
   429
# and if so, symlinks it for later usage
yann@1113
   430
# Usage: CT_SaveLocal </full/path/file.name>
yann@1113
   431
CT_SaveLocal() {
yann@1113
   432
    local file="$1"
yann@1113
   433
    local basename="${file##*/}"
yann@1113
   434
yann@1113
   435
    if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
yann@1134
   436
        CT_DoLog EXTRA "Saving '${basename}' to local storage"
yann@1113
   437
        # The file may already exist if downloads are forced: remove it first
yann@1113
   438
        CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
yann@1113
   439
        CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
yann@1113
   440
        CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
yann@1113
   441
    fi
yann@1113
   442
}
yann@1113
   443
yann@63
   444
# Download the file from one of the URLs passed as argument
yann@1113
   445
# Usage: CT_GetFile <basename> [.extension] <url> [url ...]
yann@63
   446
CT_GetFile() {
yann@63
   447
    local ext
yann@1179
   448
    local url URLS LAN_URLS
yann@63
   449
    local file="$1"
yann@1113
   450
    local first_ext
yann@63
   451
    shift
yann@712
   452
    # If next argument starts with a dot, then this is not an URL,
yann@712
   453
    # and we can consider that it is a preferred extension.
yann@242
   454
    case "$1" in
yann@712
   455
        .*) first_ext="$1"
yann@242
   456
            shift
yann@242
   457
            ;;
yann@242
   458
    esac
yann@63
   459
yann@1113
   460
    # Does it exist localy?
yann@1113
   461
    CT_GetLocal "${file}" ${first_ext} && return 0 || true
yann@1113
   462
    # No, it does not...
yann@63
   463
yann@754
   464
    # Try to retrieve the file
yann@788
   465
    CT_DoLog EXTRA "Retrieving '${file}'"
yann@63
   466
    CT_Pushd "${CT_TARBALLS_DIR}"
yann@754
   467
yann@1179
   468
    URLS="$@"
yann@1179
   469
yann@1022
   470
    # Add URLs on the LAN mirror
yann@1022
   471
    LAN_URLS=
yann@1022
   472
    if [ "${CT_USE_MIRROR}" = "y" ]; then
yann@1294
   473
        CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
yann@1294
   474
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}/${file%-*}"
yann@1294
   475
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}"
yann@695
   476
yann@1134
   477
        if [ "${CT_PREFER_MIRROR}" = "y" ]; then
yann@1134
   478
            CT_DoLog DEBUG "Pre-pending LAN mirror URLs"
yann@1179
   479
            URLS="${LAN_URLS} ${URLS}"
yann@1134
   480
        else
yann@1134
   481
            CT_DoLog DEBUG "Appending LAN mirror URLs"
yann@1179
   482
            URLS="${URLS} ${LAN_URLS}"
yann@1134
   483
        fi
yann@1022
   484
    fi
yann@1022
   485
yann@1022
   486
    # Scan all URLs in turn, and try to grab a tarball from there
yann@1763
   487
    # Do *not* try git trees (ext=/.git), this is handled in a specific
yann@1763
   488
    # wrapper, below
yann@242
   489
    for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@102
   490
        # Try all urls in turn
yann@1022
   491
        for url in ${URLS}; do
yann@523
   492
            CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
yann@265
   493
            CT_DoGetFile "${url}/${file}${ext}"
yann@265
   494
            if [ -f "${file}${ext}" ]; then
yann@799
   495
                CT_DoLog DEBUG "Got '${file}' from the Internet"
yann@1113
   496
                CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
yann@265
   497
                return 0
yann@265
   498
            fi
yann@102
   499
        done
yann@102
   500
    done
yann@63
   501
    CT_Popd
yann@63
   502
yann@754
   503
    CT_Abort "Could not retrieve '${file}'."
yann@63
   504
}
yann@63
   505
yann@1113
   506
# Checkout from CVS, and build the associated tarball
yann@1113
   507
# The tarball will be called ${basename}.tar.bz2
yann@1113
   508
# Prerequisite: either the server does not require password,
yann@1113
   509
# or the user must already be logged in.
yann@1113
   510
# 'tag' is the tag to retrieve. Must be specified, but can be empty.
yann@1113
   511
# If dirname is specified, then module will be renamed to dirname
yann@1113
   512
# prior to building the tarball.
yann@1592
   513
# Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
yann@1592
   514
# Note: if '=subdir' is given, then it is used instead of 'module'.
yann@1113
   515
CT_GetCVS() {
yann@1113
   516
    local basename="$1"
yann@1113
   517
    local uri="$2"
yann@1113
   518
    local module="$3"
yann@1113
   519
    local tag="${4:+-r ${4}}"
yann@1113
   520
    local dirname="$5"
yann@1113
   521
    local tmp_dir
yann@1113
   522
yann@1113
   523
    # Does it exist localy?
yann@1113
   524
    CT_GetLocal "${basename}" && return 0 || true
yann@1113
   525
    # No, it does not...
yann@1113
   526
yann@1113
   527
    CT_DoLog EXTRA "Retrieving '${basename}'"
yann@1113
   528
yann@1113
   529
    CT_MktempDir tmp_dir
yann@1113
   530
    CT_Pushd "${tmp_dir}"
yann@1113
   531
yann@1113
   532
    CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
yann@1592
   533
    if [ -n "${dirname}" ]; then
yann@1592
   534
        case "${dirname}" in
yann@1592
   535
            *=*)
yann@1593
   536
                CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
yann@1593
   537
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
yann@1592
   538
                ;;
yann@1592
   539
            *)
yann@1592
   540
                CT_DoExecLog ALL mv "${module}" "${dirname}"
yann@1592
   541
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
yann@1592
   542
                ;;
yann@1592
   543
        esac
yann@1592
   544
    fi
yann@1113
   545
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1113
   546
yann@1113
   547
    CT_Popd
yann@1113
   548
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1113
   549
}
yann@1113
   550
yann@1244
   551
# Check out from SVN, and build the associated tarball
yann@1244
   552
# The tarball will be called ${basename}.tar.bz2
yann@1244
   553
# Prerequisite: either the server does not require password,
yann@1244
   554
# or the user must already be logged in.
yann@1244
   555
# 'rev' is the revision to retrieve
yann@1244
   556
# Usage: CT_GetSVN <basename> <url> [rev]
yann@1244
   557
CT_GetSVN() {
yann@1244
   558
    local basename="$1"
yann@1244
   559
    local uri="$2"
yann@1244
   560
    local rev="$3"
yann@1244
   561
yann@1244
   562
    # Does it exist localy?
yann@1244
   563
    CT_GetLocal "${basename}" && return 0 || true
yann@1244
   564
    # No, it does not...
yann@1244
   565
yann@1244
   566
    CT_DoLog EXTRA "Retrieving '${basename}'"
yann@1244
   567
yann@1244
   568
    CT_MktempDir tmp_dir
yann@1244
   569
    CT_Pushd "${tmp_dir}"
yann@1244
   570
yann@1244
   571
    CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"
yann@1244
   572
    CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
yann@1244
   573
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1244
   574
yann@1244
   575
    CT_Popd
yann@1244
   576
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1244
   577
}
yann@1244
   578
yann@1763
   579
# Clone a git tree
yann@1763
   580
# Tries the given URLs in turn until one can get cloned. No tarball will be created.
yann@1763
   581
# Prerequisites: either the server does not require password,
yann@1763
   582
# or the user has already taken any action to authenticate to the server.
yann@1763
   583
# The cloned tree will *not* be stored in the local tarballs dir!
yann@1763
   584
# Usage: CT_GetGit <basename> <url [url ...]>
yann@1763
   585
CT_GetGit() {
yann@1763
   586
    local basename="$1"; shift
yann@1763
   587
    local url
yann@1763
   588
    local cloned=0
yann@1763
   589
yann@1763
   590
    # Do we have it in our tarballs dir?
yann@1763
   591
    if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
yann@1763
   592
        CT_DoLog EXTRA "Updating git tree '${basename}'"
yann@1763
   593
        CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   594
        CT_DoExecLog ALL git pull
yann@1763
   595
        CT_Popd
yann@1763
   596
    else
yann@1763
   597
        CT_DoLog EXTRA "Retrieving git tree '${basename}'"
yann@1763
   598
        for url in "${@}"; do
yann@1763
   599
            CT_DoLog ALL "Trying to clone from '${url}'"
yann@1763
   600
            CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   601
            if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
yann@1763
   602
                cloned=1
yann@1763
   603
                break
yann@1763
   604
            fi
yann@1763
   605
        done
yann@1763
   606
        CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
yann@1763
   607
    fi
yann@1763
   608
}
yann@1763
   609
yann@1126
   610
# Extract a tarball
yann@63
   611
# Some tarballs need to be extracted in specific places. Eg.: glibc addons
yann@63
   612
# must be extracted in the glibc directory; uCLibc locales must be extracted
yann@1123
   613
# in the extra/locale sub-directory of uClibc. This is taken into account
yann@1123
   614
# by the caller, that did a 'cd' into the correct path before calling us
yann@1123
   615
# and sets nochdir to 'nochdir'.
yann@1763
   616
# Note also that this function handles the git trees!
yann@1763
   617
# Usage: CT_Extract <basename> [nochdir] [options]
yann@1763
   618
# where 'options' are dependent on the source (eg. git branch/tag...)
yann@1126
   619
CT_Extract() {
yann@1761
   620
    local nochdir="$1"
yann@1761
   621
    local basename
yann@1690
   622
    local ext
yann@1690
   623
yann@1761
   624
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
   625
        shift
yann@1761
   626
        nochdir="$(pwd)"
yann@1761
   627
    else
yann@1761
   628
        nochdir="${CT_SRC_DIR}"
yann@1761
   629
    fi
yann@1761
   630
yann@1761
   631
    basename="$1"
yann@1761
   632
    shift
yann@1761
   633
yann@1690
   634
    if ! ext="$(CT_GetFileExtension "${basename}")"; then
yann@1763
   635
      CT_Abort "'${basename}' not found in '${CT_TARBALLS_DIR}'"
yann@1690
   636
    fi
yann@1126
   637
    local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1126
   638
yann@1718
   639
    # Check if already extracted
yann@1718
   640
    if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
yann@1718
   641
        CT_DoLog DEBUG "Already extracted '${basename}'"
yann@1718
   642
        return 0
yann@1718
   643
    fi
yann@1718
   644
yann@1691
   645
    # Check if previously partially extracted
yann@1691
   646
    if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
yann@1691
   647
        CT_DoLog ERROR "The '${basename}' sources were partially extracted."
yann@1691
   648
        CT_DoLog ERROR "Please remove first:"
yann@1691
   649
        CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
yann@1691
   650
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
yann@1691
   651
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1691
   652
    fi
yann@1691
   653
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
yann@1691
   654
yann@1761
   655
    CT_Pushd "${nochdir}"
yann@63
   656
yann@1126
   657
    CT_DoLog EXTRA "Extracting '${basename}'"
yann@63
   658
    case "${ext}" in
anthony@2154
   659
        .tar.bz2)     CT_DoExecLog FILE tar xvjf "${full_file}";;
anthony@2154
   660
        .tar.gz|.tgz) CT_DoExecLog FILE tar xvzf "${full_file}";;
anthony@2154
   661
        .tar)         CT_DoExecLog FILE tar xvf  "${full_file}";;
yann@1763
   662
        /.git)        CT_ExtractGit "${basename}" "${@}";;
yann@1763
   663
        *)            CT_Abort "Don't know how to handle '${basename}${ext}': unknown extension";;
yann@63
   664
    esac
yann@63
   665
yann@1208
   666
    # Some tarballs have read-only files... :-(
yann@1258
   667
    # Because of nochdir, we don't know where we are, so chmod all
yann@1258
   668
    # the src tree
yann@1271
   669
    CT_DoExecLog DEBUG chmod -R u+w "${CT_SRC_DIR}"
yann@1208
   670
yann@1763
   671
    # Don't mark as being extracted for git
yann@1763
   672
    case "${ext}" in
yann@1763
   673
        /.git)  ;;
yann@1763
   674
        *)      CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
yann@1763
   675
    esac
yann@1691
   676
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
yann@1126
   677
yann@1761
   678
    CT_Popd
yann@1126
   679
}
yann@1126
   680
yann@1763
   681
# Create a working git clone
yann@1763
   682
# Usage: CT_ExtractGit <basename> [ref]
yann@1763
   683
# where 'ref' is the reference to use:
yann@1763
   684
#   the full name of a branch, like "remotes/origin/branch_name"
yann@1763
   685
#   a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
yann@1763
   686
#   a tag name
yann@1763
   687
CT_ExtractGit() {
yann@1763
   688
    local basename="${1}"
yann@1763
   689
    local ref="${2}"
yann@1763
   690
    local clone_dir
yann@1763
   691
    local ref_type
yann@1763
   692
yann@1763
   693
    # pushd now to be able to get git revlist in case ref is a date
yann@1763
   694
    clone_dir="${CT_TARBALLS_DIR}/${basename}"
yann@1763
   695
    CT_Pushd "${clone_dir}"
yann@1763
   696
yann@1763
   697
    # What kind of reference is ${ref} ?
yann@1763
   698
    if [ -z "${ref}" ]; then
yann@1763
   699
        # Don't update the clone, keep as-is
yann@1763
   700
        ref_type=none
yann@1763
   701
    elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
yann@1763
   702
        ref_type=tag
yann@1763
   703
    elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
yann@1763
   704
        ref_type=branch
yann@1763
   705
    elif date -d "${ref}" >/dev/null 2>&1; then
yann@1763
   706
        ref_type=date
yann@1763
   707
        ref=$(git rev-list -n1 --before="${ref}")
yann@1763
   708
    else
yann@1763
   709
        CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
yann@1763
   710
    fi
yann@1763
   711
yann@1763
   712
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/${basename}"
yann@1763
   713
    CT_DoExecLog ALL ln -sf "${clone_dir}" "${CT_SRC_DIR}/${basename}"
yann@1763
   714
yann@1763
   715
    case "${ref_type}" in
yann@1763
   716
        none)   ;;
anthony@2154
   717
        *)      CT_DoExecLog FILE git checkout "${ref}";;
yann@1763
   718
    esac
yann@1763
   719
yann@1763
   720
    CT_Popd
yann@1763
   721
}
yann@1763
   722
yann@1126
   723
# Patches the specified component
yann@1761
   724
# See CT_Extract, above, for explanations on 'nochdir'
yann@1901
   725
# Usage: CT_Patch [nochdir] <packagename> <packageversion>
yann@1901
   726
# If the package directory is *not* packagename-packageversion, then
yann@1901
   727
# the caller must cd into the proper directory first, and call us
yann@1901
   728
# with nochdir
yann@1126
   729
CT_Patch() {
yann@1761
   730
    local nochdir="$1"
yann@1901
   731
    local pkgname
yann@1901
   732
    local version
yann@1901
   733
    local pkgdir
yann@1761
   734
    local base_file
yann@1761
   735
    local ver_file
yann@1507
   736
    local d
yann@1507
   737
    local -a patch_dirs
yann@1507
   738
    local bundled_patch_dir
yann@1507
   739
    local local_patch_dir
yann@1126
   740
yann@1761
   741
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
   742
        shift
yann@1906
   743
        pkgname="$1"
yann@1906
   744
        version="$2"
yann@1906
   745
        pkgdir="${pkgname}-${version}"
yann@1761
   746
        nochdir="$(pwd)"
yann@1761
   747
    else
yann@1906
   748
        pkgname="$1"
yann@1906
   749
        version="$2"
yann@1906
   750
        pkgdir="${pkgname}-${version}"
yann@1901
   751
        nochdir="${CT_SRC_DIR}/${pkgdir}"
yann@1761
   752
    fi
yann@1761
   753
yann@1126
   754
    # Check if already patched
yann@1901
   755
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
yann@1901
   756
        CT_DoLog DEBUG "Already patched '${pkgdir}'"
yann@1126
   757
        return 0
yann@63
   758
    fi
yann@63
   759
yann@1271
   760
    # Check if already partially patched
yann@1901
   761
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
yann@1901
   762
        CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
yann@1271
   763
        CT_DoLog ERROR "Please remove first:"
yann@1901
   764
        CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
yann@1901
   765
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
yann@1901
   766
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
yann@1271
   767
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1271
   768
    fi
yann@1901
   769
    touch "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1271
   770
yann@1761
   771
    CT_Pushd "${nochdir}"
yann@1123
   772
yann@1901
   773
    CT_DoLog EXTRA "Patching '${pkgdir}'"
yann@63
   774
yann@1901
   775
    bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
yann@1901
   776
    local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
yann@1507
   777
yann@1507
   778
    case "${CT_PATCH_ORDER}" in
yann@1507
   779
        bundled)        patch_dirs=("${bundled_patch_dir}");;
yann@1507
   780
        local)          patch_dirs=("${local_patch_dir}");;
yann@1507
   781
        bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
yann@1508
   782
        local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
yann@1630
   783
        none)           patch_dirs=;;
yann@1507
   784
    esac
yann@1507
   785
yann@1507
   786
    for d in "${patch_dirs[@]}"; do
yann@1507
   787
        CT_DoLog DEBUG "Looking for patches in '${d}'..."
yann@1507
   788
        if [ -n "${d}" -a -d "${d}" ]; then
yann@1507
   789
            for p in "${d}"/*.patch; do
yann@63
   790
                if [ -f "${p}" ]; then
yann@523
   791
                    CT_DoLog DEBUG "Applying patch '${p}'"
yann@1765
   792
                    CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f <"${p}"
yann@63
   793
                fi
yann@63
   794
            done
yann@1509
   795
            if [ "${CT_PATCH_SINGLE}" = "y" ]; then
yann@1509
   796
                break
yann@1509
   797
            fi
yann@63
   798
        fi
yann@63
   799
    done
yann@63
   800
yann@508
   801
    if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
yann@508
   802
        CT_DoLog ALL "Overiding config.guess and config.sub"
yann@508
   803
        for cfg in config_guess config_sub; do
yann@1101
   804
            eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
yann@1101
   805
            [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
yann@776
   806
            # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
yann@508
   807
            find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
yann@508
   808
        done
yann@508
   809
    fi
yann@508
   810
yann@1903
   811
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
yann@1903
   812
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1126
   813
yann@1761
   814
    CT_Popd
yann@63
   815
}
yann@63
   816
yann@182
   817
# Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
yann@182
   818
# Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
yann@182
   819
CT_DoConfigGuess() {
yann@1101
   820
    if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
yann@1101
   821
        "${CT_TOP_DIR}/scripts/config.guess"
yann@182
   822
    else
yann@1101
   823
        "${CT_LIB_DIR}/scripts/config.guess"
yann@182
   824
    fi
yann@182
   825
}
yann@182
   826
yann@182
   827
CT_DoConfigSub() {
yann@1101
   828
    if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
yann@1101
   829
        "${CT_TOP_DIR}/scripts/config.sub" "$@"
yann@182
   830
    else
yann@1101
   831
        "${CT_LIB_DIR}/scripts/config.sub" "$@"
yann@182
   832
    fi
yann@182
   833
}
yann@182
   834
yann@335
   835
# Compute the target tuple from what is provided by the user
yann@335
   836
# Usage: CT_DoBuildTargetTuple
yann@63
   837
# In fact this function takes the environment variables to build the target
yann@335
   838
# tuple. It is needed both by the normal build sequence, as well as the
yann@63
   839
# sample saving sequence.
yann@335
   840
CT_DoBuildTargetTuple() {
yann@383
   841
    # Set the endianness suffix, and the default endianness gcc option
yann@63
   842
    case "${CT_ARCH_BE},${CT_ARCH_LE}" in
yann@383
   843
        y,) target_endian_eb=eb
yann@383
   844
            target_endian_el=
yann@391
   845
            CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
yann@527
   846
            CT_ARCH_ENDIAN_LDFLAG="-EB"
yann@383
   847
            ;;
yann@383
   848
        ,y) target_endian_eb=
yann@383
   849
            target_endian_el=el
yann@391
   850
            CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
yann@527
   851
            CT_ARCH_ENDIAN_LDFLAG="-EL"
yann@383
   852
            ;;
yann@63
   853
    esac
yann@383
   854
yann@965
   855
    # Build the default architecture tuple part
yann@965
   856
    CT_TARGET_ARCH="${CT_ARCH}"
yann@965
   857
yann@383
   858
    # Set defaults for the system part of the tuple. Can be overriden
yann@383
   859
    # by architecture-specific values.
yann@383
   860
    case "${CT_LIBC}" in
yann@787
   861
        *glibc) CT_TARGET_SYS=gnu;;
yann@383
   862
        uClibc) CT_TARGET_SYS=uclibc;;
yann@1591
   863
        *)      CT_TARGET_SYS=elf;;
yann@63
   864
    esac
yann@383
   865
yann@391
   866
    # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
yann@497
   867
    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
   868
    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
   869
    [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
yann@391
   870
    [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
yann@391
   871
    [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
yann@405
   872
    [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
yann@391
   873
    [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
yann@412
   874
    [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float";           CT_ARCH_WITH_FLOAT="--with-float=soft";          }
yann@391
   875
yann@965
   876
    # Build the default kernel tuple part
yann@965
   877
    CT_TARGET_KERNEL="${CT_KERNEL}"
yann@964
   878
yann@965
   879
    # Overide the default values with the components specific settings
yann@964
   880
    CT_DoArchTupleValues
yann@965
   881
    CT_DoKernelTupleValues
yann@383
   882
yann@391
   883
    # Finish the target tuple construction
bartvdrmeulen@1896
   884
    CT_TARGET="${CT_TARGET_ARCH}"
bartvdrmeulen@1896
   885
    CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
bartvdrmeulen@1896
   886
    CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
bartvdrmeulen@1896
   887
    CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
yann@1094
   888
yann@1094
   889
    # Sanity checks
yann@1094
   890
    __sed_alias=""
yann@1094
   891
    if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
yann@1094
   892
        __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
yann@1094
   893
    fi
yann@1094
   894
    case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
yann@1094
   895
      :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
yann@1094
   896
      :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
yann@1094
   897
      :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
yann@1094
   898
      :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
yann@1094
   899
    esac
yann@1094
   900
yann@1094
   901
    # Canonicalise it
yann@1094
   902
    CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
yann@391
   903
    # Prepare the target CFLAGS
yann@767
   904
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
yann@527
   905
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
yann@397
   906
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
yann@397
   907
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
yann@397
   908
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
yann@397
   909
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
yann@397
   910
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
yann@527
   911
yann@527
   912
    # Now on for the target LDFLAGS
yann@767
   913
    CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
yann@63
   914
}
yann@121
   915
yann@121
   916
# This function does pause the build until the user strikes "Return"
yann@121
   917
# Usage: CT_DoPause [optional_message]
yann@121
   918
CT_DoPause() {
yann@121
   919
    local foo
yann@121
   920
    local message="${1:-Pausing for your pleasure}"
yann@121
   921
    CT_DoLog INFO "${message}"
yann@523
   922
    read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
yann@121
   923
    return 0
yann@121
   924
}
yann@121
   925
yann@1907
   926
# This function creates a tarball of the specified directory, but
yann@1907
   927
# only if it exists
yann@1907
   928
# Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
yann@1907
   929
CT_DoTarballIfExists() {
yann@1907
   930
    local dir="$1"
yann@1907
   931
    local tarball="$2"
yann@1907
   932
    shift 2
yann@1907
   933
    local -a extra_tar_opts=( "$@" )
yann@1908
   934
    local -a compress
yann@1907
   935
yann@1907
   936
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
   937
        y)  compress=( gzip -c -3 - ); tar_ext=.gz;;
yann@1908
   938
        *)  compress=( cat - );        tar_ext=;;
yann@1907
   939
    esac
yann@1907
   940
yann@1907
   941
    if [ -d "${dir}" ]; then
yann@1907
   942
        CT_DoLog DEBUG "  Saving '${dir}'"
yann@1908
   943
        { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" .    \
yann@1908
   944
          |"${compress[@]}" >"${tarball}.tar${tar_ext}"         ;
anthony@2155
   945
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
   946
    else
anthony@2155
   947
        CT_DoLog STATE "  Not saving '${dir}': does not exist"
yann@1907
   948
    fi
yann@1907
   949
}
yann@1907
   950
yann@1907
   951
# This function extracts a tarball to the specified directory, but
yann@1907
   952
# only if the tarball exists
anthony@2155
   953
# Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
yann@1907
   954
CT_DoExtractTarballIfExists() {
yann@1907
   955
    local tarball="$1"
yann@1907
   956
    local dir="$2"
yann@1907
   957
    shift 2
yann@1907
   958
    local -a extra_tar_opts=( "$@" )
yann@1908
   959
    local -a uncompress
yann@1907
   960
yann@1907
   961
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
   962
        y)  uncompress=( gzip -c -d ); tar_ext=.gz;;
yann@1908
   963
        *)  uncompress=( cat );        tar_ext=;;
yann@1907
   964
    esac
yann@1907
   965
yann@1907
   966
    if [ -f "${tarball}.tar${tar_ext}" ]; then
yann@1907
   967
        CT_DoLog DEBUG "  Restoring '${dir}'"
yann@1907
   968
        CT_DoForceRmdir "${dir}"
yann@1907
   969
        CT_DoExecLog DEBUG mkdir -p "${dir}"
yann@1908
   970
        { "${uncompress[@]}" "${tarball}.tar${tar_ext}"     \
yann@1908
   971
          |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
anthony@2155
   972
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
   973
    else
anthony@2155
   974
        CT_DoLog STATE "  Not restoring '${dir}': does not exist"
yann@1907
   975
    fi
yann@1907
   976
}
yann@1907
   977
yann@121
   978
# This function saves the state of the toolchain to be able to restart
yann@121
   979
# at any one point
yann@121
   980
# Usage: CT_DoSaveState <next_step_name>
yann@121
   981
CT_DoSaveState() {
yann@121
   982
	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
yann@121
   983
    local state_name="$1"
yann@121
   984
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@121
   985
yann@1266
   986
    # Log this to the log level required by the user
yann@1266
   987
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
yann@1134
   988
yann@121
   989
    rm -rf "${state_dir}"
yann@121
   990
    mkdir -p "${state_dir}"
yann@121
   991
anthony@2155
   992
    CT_DoLog STATE "  Saving environment and aliases"
yann@738
   993
    # We must omit shell functions, and some specific bash variables
yann@738
   994
    # that break when restoring the environment, later. We could do
yann@1299
   995
    # all the processing in the awk script, but a sed is easier...
yann@1299
   996
    set |awk '
yann@1017
   997
              BEGIN { _p = 1; }
yann@1017
   998
              $0~/^[^ ]+ \(\)/ { _p = 0; }
yann@1017
   999
              _p == 1
yann@1017
  1000
              $0 == "}" { _p = 1; }
yann@1017
  1001
              ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
yann@738
  1002
                           /^(UID|EUID)=/d;
yann@738
  1003
                           /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
yann@121
  1004
yann@2130
  1005
    if [ "${CT_COMPLIBS_BACKUP}" = "y" ]; then
yann@1907
  1006
        CT_DoTarballIfExists "${CT_COMPLIBS_DIR}" "${state_dir}/complibs_dir"
yann@1894
  1007
    fi
yann@1907
  1008
    CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
yann@1907
  1009
    CT_DoTarballIfExists "${CT_CC_CORE_STATIC_PREFIX_DIR}" "${state_dir}/cc_core_static_prefix_dir"
yann@1907
  1010
    CT_DoTarballIfExists "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${state_dir}/cc_core_shared_prefix_dir"
yann@1907
  1011
    CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
yann@121
  1012
yann@121
  1013
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
anthony@2155
  1014
        CT_DoLog STATE "  Saving log file"
yann@121
  1015
        exec >/dev/null
yann@121
  1016
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
  1017
            y)  gzip -3 -c "${CT_LOG_FILE}"  >"${state_dir}/log.gz";;
yann@121
  1018
            *)  cat "${CT_LOG_FILE}" >"${state_dir}/log";;
yann@121
  1019
        esac
yann@121
  1020
        exec >>"${CT_LOG_FILE}"
yann@121
  1021
    fi
yann@121
  1022
}
yann@121
  1023
yann@136
  1024
# This function restores a previously saved state
yann@121
  1025
# Usage: CT_DoLoadState <state_name>
yann@121
  1026
CT_DoLoadState(){
yann@121
  1027
    local state_name="$1"
yann@121
  1028
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@135
  1029
    local old_RESTART="${CT_RESTART}"
yann@135
  1030
    local old_STOP="${CT_STOP}"
yann@121
  1031
yann@523
  1032
    CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
yann@141
  1033
yann@121
  1034
    # We need to do something special with the log file!
yann@121
  1035
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
  1036
        exec >"${state_dir}/tail.log"
yann@121
  1037
    fi
yann@1266
  1038
yann@1266
  1039
    # Log this to the log level required by the user
yann@1266
  1040
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
yann@121
  1041
yann@1907
  1042
    CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
yann@1907
  1043
    CT_DoExtractTarballIfExists "${state_dir}/cc_core_shared_prefix_dir" "${CT_CC_CORE_SHARED_PREFIX_DIR}"
yann@1907
  1044
    CT_DoExtractTarballIfExists "${state_dir}/cc_core_static_prefix_dir" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@1907
  1045
    CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
yann@2130
  1046
    if [ "${CT_COMPLIBS_BACKUP}" = "y" ]; then
yann@1907
  1047
        CT_DoExtractTarballIfExists "${state_dir}/complibs_dir" "${CT_COMPLIBS_DIR}"
yann@1894
  1048
    fi
yann@1894
  1049
yann@121
  1050
    # Restore the environment, discarding any error message
yann@121
  1051
    # (for example, read-only bash internals)
anthony@2155
  1052
    CT_DoLog STATE "  Restoring environment"
yann@121
  1053
    . "${state_dir}/env.sh" >/dev/null 2>&1 || true
yann@121
  1054
yann@135
  1055
    # Restore the new RESTART and STOP steps
yann@135
  1056
    CT_RESTART="${old_RESTART}"
yann@135
  1057
    CT_STOP="${old_STOP}"
yann@135
  1058
    unset old_stop old_restart
yann@135
  1059
yann@121
  1060
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
anthony@2155
  1061
        CT_DoLog STATE "  Restoring log file"
yann@121
  1062
        exec >/dev/null
yann@121
  1063
        case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@121
  1064
            y)  zcat "${state_dir}/log.gz" >"${CT_LOG_FILE}";;
yann@121
  1065
            *)  cat "${state_dir}/log" >"${CT_LOG_FILE}";;
yann@121
  1066
        esac
yann@121
  1067
        cat "${state_dir}/tail.log" >>"${CT_LOG_FILE}"
yann@121
  1068
        exec >>"${CT_LOG_FILE}"
yann@121
  1069
        rm -f "${state_dir}/tail.log"
yann@121
  1070
    fi
yann@121
  1071
}