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