scripts/functions
author Remy Bohmer <linux@bohmer.net>
Sun Jul 11 22:23:34 2010 +0200 (2010-07-11)
changeset 2021 3e52a1510f87
parent 1909 5921089b34bd
child 2029 93f7e40dacdf
permissions -rw-r--r--
debug/gdb: Fix compilation for Mingw hosts

GDB requires PDcurses instead of ncurses while running on Windows.
So, do not always compile ncurses in case GDB needs to build.

PDcurses is provided by an earlier build step and is not described in
this file.

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