uboot/MAKEALL
<<
>>
Prefs
   1#!/bin/bash
   2# Tool mainly for U-Boot Quality Assurance: build one or more board
   3# configurations with minimal verbosity, showing only warnings and
   4# errors.
   5#
   6# SPDX-License-Identifier:      GPL-2.0+
   7
   8usage()
   9{
  10        # if exiting with 0, write to stdout, else write to stderr
  11        local ret=${1:-0}
  12        [ "${ret}" -eq 1 ] && exec 1>&2
  13        cat <<-EOF
  14        Usage: MAKEALL [options] [--] [boards-to-build]
  15
  16        Options:
  17          -a ARCH,   --arch ARCH       Build all boards with arch ARCH
  18          -c CPU,    --cpu CPU         Build all boards with cpu CPU
  19          -v VENDOR, --vendor VENDOR   Build all boards with vendor VENDOR
  20          -s SOC,    --soc SOC         Build all boards with soc SOC
  21          -b BOARD,  --board BOARD     Build all boards with board name BOARD
  22          -l,        --list            List all targets to be built
  23          -m,        --maintainers     List all targets and maintainer email
  24          -M,        --mails           List all targets and all affilated emails
  25          -C,        --check           Enable build checking
  26          -n,        --continue        Continue (skip boards already built)
  27          -r,        --rebuild-errors  Rebuild any boards that errored
  28          -h,        --help            This help output
  29
  30        Selections by these options are logically ANDed; if the same option
  31        is used repeatedly, such selections are ORed.  So "-v FOO -v BAR"
  32        will select all configurations where the vendor is either FOO or
  33        BAR.  Any additional arguments specified on the command line are
  34        always build additionally.  See the boards.cfg file for more info.
  35
  36        If no boards are specified, then the default is "powerpc".
  37
  38        Environment variables:
  39          BUILD_NCPUS      number of parallel make jobs (default: auto)
  40          CROSS_COMPILE    cross-compiler toolchain prefix (default: "")
  41          CROSS_COMPILE_<ARCH> cross-compiler toolchain prefix for
  42                           architecture "ARCH".  Substitute "ARCH" for any
  43                           supported architecture (default: "")
  44          MAKEALL_LOGDIR   output all logs to here (default: ./LOG/)
  45          BUILD_DIR        output build directory (default: ./)
  46          BUILD_NBUILDS    number of parallel targets (default: 1)
  47
  48        Examples:
  49          - build all Power Architecture boards:
  50              MAKEALL -a powerpc
  51              MAKEALL --arch powerpc
  52              MAKEALL powerpc
  53          - build all PowerPC boards manufactured by vendor "esd":
  54              MAKEALL -a powerpc -v esd
  55          - build all PowerPC boards manufactured either by "keymile" or "siemens":
  56              MAKEALL -a powerpc -v keymile -v siemens
  57          - build all Freescale boards with MPC83xx CPUs, plus all 4xx boards:
  58              MAKEALL -c mpc83xx -v freescale 4xx
  59        EOF
  60        exit ${ret}
  61}
  62
  63deprecation() {
  64        echo "** Note: MAKEALL is deprecated - please use buildman instead"
  65        echo "** See tools/buildman/README for details"
  66        echo
  67}
  68
  69deprecation
  70
  71SHORT_OPTS="ha:c:v:s:b:lmMCnr"
  72LONG_OPTS="help,arch:,cpu:,vendor:,soc:,board:,list,maintainers,mails,check,continue,rebuild-errors"
  73
  74# Option processing based on util-linux-2.13/getopt-parse.bash
  75
  76# Note that we use `"$@"' to let each command-line parameter expand to a
  77# separate word. The quotes around `$@' are essential!
  78# We need TEMP as the `eval set --' would nuke the return value of
  79# getopt.
  80TEMP=`getopt -o ${SHORT_OPTS} --long ${LONG_OPTS} \
  81     -n 'MAKEALL' -- "$@"`
  82
  83[ $? != 0 ] && usage 1
  84
  85# Note the quotes around `$TEMP': they are essential!
  86eval set -- "$TEMP"
  87
  88SELECTED=''
  89ONLY_LIST=''
  90PRINT_MAINTS=''
  91MAINTAINERS_ONLY=''
  92CONTINUE=''
  93REBUILD_ERRORS=''
  94
  95while true ; do
  96        case "$1" in
  97        -a|--arch)
  98                # echo "Option ARCH: argument \`$2'"
  99                if [ "$opt_a" ] ; then
 100                        opt_a="${opt_a%)} || \$2 == \"$2\")"
 101                else
 102                        opt_a="(\$2 == \"$2\")"
 103                fi
 104                SELECTED='y'
 105                shift 2 ;;
 106        -c|--cpu)
 107                # echo "Option CPU: argument \`$2'"
 108                if [ "$opt_c" ] ; then
 109                        opt_c="${opt_c%)} || \$3 == \"$2\" || \$3 ~ /$2:/)"
 110                else
 111                        opt_c="(\$3 == \"$2\" || \$3 ~ /$2:/)"
 112                fi
 113                SELECTED='y'
 114                shift 2 ;;
 115        -s|--soc)
 116                # echo "Option SoC: argument \`$2'"
 117                if [ "$opt_s" ] ; then
 118                        opt_s="${opt_s%)} || \$4 == \"$2\" || \$4 ~ /$2/)"
 119                else
 120                        opt_s="(\$4 == \"$2\" || \$4 ~ /$2/)"
 121                fi
 122                SELECTED='y'
 123                shift 2 ;;
 124        -v|--vendor)
 125                # echo "Option VENDOR: argument \`$2'"
 126                if [ "$opt_v" ] ; then
 127                        opt_v="${opt_v%)} || \$5 == \"$2\")"
 128                else
 129                        opt_v="(\$5 == \"$2\")"
 130                fi
 131                SELECTED='y'
 132                shift 2 ;;
 133        -b|--board)
 134                # echo "Option BOARD: argument \`$2'"
 135                if [ "$opt_b" ] ; then
 136                        opt_b="${opt_b%)} || \$6 == \"$2\" || \$7 == \"$2\")"
 137                else
 138                        # We need to check the 7th field too
 139                        # for boards whose 6th field is "-"
 140                        opt_b="(\$6 == \"$2\" || \$7 == \"$2\")"
 141                fi
 142                SELECTED='y'
 143                shift 2 ;;
 144        -C|--check)
 145                CHECK='C=1'
 146                shift ;;
 147        -n|--continue)
 148                CONTINUE='y'
 149                shift ;;
 150        -r|--rebuild-errors)
 151                REBUILD_ERRORS='y'
 152                shift ;;
 153        -l|--list)
 154                ONLY_LIST='y'
 155                shift ;;
 156        -m|--maintainers)
 157                ONLY_LIST='y'
 158                PRINT_MAINTS='y'
 159                MAINTAINERS_ONLY='y'
 160                shift ;;
 161        -M|--mails)
 162                ONLY_LIST='y'
 163                PRINT_MAINTS='y'
 164                shift ;;
 165        -h|--help)
 166                usage ;;
 167        --)
 168                shift ; break ;;
 169        *)
 170                echo "Internal error!" >&2 ; exit 1 ;;
 171        esac
 172done
 173
 174GNU_MAKE=$(scripts/show-gnu-make) || {
 175        echo "GNU Make not found" >&2
 176        exit 1
 177}
 178
 179# echo "Remaining arguments:"
 180# for arg do echo '--> '"\`$arg'" ; done
 181
 182tools/genboardscfg.py || {
 183        echo "Failed to generate boards.cfg" >&2
 184        exit 1
 185}
 186
 187FILTER="\$1 !~ /^#/"
 188[ "$opt_a" ] && FILTER="${FILTER} && $opt_a"
 189[ "$opt_c" ] && FILTER="${FILTER} && $opt_c"
 190[ "$opt_s" ] && FILTER="${FILTER} && $opt_s"
 191[ "$opt_v" ] && FILTER="${FILTER} && $opt_v"
 192[ "$opt_b" ] && FILTER="${FILTER} && $opt_b"
 193
 194if [ "$SELECTED" ] ; then
 195        SELECTED=$(awk '('"$FILTER"') { print $7 }' boards.cfg)
 196
 197        # Make sure some boards from boards.cfg are actually found
 198        if [ -z "$SELECTED" ] ; then
 199                echo "Error: No boards selected, invalid arguments"
 200                exit 1
 201        fi
 202fi
 203
 204#########################################################################
 205
 206# Print statistics when we exit
 207trap exit 1 2 3 15
 208trap print_stats 0
 209
 210# Determine number of CPU cores if no default was set
 211: ${BUILD_NCPUS:="`getconf _NPROCESSORS_ONLN`"}
 212
 213if [ "$BUILD_NCPUS" -gt 1 ]
 214then
 215        JOBS="-j $((BUILD_NCPUS + 1))"
 216else
 217        JOBS=""
 218fi
 219
 220if [ "${MAKEALL_LOGDIR}" ] ; then
 221        LOG_DIR=${MAKEALL_LOGDIR}
 222else
 223        LOG_DIR="LOG"
 224fi
 225
 226: ${BUILD_NBUILDS:=1}
 227BUILD_MANY=0
 228
 229if [ "${BUILD_NBUILDS}" -gt 1 ] ; then
 230        BUILD_MANY=1
 231        : ${BUILD_DIR:=./build}
 232        mkdir -p "${BUILD_DIR}/ERR"
 233        find "${BUILD_DIR}/ERR/" -type f -exec rm -f {} +
 234fi
 235
 236: ${BUILD_DIR:=.}
 237
 238OUTPUT_PREFIX="${BUILD_DIR}"
 239
 240[ -d ${LOG_DIR} ] || mkdir "${LOG_DIR}" || exit 1
 241if [ "$CONTINUE" != 'y' -a "$REBUILD_ERRORS" != 'y' ] ; then
 242        find "${LOG_DIR}/" -type f -exec rm -f {} +
 243fi
 244
 245LIST=""
 246
 247# Keep track of the number of builds and errors
 248ERR_CNT=0
 249ERR_LIST=""
 250WRN_CNT=0
 251WRN_LIST=""
 252TOTAL_CNT=0
 253SKIP_CNT=0
 254CURRENT_CNT=0
 255OLDEST_IDX=1
 256RC=0
 257
 258# Helper funcs for parsing boards.cfg
 259targets_by_field()
 260{
 261        field=$1
 262        regexp=$2
 263
 264        awk '($1 !~ /^#/ && $'"$field"' ~ /^'"$regexp"'$/) { print $7 }' \
 265                                                                boards.cfg
 266}
 267
 268targets_by_arch() { targets_by_field 2 "$@" ; }
 269targets_by_cpu()  { targets_by_field 3 "$@" ; targets_by_field 3 "$@:.*" ; }
 270targets_by_soc()  { targets_by_field 4 "$@" ; }
 271
 272#########################################################################
 273## MPC5xx Systems
 274#########################################################################
 275
 276LIST_5xx="$(targets_by_cpu mpc5xx)"
 277
 278#########################################################################
 279## MPC5xxx Systems
 280#########################################################################
 281
 282LIST_5xxx="$(targets_by_cpu mpc5xxx)"
 283
 284#########################################################################
 285## MPC512x Systems
 286#########################################################################
 287
 288LIST_512x="$(targets_by_cpu mpc512x)"
 289
 290#########################################################################
 291## MPC8xx Systems
 292#########################################################################
 293
 294LIST_8xx="$(targets_by_cpu mpc8xx)"
 295
 296#########################################################################
 297## PPC4xx Systems
 298#########################################################################
 299
 300LIST_4xx="$(targets_by_cpu ppc4xx)"
 301
 302#########################################################################
 303## MPC8260 Systems (includes 8250, 8255 etc.)
 304#########################################################################
 305
 306LIST_8260="$(targets_by_cpu mpc8260)"
 307
 308#########################################################################
 309## MPC83xx Systems (includes 8349, etc.)
 310#########################################################################
 311
 312LIST_83xx="$(targets_by_cpu mpc83xx)"
 313
 314#########################################################################
 315## MPC85xx Systems (includes 8540, 8560 etc.)
 316#########################################################################
 317
 318LIST_85xx="$(targets_by_cpu mpc85xx)"
 319
 320#########################################################################
 321## MPC86xx Systems
 322#########################################################################
 323
 324LIST_86xx="$(targets_by_cpu mpc86xx)"
 325
 326#########################################################################
 327## PowerPC groups
 328#########################################################################
 329
 330LIST_TSEC="             \
 331        ${LIST_83xx}    \
 332        ${LIST_85xx}    \
 333        ${LIST_86xx}    \
 334"
 335
 336LIST_powerpc="          \
 337        ${LIST_5xx}     \
 338        ${LIST_512x}    \
 339        ${LIST_5xxx}    \
 340        ${LIST_8xx}     \
 341        ${LIST_824x}    \
 342        ${LIST_8260}    \
 343        ${LIST_83xx}    \
 344        ${LIST_85xx}    \
 345        ${LIST_86xx}    \
 346        ${LIST_4xx}     \
 347"
 348
 349# Alias "ppc" -> "powerpc" to not break compatibility with older scripts
 350# still using "ppc" instead of "powerpc"
 351LIST_ppc="              \
 352        ${LIST_powerpc} \
 353"
 354
 355#########################################################################
 356## StrongARM Systems
 357#########################################################################
 358
 359LIST_SA="$(targets_by_cpu sa1100)"
 360
 361#########################################################################
 362## ARM7 Systems
 363#########################################################################
 364
 365LIST_ARM7="$(targets_by_cpu arm720t)"
 366
 367#########################################################################
 368## ARM9 Systems
 369#########################################################################
 370
 371LIST_ARM9="$(targets_by_cpu arm920t)    \
 372        $(targets_by_cpu arm926ejs)     \
 373        $(targets_by_cpu arm946es)      \
 374"
 375
 376#########################################################################
 377## ARM11 Systems
 378#########################################################################
 379LIST_ARM11="$(targets_by_cpu arm1136)   \
 380        $(targets_by_cpu arm1176)       \
 381"
 382
 383#########################################################################
 384## ARMV7 Systems
 385#########################################################################
 386
 387LIST_ARMV7="$(targets_by_cpu armv7)"
 388
 389#########################################################################
 390## ARMV8 Systems
 391#########################################################################
 392
 393LIST_ARMV8="$(targets_by_cpu armv8)"
 394
 395#########################################################################
 396## AT91 Systems
 397#########################################################################
 398
 399LIST_at91="$(targets_by_soc at91)"
 400
 401#########################################################################
 402## Xscale Systems
 403#########################################################################
 404
 405LIST_pxa="$(targets_by_cpu pxa)"
 406
 407#########################################################################
 408## SPEAr Systems
 409#########################################################################
 410
 411LIST_spear="$(targets_by_soc spear)"
 412
 413#########################################################################
 414## ARM groups
 415#########################################################################
 416
 417LIST_arm="$(targets_by_arch arm |               \
 418        for ARMV8_TARGET in $LIST_ARMV8;        \
 419                do sed "/$ARMV8_TARGET/d";      \
 420        done)                                   \
 421"
 422
 423#########################################################################
 424## MIPS Systems         (default = big endian)
 425#########################################################################
 426
 427LIST_mips="$(targets_by_arch mips)"
 428
 429#########################################################################
 430## OpenRISC Systems
 431#########################################################################
 432
 433LIST_openrisc="$(targets_by_arch openrisc)"
 434
 435#########################################################################
 436## x86 Systems
 437#########################################################################
 438
 439LIST_x86="$(targets_by_arch x86)"
 440
 441#########################################################################
 442## Nios-II Systems
 443#########################################################################
 444
 445LIST_nios2="$(targets_by_arch nios2)"
 446
 447#########################################################################
 448## MicroBlaze Systems
 449#########################################################################
 450
 451LIST_microblaze="$(targets_by_arch microblaze)"
 452
 453#########################################################################
 454## ColdFire Systems
 455#########################################################################
 456
 457LIST_m68k="$(targets_by_arch m68k)"
 458LIST_coldfire=${LIST_m68k}
 459
 460#########################################################################
 461## AVR32 Systems
 462#########################################################################
 463
 464LIST_avr32="$(targets_by_arch avr32)"
 465
 466#########################################################################
 467## Blackfin Systems
 468#########################################################################
 469
 470LIST_blackfin="$(targets_by_arch blackfin)"
 471
 472#########################################################################
 473## SH Systems
 474#########################################################################
 475
 476LIST_sh2="$(targets_by_cpu sh2)"
 477LIST_sh3="$(targets_by_cpu sh3)"
 478LIST_sh4="$(targets_by_cpu sh4)"
 479
 480LIST_sh="$(targets_by_arch sh)"
 481
 482#########################################################################
 483## SPARC Systems
 484#########################################################################
 485
 486LIST_sparc="$(targets_by_arch sparc)"
 487
 488#########################################################################
 489## NDS32 Systems
 490#########################################################################
 491
 492LIST_nds32="$(targets_by_arch nds32)"
 493
 494#########################################################################
 495## ARC Systems
 496#########################################################################
 497
 498LIST_arc="$(targets_by_arch arc)"
 499
 500#-----------------------------------------------------------------------
 501
 502get_target_location() {
 503        local target=$1
 504        local BOARD_NAME=""
 505        local CONFIG_NAME=""
 506        local board=""
 507        local vendor=""
 508
 509        # Automatic mode
 510        local line=`awk '\$7 == "'"$target"'" { print \$0 }' boards.cfg`
 511        if [ -z "${line}" ] ; then echo "" ; return ; fi
 512
 513        set ${line}
 514
 515        CONFIG_NAME="${7%_defconfig}"
 516
 517        [ "${BOARD_NAME}" ] || BOARD_NAME="${7%_defconfig}"
 518
 519        if [ $# -gt 5 ]; then
 520                if [ "$6" = "-" ] ; then
 521                        board=${BOARD_NAME}
 522                else
 523                        board="$6"
 524                fi
 525        fi
 526
 527        [ $# -gt 4 ] && [ "$5" != "-" ] && vendor="$5"
 528        [ $# -gt 6 ] && [ "$8" != "-" ] && {
 529                tmp="${8%:*}"
 530                if [ "$tmp" ] ; then
 531                        CONFIG_NAME="$tmp"
 532                fi
 533        }
 534
 535        # Assign board directory to BOARDIR variable
 536        if [ "${vendor}" == "-" ] ; then
 537            BOARDDIR=${board}
 538        else
 539            BOARDDIR=${vendor}/${board}
 540        fi
 541
 542        echo "${CONFIG_NAME}:${BOARDDIR}:${BOARD_NAME}"
 543}
 544
 545get_target_maintainers() {
 546        local name=`echo $1 | cut -d : -f 3`
 547
 548        local line=`awk '\$7 == "'"$target"'" { print \$0 }' boards.cfg`
 549        if [ -z "${line}" ]; then
 550                echo ""
 551                return ;
 552        fi
 553
 554        local mails=`echo ${line} | cut -d ' ' -f 9- | sed -e 's/[^<]*<//' -e 's/>.*</ /' -e 's/>[^>]*$//'`
 555        [ "$mails" == "-" ] && mails=""
 556        echo "$mails"
 557}
 558
 559get_target_arch() {
 560        local target=$1
 561
 562        awk '$7 == "'$target'" { print $2 }' boards.cfg
 563}
 564
 565list_target() {
 566        if [ "$PRINT_MAINTS" != 'y' ] ; then
 567                echo "$1"
 568                return
 569        fi
 570
 571        echo -n "$1:"
 572
 573        local loc=`get_target_location $1`
 574
 575        if [ -z "${loc}" ] ; then echo "ERROR" ; return ; fi
 576
 577        local maintainers_result=`get_target_maintainers ${loc} | tr " " "\n"`
 578
 579        if [ "$MAINTAINERS_ONLY" != 'y' ] ; then
 580
 581                local dir=`echo ${loc} | cut -d ":" -f 2`
 582                local cfg=`echo ${loc} | cut -d ":" -f 1`
 583                local git_result=`git log --format=%aE board/${dir} \
 584                                include/configs/${cfg}.h | grep "@"`
 585                local git_result_recent=`echo ${git_result} | tr " " "\n" | \
 586                                                head -n 3`
 587                local git_result_top=`echo ${git_result} | tr " " "\n" | \
 588                        sort | uniq -c | sort -nr | head -n 3 | \
 589                        sed "s/^ \+[0-9]\+ \+//"`
 590
 591                echo -e "$git_result_recent\n$git_result_top\n$maintainers_result" | \
 592                        sort -u | tr "\n" " " | sed "s/ $//" ;
 593        else
 594                echo -e "$maintainers_result" | sort -u | tr "\n" " " | \
 595                                                sed "s/ $//" ;
 596        fi
 597
 598        echo ""
 599}
 600
 601# Each finished build will have a file called ${donep}${n},
 602# where n is the index of the build. Each build
 603# we've already noted as finished will have ${skipp}${n}.
 604# The code managing the build process will use this information
 605# to ensure that only BUILD_NBUILDS builds are in flight at once
 606donep="${LOG_DIR}/._done_"
 607skipp="${LOG_DIR}/._skip_"
 608
 609build_target_killed() {
 610        echo "Aborted $target build."
 611        # Remove the logs for this board since it was aborted
 612        rm -f ${LOG_DIR}/$target.MAKELOG ${LOG_DIR}/$target.ERR
 613        exit
 614}
 615
 616build_target() {
 617        target=$1
 618        build_idx=$2
 619
 620        if [ "$ONLY_LIST" == 'y' ] ; then
 621                list_target ${target}
 622                return
 623        fi
 624
 625        if [ $BUILD_MANY == 1 ] ; then
 626                output_dir="${OUTPUT_PREFIX}/${target}"
 627                mkdir -p "${output_dir}"
 628                trap build_target_killed TERM
 629        else
 630                output_dir="${OUTPUT_PREFIX}"
 631        fi
 632
 633        target_arch=$(get_target_arch ${target})
 634        eval cross_toolchain=\$CROSS_COMPILE_`echo $target_arch | tr '[:lower:]' '[:upper:]'`
 635        if [ "${cross_toolchain}" ] ; then
 636            MAKE="$GNU_MAKE CROSS_COMPILE=${cross_toolchain}"
 637        elif [ "${CROSS_COMPILE}" ] ; then
 638            MAKE="$GNU_MAKE CROSS_COMPILE=${CROSS_COMPILE}"
 639        else
 640            MAKE=$GNU_MAKE
 641        fi
 642
 643        if [  "${output_dir}" != "." ] ; then
 644                MAKE="${MAKE} O=${output_dir}"
 645        fi
 646
 647        ${MAKE} mrproper >/dev/null
 648
 649        echo "Building ${target} board..."
 650        ${MAKE} -s ${target}_defconfig >/dev/null
 651
 652        ${MAKE} ${JOBS} ${CHECK} all \
 653                >${LOG_DIR}/$target.MAKELOG 2> ${LOG_DIR}/$target.ERR
 654
 655        # Check for 'make' errors
 656        if [ ${PIPESTATUS[0]} -ne 0 ] ; then
 657                RC=1
 658        fi
 659
 660        OBJS=${output_dir}/u-boot
 661        if [ -e ${output_dir}/spl/u-boot-spl ]; then
 662                OBJS="${OBJS} ${output_dir}/spl/u-boot-spl"
 663        fi
 664
 665        ${CROSS_COMPILE}size ${OBJS} | tee -a ${LOG_DIR}/$target.MAKELOG
 666
 667        if [ $BUILD_MANY == 1 ] ; then
 668                trap - TERM
 669
 670                ${MAKE} -s clean
 671
 672                if [ -s ${LOG_DIR}/${target}.ERR ] ; then
 673                        cp ${LOG_DIR}/${target}.ERR ${OUTPUT_PREFIX}/ERR/${target}
 674                else
 675                        rm ${LOG_DIR}/${target}.ERR
 676                fi
 677        else
 678                if [ -s ${LOG_DIR}/${target}.ERR ] ; then
 679                        if grep -iw error ${LOG_DIR}/${target}.ERR ; then
 680                                : $(( ERR_CNT += 1 ))
 681                                ERR_LIST="${ERR_LIST} $target"
 682                        else
 683                                : $(( WRN_CNT += 1 ))
 684                                WRN_LIST="${WRN_LIST} $target"
 685                        fi
 686                else
 687                        rm ${LOG_DIR}/${target}.ERR
 688                fi
 689        fi
 690
 691        [ -e "${LOG_DIR}/${target}.ERR" ] && cat "${LOG_DIR}/${target}.ERR"
 692
 693        touch "${donep}${build_idx}"
 694}
 695
 696manage_builds() {
 697        search_idx=${OLDEST_IDX}
 698        if [ "$ONLY_LIST" == 'y' ] ; then return ; fi
 699
 700        while true; do
 701                if [ -e "${donep}${search_idx}" ] ; then
 702                        : $(( CURRENT_CNT-- ))
 703                        [ ${OLDEST_IDX} -eq ${search_idx} ] &&
 704                                : $(( OLDEST_IDX++ ))
 705
 706                        # Only want to count it once
 707                        rm -f "${donep}${search_idx}"
 708                        touch "${skipp}${search_idx}"
 709                elif [ -e "${skipp}${search_idx}" ] ; then
 710                        [ ${OLDEST_IDX} -eq ${search_idx} ] &&
 711                                : $(( OLDEST_IDX++ ))
 712                fi
 713                : $(( search_idx++ ))
 714                if [ ${search_idx} -gt ${TOTAL_CNT} ] ; then
 715                        if [ ${CURRENT_CNT} -ge ${BUILD_NBUILDS} ] ; then
 716                                search_idx=${OLDEST_IDX}
 717                                sleep 1
 718                        else
 719                                break
 720                        fi
 721                fi
 722        done
 723}
 724
 725build_targets() {
 726        for t in "$@" ; do
 727                # If a LIST_xxx var exists, use it.  But avoid variable
 728                # expansion in the eval when a board name contains certain
 729                # characters that the shell interprets.
 730                case ${t} in
 731                        *[-+=]*) list= ;;
 732                        *)       list=$(eval echo '${LIST_'$t'}') ;;
 733                esac
 734                if [ -n "${list}" ] ; then
 735                        build_targets ${list}
 736                else
 737                        : $((TOTAL_CNT += 1))
 738                        : $((CURRENT_CNT += 1))
 739                        rm -f "${donep}${TOTAL_CNT}"
 740                        rm -f "${skipp}${TOTAL_CNT}"
 741                        if [ "$CONTINUE" = 'y' -a -e ${LOG_DIR}/$t.MAKELOG ] ; then
 742                                : $((SKIP_CNT += 1))
 743                                touch "${donep}${TOTAL_CNT}"
 744                        elif [ "$REBUILD_ERRORS" = 'y' -a ! -e ${LOG_DIR}/$t.ERR ] ; then
 745                                : $((SKIP_CNT += 1))
 746                                touch "${donep}${TOTAL_CNT}"
 747                        else
 748                                if [ $BUILD_MANY == 1 ] ; then
 749                                        build_target ${t} ${TOTAL_CNT} &
 750                                else
 751                                        CUR_TGT="${t}"
 752                                        build_target ${t} ${TOTAL_CNT}
 753                                        CUR_TGT=''
 754                                fi
 755                        fi
 756                fi
 757
 758                # We maintain a running count of all the builds we have done.
 759                # Each finished build will have a file called ${donep}${n},
 760                # where n is the index of the build. Each build
 761                # we've already noted as finished will have ${skipp}${n}.
 762                # We track the current index via TOTAL_CNT, and the oldest
 763                # index. When we exceed the maximum number of parallel builds,
 764                # We look from oldest to current for builds that have completed,
 765                # and update the current count and oldest index as appropriate.
 766                # If we've gone through the entire list, wait a second, and
 767                # reprocess the entire list until we find a build that has
 768                # completed
 769                if [ ${CURRENT_CNT} -ge ${BUILD_NBUILDS} ] ; then
 770                        manage_builds
 771                fi
 772        done
 773}
 774
 775#-----------------------------------------------------------------------
 776
 777kill_children() {
 778        local OS=$(uname -s)
 779        local children=""
 780        case "${OS}" in
 781                "Darwin")
 782                        # Mac OS X is known to have BSD style ps
 783                        local pgid=$(ps -p $$ -o pgid | sed -e "/PGID/d")
 784                        children=$(ps -g $pgid -o pid | sed -e "/PID\|$$\|$pgid/d")
 785                        ;;
 786                *)
 787                        # everything else tries the GNU style
 788                        local pgid=$(ps -p $$ --no-headers -o "%r" | tr -d ' ')
 789                        children=$(pgrep -g $pgid | sed -e "/$$\|$pgid/d")
 790                        ;;
 791        esac
 792
 793        kill $children 2> /dev/null
 794        wait $children 2> /dev/null
 795
 796        exit
 797}
 798
 799print_stats() {
 800        if [ "$ONLY_LIST" == 'y' ] ; then return ; fi
 801
 802        # Only count boards that completed
 803        : $((TOTAL_CNT = `find ${skipp}* 2> /dev/null | wc -l`))
 804
 805        rm -f ${donep}* ${skipp}*
 806
 807        if [ $BUILD_MANY == 1 ] && [ -e "${OUTPUT_PREFIX}/ERR" ] ; then
 808                ERR_LIST=`grep -riwl error ${OUTPUT_PREFIX}/ERR/`
 809                ERR_LIST=`for f in $ERR_LIST ; do echo -n " $(basename $f)" ; done`
 810                ERR_CNT=`echo $ERR_LIST | wc -w | awk '{print $1}'`
 811                WRN_LIST=`grep -riwL error ${OUTPUT_PREFIX}/ERR/`
 812                WRN_LIST=`for f in $WRN_LIST ; do echo -n " $(basename $f)" ; done`
 813                WRN_CNT=`echo $WRN_LIST | wc -w | awk '{print $1}'`
 814        else
 815                # Remove the logs for any board that was interrupted
 816                rm -f ${LOG_DIR}/${CUR_TGT}.MAKELOG ${LOG_DIR}/${CUR_TGT}.ERR
 817        fi
 818
 819        : $((TOTAL_CNT -= ${SKIP_CNT}))
 820        echo ""
 821        echo "--------------------- SUMMARY ----------------------------"
 822        if [ "$CONTINUE" = 'y' -o "$REBUILD_ERRORS" = 'y' ] ; then
 823                echo "Boards skipped: ${SKIP_CNT}"
 824        fi
 825        echo "Boards compiled: ${TOTAL_CNT}"
 826        if [ ${ERR_CNT} -gt 0 ] ; then
 827                echo "Boards with errors: ${ERR_CNT} (${ERR_LIST} )"
 828        fi
 829        if [ ${WRN_CNT} -gt 0 ] ; then
 830                echo "Boards with warnings but no errors: ${WRN_CNT} (${WRN_LIST} )"
 831        fi
 832        echo "----------------------------------------------------------"
 833
 834        if [ $BUILD_MANY == 1 ] ; then
 835                kill_children
 836        fi
 837
 838        deprecation
 839
 840        exit $RC
 841}
 842
 843#-----------------------------------------------------------------------
 844
 845# Build target groups selected by options, plus any command line args
 846set -- ${SELECTED} "$@"
 847# run PowerPC by default
 848[ $# = 0 ] && set -- powerpc
 849build_targets "$@"
 850wait
 851