scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Tue Sep 23 14:48:10 2008 +0000 (2008-09-23)
changeset 872 fd4bf138f08f
parent 799 a31e625eb343
child 919 70f7ea9f910a
permissions -rw-r--r--
Bart De VOS pointed out that removing absolute paths from the libc linker scripts is plainly wrong.
It dates from dawn ages of the original crosstool code, and is not well explained. At that time, binutils might not understand the sysroot stuff, and it was necessary to remove absolute paths in that case.

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