scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Wed Apr 06 22:30:57 2011 +0200 (2011-04-06)
changeset 2381 0ca0f85a4b2a
parent 2340 580f427595bc
child 2382 cbd07f3dd6e3
permissions -rw-r--r--
complibs: disable building shared libs

Managing the shared version of the companion libraries
has become cumbersome.

Also, it will one day be possible to use the companion
libraries from the host distribution, and then we will
be able to easily use either shared or static libs.

As a side note, while working on the canadian-rework
series, it has become quite more complex to properly
handle shared companion libraries, as they need to be
built both for the build and gost systems. That's not
easy to handle. At all.

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