1#!/bin/sh
2#
3# Copyright (C) 2010 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17#  This shell script is used to run all NDK build tests in a row.
18#  "Build tests" are tests that check the building features of the NDK
19#  but do not run anything on target devices/emulators.
20#
21
22#  You need to define the NDK
23
24PROGDIR=`dirname $0`
25PROGDIR=`cd $PROGDIR && pwd`
26
27# Assume that we are under tests/
28# and that the samples will be under samples/ and platforms/android-N/samples/
29#
30ROOTDIR=`cd $PROGDIR/.. && pwd`
31NDK_BUILDTOOLS_PATH=$ROOTDIR/build/tools
32. $NDK_BUILDTOOLS_PATH/ndk-common.sh
33. $NDK_BUILDTOOLS_PATH/prebuilt-common.sh
34
35# Defining _NDK_TESTING_ALL_=yes to put armeabi-v7a-hard in its own libs/armeabi-v7a-hard
36# directoy and tested separately from armeabi-v7a.  Some tests are now compiled with both
37# APP_ABI=armeabi-v7a and APP_ABI=armeabi-v7a-hard. Without _NDK_TESTING_ALL_=yes, tests
38# may fail to install due to race condition on the same libs/armeabi-v7a
39if [ -z "$_NDK_TESTING_ALL_" ]; then
40   _NDK_TESTING_ALL_=all
41fi
42export _NDK_TESTING_ALL_
43
44# The list of tests that are too long to be part of a normal run of
45# run-tests.sh. Most of these do not run properly at the moment.
46LONG_TESTS="prebuild-stlport test-stlport test-gnustl-full \
47test-stlport_shared-exception test-stlport_static-exception \
48test-gnustl_shared-exception-full test-gnustl_static-exception-full \
49test-googletest-full test-libc++-shared-full test-libc++-static-full"
50
51#
52# Parse options
53#
54VERBOSE=no
55ABI=default
56PLATFORM=""
57NDK_ROOT=
58JOBS=$BUILD_NUM_CPUS
59find_program ADB_CMD adb
60TESTABLES="samples build device awk"
61FULL_TESTS=no
62RUN_TESTS=
63RUN_TESTS_FILTERED=
64NDK_PACKAGE=
65WINE=
66CONTINUE_ON_BUILD_FAIL=
67if [ -z "$TEST_DIR" ]; then
68    TEST_DIR="/tmp/ndk-$USER/tests"
69fi
70if [ -z "$TARGET_TEST_SUBDIR" ]; then
71    TARGET_TEST_SUBDIR="ndk-tests"
72fi
73
74while [ -n "$1" ]; do
75    opt="$1"
76    optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
77    case "$opt" in
78        --help|-h|-\?)
79            OPTION_HELP=yes
80            ;;
81        --verbose)
82            if [ "$VERBOSE" = "yes" ] ; then
83                VERBOSE2=yes
84            else
85                VERBOSE=yes
86            fi
87            ;;
88        --abi=*)
89            ABI="$optarg"
90            ;;
91        --platform=*)
92            PLATFORM="$optarg"
93	    ;;
94        --test-dir=*)
95            TEST_DIR="$optarg"
96            ;;
97        --ndk=*)
98            NDK_ROOT="$optarg"
99            ;;
100        --full)
101            FULL_TESTS=yes;
102            ;;
103        --test=*)
104            RUN_TESTS="$RUN_TESTS $optarg"
105            ;;
106        --test-filtered=*)
107            # same as --test but apply BROKEN_RUN too. Useful for projects with tons of test some of them can't run
108            RUN_TESTS="$RUN_TESTS $optarg"
109            RUN_TESTS_FILTERED="yes"
110            ;;
111        --package=*)
112            NDK_PACKAGE="$optarg"
113            ;;
114        -j*)
115            JOBS=`expr "$opt" : '-j\(.*\)'`
116            shift
117            ;;
118        --jobs=*)
119            JOBS="$optarg"
120            ;;
121        --adb=*)
122            ADB_CMD="$optarg"
123            ;;
124        --only-samples)
125            TESTABLES=samples
126            ;;
127        --only-build)
128            TESTABLES=build
129            ;;
130        --only-device)
131            TESTABLES=device
132            ;;
133        --only-awk)
134            TESTABLES=awk
135            ;;
136        --wine)
137            WINE=yes
138            ;;
139        --continue-on-build-fail)
140            CONTINUE_ON_BUILD_FAIL=yes
141            ;;
142        -*) # unknown options
143            echo "ERROR: Unknown option '$opt', use --help for list of valid ones."
144            exit 1
145        ;;
146        *)  # Simply record new test name
147            RUN_TESTS=$RUN_TESTS" $opt"
148            ;;
149    esac
150    shift
151done
152
153if [ "$OPTION_HELP" = "yes" ] ; then
154    echo "Usage: $PROGNAME [options] [testname1 [testname2...]]"
155    echo ""
156    echo "Run NDK automated tests. Without any parameter, this will try to"
157    echo "run all standard tests, except those are tagged broken. You can"
158    echo "also select/enforce specific tests by listing their name on the"
159    echo "command-line."
160    echo ""
161    echo "Valid options:"
162    echo ""
163    echo "    --help|-h|-?      Print this help"
164    echo "    --verbose         Enable verbose mode (can be used several times)"
165    echo "    --ndk=<path>      Path to NDK to test [$ROOTDIR]"
166    echo "    --package=<path>  Path to NDK package to test"
167    echo "    -j<N> --jobs=<N>  Launch parallel builds [$JOBS]"
168    echo "    --abi=<name>      Only run tests for the specific ABI [$ABI]"
169    echo "    --platform=<name> Force API level for testing; platform=<android-x>"
170    echo "    --adb=<file>      Specify adb executable for device tests"
171    echo "    --only-samples    Only rebuild samples"
172    echo "    --only-build      Only rebuild build tests"
173    echo "    --only-device     Only rebuild & run device tests"
174    echo "    --only-awk        Only run awk tests."
175    echo "    --full            Run all device tests, even very long ones."
176    echo "    --wine            Build all tests with wine on Linux"
177    echo ""
178    echo "NOTE: You cannot use --ndk and --package at the same time."
179    echo ""
180    exit 0
181fi
182
183# Run a command in ADB.
184#
185# This is needed because "adb shell" does not return the proper status
186# of the launched command, so we need to add it to the output, and grab
187# it after that.
188# $1: Device name
189# $2: Variable name that will contain the result
190# $3+: Command options
191adb_var_shell_cmd ()
192{
193    # We need a temporary file to store the output of our command
194    local ADB_SHELL_CMD_LOG RET OUT
195    local DEVICE=$1
196    local VARNAME=$2
197    shift; shift;
198    ADB_SHELL_CMD_LOG=$(mktemp -t XXXXXXXX)
199    # Run the command, while storing the standard output to ADB_SHELL_CMD_LOG
200    # and appending the exit code as the last line.
201    if [ $VERBOSE = "yes" ] ; then
202        echo "$ADB_CMD -s \"$DEVICE\" shell \"$@\""
203        $ADB_CMD -s "$DEVICE" shell "$@" ";" echo \$? | sed -e 's![[:cntrl:]]!!g' | tee $ADB_SHELL_CMD_LOG
204    else
205        $ADB_CMD -s "$DEVICE" shell "$@" ";" echo \$? | sed -e 's![[:cntrl:]]!!g' > $ADB_SHELL_CMD_LOG
206    fi
207    # Get last line in log, which contains the exit code from the command
208    RET=`sed -e '$!d' $ADB_SHELL_CMD_LOG`
209    # Get output, which corresponds to everything except the last line
210    OUT=`sed -e '$d' $ADB_SHELL_CMD_LOG`
211    rm -f $ADB_SHELL_CMD_LOG
212    if [ "$VARNAME" != "" ]; then
213        eval $VARNAME=\"\$OUT\"
214    fi
215    return $RET
216}
217
218# Make a directory path on device
219#
220# The 'mkdir' command on the Android device does not
221# support the '-p' option. This function will test
222# for the existence of the parent directory and recursively
223# call itself until it files a parent which exists; then
224# create the requested directory.
225adb_shell_mkdir ()
226{
227    local FULLDIR BASEDIR
228    local DEVICE=$1
229    local FULLDIR=$2
230    local BASEDIR=`dirname $FULLDIR`
231
232    adb_var_shell_cmd "$DEVICE" "" "ls $BASEDIR 1>/dev/null 2>&1"
233    if [ $? != 0 ] ; then
234        if [ $BASEDIR = "/" ] ; then
235            dump "ERROR: Could not find the root (/) directory on the device!"
236            exit 1
237        else
238            adb_shell_mkdir "$DEVICE" $BASEDIR
239            adb_shell_mkdir "$DEVICE" $FULLDIR
240        fi
241    else
242        #If the directory doesn't exist, make it
243        adb_var_shell_cmd "$DEVICE" "" "ls $FULLDIR 1>/dev/null 2>&1 || mkdir $FULLDIR"
244        if [ $? != 0 ] ; then
245            dump "ERROR: Could not mkdir '$FULLDIR' on the device!"
246            exit 1
247        fi
248    fi
249}
250
251# Returns 0 if a variable containing one or more items separated
252# by spaces contains a given value.
253# $1: variable name (e.g. FOO)
254# $2: value to test
255var_list_contains ()
256{
257    echo `var_value $1` | tr ' ' '\n' | grep -q -F -x -e "$2"
258}
259
260#
261# List of stuff to actually tests
262#
263is_testable () {
264    var_list_contains TESTABLES "$1"
265}
266
267# is_buildable returns 0 if a test should be built/run for this invocation
268# $1: test path
269if [ -n "$RUN_TESTS" ] ; then
270    is_buildable () {
271        [ -f $1/build.sh -o -f $1/jni/Android.mk ] &&
272        var_list_contains RUN_TESTS "`basename $1`"
273    }
274elif [ "$FULL_TESTS" = "yes" ] ; then
275    is_buildable () {
276        [ -f $1/build.sh -o -f $1/jni/Android.mk ]
277    }
278else # !FULL_TESTS
279    is_buildable () {
280        [ -f $1/build.sh -o -f $1/jni/Android.mk ] || return 1
281        ! var_list_contains LONG_TESTS "`basename $1`" || return 1
282    }
283fi # !FULL_TESTS
284
285
286mkdir -p $TEST_DIR
287setup_default_log_file "$TEST_DIR/build-tests.log"
288
289if [ -n "$NDK_PACKAGE" ] ; then
290    if [ -n "$NDK_ROOT" ] ; then
291        dump "ERROR: You can't use --ndk and --package at the same time!"
292        exit 1
293    fi
294    NDK_ROOT=/tmp/ndk-tests/install
295    mkdir -p  "$NDK_ROOT" && rm -rf "$NDK_ROOT/*"
296    dump "Unpacking NDK package to $NDK_ROOT"
297    unpack_archive "$NDK_PACKAGE" "$NDK_ROOT"
298    NDK_ROOT=`ls -d $NDK_ROOT/*`
299fi
300
301#
302# Check the NDK install path.
303#
304if [ -n "$NDK_ROOT" ] ; then
305    if [ ! -d "$NDK_ROOT" ] ; then
306        dump "ERROR: Your --ndk option does not point to a directory: $NDK_ROOT"
307        dump "Please use a valid path for this option."
308        exit 1
309    fi
310    if [ ! -f "$NDK_ROOT/ndk-build" -o ! -f "$NDK_ROOT/build/tools/prebuilt-common.sh" ] ; then
311        dump "ERROR: Your --ndk option does not point to a valid NDK install: $NDK_ROOT"
312        dump "Please use a valid NDK install path for this option."
313        exit 3
314    fi
315    NDK="$NDK_ROOT"
316else
317    NDK="$ROOTDIR"
318fi
319
320#
321# Create log file
322#
323
324BUILD_DIR=$TEST_DIR/build
325mkdir -p "$BUILD_DIR" && rm -rf "$BUILD_DIR/*"
326
327#
328# Add -link-native-binary to allow linking native binaries
329#
330if [ "$NDK_ABI_FILTER" != "${NDK_ABI_FILTER%%bc*}" ] ; then
331  APP_LDFLAGS="$APP_LDFLAGS -Wl,-link-native-binary"
332fi
333
334
335###
336### RUN AWK TESTS
337###
338
339# Run a simple awk script
340# $1: awk script to run
341# $2: input file
342# $3: expected output file
343# $4+: optional additional command-line arguments for the awk command
344run_awk_test ()
345{
346    local SCRIPT="$1"
347    local SCRIPT_NAME="`basename $SCRIPT`"
348    local INPUT="$2"
349    local INPUT_NAME="`basename $INPUT`"
350    local EXPECTED="$3"
351    local EXPECTED_NAME="`basename $EXPECTED`"
352    shift; shift; shift;
353    local OUTPUT="$BUILD_DIR/$EXPECTED_NAME"
354    if [ "$VERBOSE2" = "yes" ]; then
355        echo "### COMMAND: awk -f \"$SCRIPT\" $@ < \"$INPUT\" > \"$OUTPUT\""
356    fi
357    awk -f "$SCRIPT" $@ < "$INPUT" > "$OUTPUT"
358    fail_panic "Can't run awk script: $SCRIPT"
359    if [ "$VERBOSE2" = "yes" ]; then
360        echo "OUTPUT FROM SCRIPT:"
361        cat "$OUTPUT"
362        echo "EXPECTED VALUES:"
363        cat "$EXPECTED"
364    fi
365    cmp -s "$OUTPUT" "$EXPECTED"
366    if [ $? = 0 ] ; then
367        echo "Awk script: $SCRIPT_NAME: passed $INPUT_NAME"
368        if [ "$VERBOSE2" = "yes" ]; then
369            cat "$OUTPUT"
370        fi
371    else
372        if [ "$VERBOSE" = "yes" ]; then
373            run diff -burN "$EXPECTED" "$OUTPUT"
374        fi
375        echo "Awk script: $SCRIPT_NAME: $INPUT_NAME FAILED!!"
376        rm -f "$OUTPUT"
377        exit 1
378    fi
379}
380
381run_awk_test_dir ()
382{
383    local SCRIPT_NAME="`basename \"$DIR\"`"
384    local SCRIPT="$ROOTDIR/build/awk/$SCRIPT_NAME.awk"
385    local INPUT
386    local OUTPUT
387    if [ ! -f "$SCRIPT" ]; then
388        echo "Awk script: $SCRIPT_NAME: Missing script: $SCRIPT"
389        continue
390    fi
391    for INPUT in `ls "$PROGDIR"/awk/$SCRIPT_NAME/*.in`; do
392        OUTPUT=`echo $INPUT | sed 's/\.in$/.out/g'`
393        if [ ! -f "$OUTPUT" ]; then
394            echo "Awk script: $SCRIPT_NAME: Missing awk output file: $OUTPUT"
395            continue
396        fi
397        run_awk_test "$SCRIPT" "$INPUT" "$OUTPUT"
398    done
399}
400
401if is_testable awk; then
402    AWKDIR="$ROOTDIR/build/awk"
403    for DIR in `ls -d "$PROGDIR"/awk/*`; do
404        run_awk_test_dir "$DIR"
405    done
406fi
407
408###
409###  REBUILD ALL SAMPLES FIRST
410###
411
412NDK_BUILD_FLAGS="-B"
413if [ "$WINE" ]; then
414    case "$NDK_HOST_32BIT" in
415        1|true)
416            WINE=wine12
417            ;;
418        *)
419            WINE=wine17
420            NDK_BUILD_FLAGS=""  # make.exe -B hangs in wine > 1.2.x
421            if [ "$NDK_TOOLCHAIN_VERSION" != "4.4.3" ] ; then
422                APP_LDFLAGS="$APP_LDFLAGS -fuse-ld=mcld" # 64-bit ld.gold can't run in any wine!
423            fi
424            ;;
425    esac
426    find_program WINE_PROG $WINE
427    fail_panic "Can't locate $WINE"
428fi
429
430# $1: output bitcode path
431gen_empty_bitcode() {
432    TEMP_FILE=`mktemp`
433    mv $TEMP_FILE ${TEMP_FILE}.c
434    run $NDK/$(get_llvm_toolchain_binprefix $DEFAULT_LLVM_VERSION)/clang -shared -target le32-none-ndk -emit-llvm -o $1 ${TEMP_FILE}.c
435    rm -f ${TEMP_FILE}.c
436}
437
438# $1: output archive path
439gen_empty_archive() {
440    run ar crs $1
441}
442
443case $ABI in
444    default)  # Let the APP_ABI in jni/Application.mk decide what to build
445        ;;
446    armeabi|armeabi-v7a|arm64-v8a|x86|x86_64|mips|mips64|armeabi-v7a-hard)
447        NDK_BUILD_FLAGS="$NDK_BUILD_FLAGS APP_ABI=$ABI"
448        ;;
449    *)
450        if [ -n "$(filter_out "$PREBUILT_ABIS" "$ABI")" ] && [ -n "$(find_ndk_unknown_archs)" ]; then
451            ABI=$(find_ndk_unknown_archs)
452            NDK_BUILD_FLAGS="$NDK_BUILD_FLAGS APP_ABI=$ABI"
453
454            # Create those temporarily files to make testing happy
455            GCC_TOOLCHAIN_VERSION=`cat $NDK/toolchains/llvm-$DEFAULT_LLVM_VERSION/setup.mk | grep '^TOOLCHAIN_VERSION' | awk '{print $3'}`
456            run mkdir -p $NDK/$GNUSTL_SUBDIR/$GCC_TOOLCHAIN_VERSION/libs/$ABI
457            run mkdir -p $NDK/$GABIXX_SUBDIR/libs/$ABI
458            run mkdir -p $NDK/$LIBPORTABLE_SUBDIR/libs/$ABI
459            run gen_empty_archive $NDK/$GNUSTL_SUBDIR/$GCC_TOOLCHAIN_VERSION/libs/$ABI/libsupc++.a
460            run gen_empty_archive $NDK/$GNUSTL_SUBDIR/$GCC_TOOLCHAIN_VERSION/libs/$ABI/libgnustl_static.a
461            run gen_empty_bitcode $NDK/$GNUSTL_SUBDIR/$GCC_TOOLCHAIN_VERSION/libs/$ABI/libgnustl_shared.bc
462            run gen_empty_archive $NDK/$GABIXX_SUBDIR/libs/$ABI/libgabi++_static.a
463            run gen_empty_bitcode $NDK/$GABIXX_SUBDIR/libs/$ABI/libgabi++_shared.bc
464            run cp -a $NDK/$GNUSTL_SUBDIR/$GCC_TOOLCHAIN_VERSION/libs/$(get_default_abi_for_arch arm)/include $NDK/$GNUSTL_SUBDIR/$GCC_TOOLCHAIN_VERSION/libs/$ABI
465        else
466            echo "ERROR: Unsupported abi value: $ABI"
467            exit 1
468        fi
469        ;;
470esac
471
472# Force all tests to run at one API level
473if [ "$PLATFORM" != "" ]; then
474    NDK_BUILD_FLAGS="$NDK_BUILD_FLAGS APP_PLATFORM=$PLATFORM"
475fi
476
477# Use --verbose twice to see build commands for the tests
478if [ "$VERBOSE2" = "yes" ] ; then
479    NDK_BUILD_FLAGS="$NDK_BUILD_FLAGS V=1"
480fi
481
482run_ndk_build ()
483{
484    if [ "$WINE" ]; then
485        if [ "$WINE" = "wine12" ]; then
486            run $WINE cmd /c Z:$NDK/ndk-build.cmd -j$JOBS "$@" APP_LDFLAGS="$APP_LDFLAGS" APP_CFLAGS="$APP_CFLAGS"
487        else
488            # do "clean" instead of -B
489            run $WINE cmd /c Z:$NDK/ndk-build.cmd clean
490            # make.exe can't do parallel build in wine > 1.2.x
491            run $WINE cmd /c Z:$NDK/ndk-build.cmd "$@" -j1 APP_LDFLAGS="$APP_LDFLAGS" APP_CFLAGS="$APP_CFLAGS"
492        fi
493    else
494        run $NDK/ndk-build -j$JOBS "$@" APP_LDFLAGS="$APP_LDFLAGS" APP_CFLAGS="$APP_CFLAGS"
495    fi
496}
497
498# get build var
499# $1: project directory
500# $2: var
501get_build_var ()
502{
503    local PROJECT=$1
504    local VAR=$2
505
506    if [ -z "$GNUMAKE" ] ; then
507        GNUMAKE=make
508    fi
509    $GNUMAKE --no-print-dir -f $NDK/build/core/build-local.mk -C $PROJECT DUMP_$VAR | tail -1
510}
511
512
513# check if the project is broken and shouldn't be built
514# $1: project directory
515# $2: optional error message
516is_broken_build ()
517{
518    local PROJECT="$1"
519    local ERRMSG="$2"
520
521    if [ -z "$RUN_TESTS" ] ; then
522        if [ -f "$PROJECT/BROKEN_BUILD" ] ; then
523            if [ ! -s "$PROJECT/BROKEN_BUILD" ] ; then
524                # skip all
525                if [ -z "$ERRMSG" ] ; then
526                    echo "Skipping `basename $PROJECT`: (build)"
527                else
528                    echo "Skipping $ERRMSG: `basename $PROJECT`"
529                fi
530                return 0
531            else
532                # only skip listed in file
533                TARGET_TOOLCHAIN=`get_build_var $PROJECT TARGET_TOOLCHAIN`
534                TARGET_TOOLCHAIN_VERSION=`echo $TARGET_TOOLCHAIN | tr '-' '\n' | tail -1`
535                grep -q -e "$TARGET_TOOLCHAIN_VERSION" "$PROJECT/BROKEN_BUILD"
536                if [ $? = 0 ] ; then
537                    if [ -z "$ERRMSG" ] ; then
538                        echo "Skipping `basename $PROJECT`: (no build for $TARGET_TOOLCHAIN_VERSION)"
539                    else
540                        echo "Skipping $ERRMSG: `basename $PROJECT` (no build for $TARGET_TOOLCHAIN_VERSION)"
541                    fi
542                    return 0
543                fi
544                # skip incompatible forced platform
545                if [ "$PLATFORM" != "" ] ; then
546                    grep -q -e "$PLATFORM" "$PROJECT/BROKEN_BUILD" || grep -q -e "android-forced" "$PROJECT/BROKEN_BUILD"
547                    if [ $? = 0 ] ; then
548                        if [ -z "$ERRMSG" ] ; then
549                            echo "Skipping `basename $PROJECT`: (no build for $PLATFORM)"
550                        else
551                            echo "Skipping $ERRMSG: `basename $PROJECT` (no build for $PLATFORM)"
552                        fi
553                        return 0
554                    fi
555                fi
556            fi
557        fi
558    fi
559    return 1
560}
561
562# check if $ABI is incompatible and shouldn't be built
563# $1: project directory
564is_incompatible_abi ()
565{
566    local PROJECT="$1"
567    # Basically accept all for unknown arch, even some cases may not be suitable for this way
568    if [ "$ABI" != "default" -a "$ABI" != "$(find_ndk_unknown_archs)" ] ; then
569        # check APP_ABI
570        local APP_ABIS=`get_build_var $PROJECT APP_ABI`
571        APP_ABIS=$APP_ABIS" "
572        if [ "$APP_ABIS" != "${APP_ABIS%%all*}" ] ; then
573        # replace "all", "all32" and "all64"
574          _EXPANDED=`get_build_var $PROJECT NDK_APP_ABI_ALL_EXPANDED`
575          _FRONT="${APP_ABIS%%all*}"
576          _BACK="${APP_ABIS#*all}"
577          APP_ABIS="${_FRONT}${_EXPANDED}${_BACK}"
578          _EXPANDED=`get_build_var $PROJECT NDK_APP_ABI_ALL32_EXPANDED`
579          _FRONT="${APP_ABIS%%all32*}"
580          _BACK="${APP_ABIS#*all32}"
581          APP_ABIS="${_FRONT}${_EXPANDED}${_BACK}"
582          _EXPANDED=`get_build_var $PROJECT NDK_APP_ABI_ALL64_EXPANDED`
583          _FRONT="${APP_ABIS%%all64*}"
584          _BACK="${APP_ABIS#*all64}"
585          APP_ABIS="${_FRONT}${_EXPANDED}${_BACK}"
586        fi
587        if [ "$APP_ABIS" = "${APP_ABIS%$ABI *}" ] ; then
588            echo "Skipping `basename $PROJECT`: incompatible ABI, needs $APP_ABIS"
589            return 0
590        fi
591    fi
592    return 1
593}
594
595compile_on_the_fly()
596{
597    local DSTDIR="$1"
598    local COMPILER_PKGNAME="compiler.abcc"
599    if [ -z "`$ADB_CMD -s "$DEVICE" shell pm path $COMPILER_PKGNAME`" ]; then
600        dump "ERROR: No abcc found for unknown arch testing"
601        return 1
602    fi
603    run $ADB_CMD -s "$DEVICE" shell am force-stop $COMPILER_PKGNAME
604    run $ADB_CMD -s "$DEVICE" shell am startservice --user 0 -a ${COMPILER_PKGNAME}.BITCODE_COMPILE_TEST -n $COMPILER_PKGNAME/.AbccService -e working_dir $DSTDIR
605
606    old_pid="`$ADB_CMD -s "$DEVICE" shell top -n 1 | grep $COMPILER_PKGNAME | awk '{print $1}'`"
607    threshold=`echo $((60*10))` # Wait at most 10 minutes for large testcases
608    sleep_seconds=0
609    while [ 2 -eq 2 ]; do
610      if [ $sleep_seconds -gt $threshold ]; then
611        pid="`$ADB_CMD -s "$DEVICE" shell top -n 1 | grep $COMPILER_PKGNAME | awk '{print $1}'`"
612        if [ "$pid" = "$old_pid" ]; then
613          # Too much time
614          break
615        fi
616        old_pid="$pid"
617        sleep_seconds=0
618      fi
619      if [ -n "`$ADB_CMD -s "$DEVICE" shell ls $DSTDIR | grep compile_result`" ]; then
620        # Compile done
621        break
622      fi
623      sleep 3
624      sleep_seconds="`echo $sleep_seconds + 3 | bc`"
625    done
626    ret="`$ADB_CMD -s "$DEVICE" shell cat $DSTDIR/compile_result`"
627    ret=`echo $ret | tr -d "\r\n"`
628    if [ $sleep_seconds -gt $threshold ] || [ "$ret" != "0" ]; then
629      dump "ERROR: Could not compile bitcodes for $TEST_NAME on device"
630      if [ $sleep_seconds -gt $threshold ]; then
631        dump "- Reason: Compile time too long"
632      elif [ -n "`$ADB_CMD -s "$DEVICE" shell ls $DSTDIR | grep compile_error`" ]; then
633        dump "- Reason: `$ADB_CMD -s "$DEVICE" shell cat $DSTDIR/compile_error`"
634      fi
635      run $ADB_CMD -s "$DEVICE" shell am force-stop $COMPILER_PKGNAME
636      return 1
637    fi
638    run $ADB_CMD -s "$DEVICE" shell am force-stop $COMPILER_PKGNAME
639    return 0
640}
641
642
643build_project ()
644{
645    local NAME=`basename $1`
646    local CHECK_ABI=$2
647    local DIR="$BUILD_DIR/$NAME"
648
649    if is_broken_build $1; then
650        return 0;
651    fi
652    if [ "$CHECK_ABI" = "yes" ] ; then
653        if is_incompatible_abi $1 ; then
654            return 0
655        fi
656    fi
657    rm -rf "$DIR" && cp -r "$1" "$DIR"
658    # build it
659    (run cd "$DIR" && run_ndk_build $NDK_BUILD_FLAGS)
660    RET=$?
661    if [ -f "$1/BUILD_SHOULD_FAIL" ]; then
662        if [ $RET = 0 ]; then
663            echo "!!! FAILURE: BUILD SHOULD HAVE FAILED [$1]"
664            if [ "$CONTINUE_ON_BUILD_FAIL" != yes ] ; then
665                exit 1
666            fi
667        fi
668        log "!!! SUCCESS: BUILD FAILED AS EXPECTED [$(basename $1)]"
669        RET=0
670    fi
671    if [ $RET != 0 ] ; then
672        echo "!!! BUILD FAILURE [$1]!!! See $NDK_LOGFILE for details or use --verbose option!"
673        if [ "$CONTINUE_ON_BUILD_FAIL" != yes ] ; then
674            exit 1
675        fi
676    fi
677}
678
679#
680# Determine list of samples directories.
681#
682if is_testable samples; then
683    if [ -f "$NDK/RELEASE.TXT" ] ; then
684        # This is a release package, all samples should be under $NDK/samples
685        SAMPLES_DIRS="$NDK/samples"
686        if [ ! -d "$SAMPLES_DIRS" ] ; then
687            dump "ERROR: Missing samples directory: $SAMPLES_DIRS"
688            dump "Your NDK release installation is broken!"
689            exit 1
690        fi
691        log "Using release NDK samples from: $SAMPLES_DIRS"
692    else
693        # This is a development work directory, we will take the samples
694        # directly from development/ndk.
695        DEVNDK_DIR=`dirname $NDK`/development/ndk
696        if [ ! -d "$DEVNDK_DIR" ] ; then
697            dump "ERROR: Could not find development NDK directory: $DEVNDK_DIR"
698            dump "Please clone platform/development.git from android.googlesource.com"
699            exit 1
700        fi
701        SAMPLES_DIRS="$DEVNDK_DIR/samples"
702        for DIR in `ls -d $DEVNDK_DIR/platforms/android-*/samples`; do
703            SAMPLES_DIRS="$SAMPLES_DIRS $DIR"
704        done
705        dump "Using development NDK samples from $DEVNDK_DIR"
706        if [ "$VERBOSE" = "yes" ] ; then
707            echo "$SAMPLES_DIRS" | tr ' ' '\n'
708        fi
709    fi
710
711    #
712    # Copy the samples to a temporary build directory
713
714    build_sample ()
715    {
716        echo "Building NDK sample: `basename $1`"
717        build_project $1 "no"
718    }
719
720    for DIR in $SAMPLES_DIRS; do
721        for SUBDIR in `ls -d $DIR/*`; do
722            if is_buildable $SUBDIR; then
723                build_sample $SUBDIR
724            fi
725        done
726    done
727fi
728
729###
730###  BUILD PROJECTS UNDER tests/build/
731###
732
733if is_testable build; then
734    build_build_test ()
735    {
736        local NAME="$(basename $1)"
737        echo "Building NDK build test: `basename $1`"
738        if [ -f $1/build.sh ]; then
739            local DIR="$BUILD_DIR/$NAME"
740            if [ -f "$1/jni/Android.mk" -a -f "$1/jni/Application.mk" ] ; then
741                # exclude jni/Android.mk with import-module because it needs NDK_MODULE_PATH
742                grep -q  "call import-module" "$1/jni/Android.mk"
743                if [ $? != 0 ] ; then
744                    if (is_broken_build $1 || is_incompatible_abi $1) then
745                        return 0;
746                    fi
747                fi
748            fi
749            rm -rf "$DIR" && cp -r "$1" "$DIR"
750            export NDK
751            (cd "$DIR" && run ./build.sh -j$JOBS $NDK_BUILD_FLAGS)
752            if [ $? != 0 ]; then
753                echo "!!! BUILD FAILURE [$1]!!! See $NDK_LOGFILE for details or use --verbose option!"
754                if [ "$CONTINUE_ON_BUILD_FAIL" != yes ] ; then
755                    exit 1
756                fi
757            fi
758        else
759            build_project $1 "yes"
760        fi
761    }
762
763    for DIR in `ls -d $ROOTDIR/tests/build/*`; do
764        if is_buildable $DIR; then
765            build_build_test $DIR
766        fi
767    done
768fi
769
770###
771###  BUILD PROJECTS UNDER tests/device/
772###
773
774CPU_ABIS=
775if is_testable device; then
776    build_device_test ()
777    {
778        if is_broken_build $1 "broken device test build"; then
779            return 0;
780        fi
781        echo "Building NDK device test: `basename $1`"
782        build_project $1 "yes"
783    }
784
785    # $1: DEVICE
786    # $2: DEVICE CPU ABI
787    # $3: test
788    # $4: tmp dir
789    run_device_test ()
790    {
791        local DEVICE=$1
792        local CPU_ABI=$2
793        local TEST=$3
794        local TEST_NAME="$(basename $TEST)"
795        local SRCDIR
796        local DSTDIR="$4/$TARGET_TEST_SUBDIR"
797        local SRCFILE
798        local DSTFILE
799        local PROGRAM
800        # Do not run the test if BROKEN_RUN is defined
801        if [ -z "$RUN_TESTS" ]; then
802            if is_broken_build $TEST "NDK device test not built"; then
803                return 0
804            fi
805            if [ -f "$TEST/BROKEN_RUN" ] ; then
806                if [ ! -s "$TEST/BROKEN_RUN" ] ; then
807                    # skip all
808                    dump "Skipping NDK device test run: $TEST_NAME"
809                    return 0
810                else
811                    # skip all tests built by toolchain
812                    TARGET_TOOLCHAIN=`get_build_var $TEST TARGET_TOOLCHAIN`
813                    TARGET_TOOLCHAIN_VERSION=`echo $TARGET_TOOLCHAIN | tr '-' '\n' | tail -1`
814                    grep -q -e "$TARGET_TOOLCHAIN_VERSION" "$TEST/BROKEN_RUN"
815                    if [ $? = 0 ] ; then
816                        dump "Skipping NDK device test run: $TEST_NAME (no run for binary built by $TARGET_TOOLCHAIN_VERSION)"
817                        return 0
818                    fi
819                    # skip tests listed in file
820                    SKIPPED_EXECUTABLES=`cat $TEST/BROKEN_RUN | tr '\n' ' '`
821                    dump "Skipping NDK device test run: $TEST_NAME ($SKIPPED_EXECUTABLES)"
822                fi
823            fi
824        fi
825        if [ "$ABI" = "$(find_ndk_unknown_archs)" ] && [ -d "$BUILD_DIR/`basename $TEST`/libs" ]; then
826            cd $BUILD_DIR/`basename $TEST`/libs && cp -a $ABI $CPU_ABI
827        fi
828        SRCDIR="$BUILD_DIR/`basename $TEST`/libs/$CPU_ABI"
829        if [ ! -d "$SRCDIR" ] || [ -z "`ls $SRCDIR`" ]; then
830            dump "Skipping NDK device test run (no $CPU_ABI binaries): $TEST_NAME"
831            return 0
832        fi
833        # First, copy all files to the device, except for gdbserver, gdb.setup, and
834        # those declared in $TEST/BROKEN_RUN
835        adb_shell_mkdir "$DEVICE" $DSTDIR
836
837        if [ "$ABI" = "$(find_ndk_unknown_archs)" ]; then # on-the-fly on-device compilation
838            run $ADB_CMD -s "$DEVICE" shell rm -rf $DSTDIR/abcc_tmp
839            adb_shell_mkdir "$DEVICE" $DSTDIR/abcc_tmp
840            run $ADB_CMD -s "$DEVICE" shell chmod 0777 $DSTDIR/abcc_tmp
841            for SRCFILE in `ls $SRCDIR`; do
842                run $ADB_CMD -s "$DEVICE" push "$SRCDIR/$SRCFILE" $DSTDIR/abcc_tmp
843                run $ADB_CMD -s "$DEVICE" shell chmod 0644 $DSTDIR/abcc_tmp/$SRCFILE
844            done
845            compile_on_the_fly $DSTDIR/abcc_tmp
846            if [ $? -ne 0 ]; then
847                test "$CONTINUE_ON_BUILD_FAIL" != "yes" && exit 1
848                return 1
849            fi
850            run rm -f $SRCDIR/*
851            run $ADB_CMD -s "$DEVICE" pull $DSTDIR/abcc_tmp $SRCDIR
852            run rm -f $SRCDIR/compile_result
853            run rm -f $SRCDIR/compile_error
854            run rm -f $SRCDIR/*$(get_lib_suffix_for_abi $ABI)
855            run $ADB_CMD -s "$DEVICE" shell rm -rf $DSTDIR/abcc_tmp
856        fi
857
858        for SRCFILE in `ls $SRCDIR`; do
859            DSTFILE=`basename $SRCFILE`
860            echo "$DSTFILE" | grep -q -e '\.so$'
861            if [ $? != 0 ] ; then
862                continue
863            fi
864            SRCPATH="$SRCDIR/$SRCFILE"
865            if [ $HOST_OS = cygwin ]; then
866                SRCPATH=`cygpath -m $SRCPATH`
867            fi
868            DSTPATH="$DSTDIR/$DSTFILE"
869            run $ADB_CMD -s "$DEVICE" push "$SRCPATH" "$DSTPATH" &&
870            run $ADB_CMD -s "$DEVICE" shell chmod 0755 $DSTPATH
871            if [ $? != 0 ] ; then
872                dump "ERROR: Could not install $SRCPATH to device $DEVICE!"
873                exit 1
874            fi
875        done
876
877        for SRCFILE in `ls $SRCDIR`; do
878            DSTFILE=`basename $SRCFILE`
879            if [ "$DSTFILE" = "gdbserver" -o "$DSTFILE" = "gdb.setup" ] ; then
880                continue
881            fi
882            echo "$DSTFILE" | grep -q -e '\.so$'
883            if [ $? = 0 ] ; then
884              continue
885            fi
886            if [ -z "$RUN_TESTS" -o "$RUN_TESTS_FILTERED" = "yes" ]; then
887                if [ -f "$TEST/BROKEN_RUN" ]; then
888                    grep -q -w -e "$DSTFILE" "$TEST/BROKEN_RUN"
889                    if [ $? = 0 ] ; then
890                        continue
891                    fi
892                fi
893            fi
894            SRCPATH="$SRCDIR/$SRCFILE"
895            if [ $HOST_OS = cygwin ]; then
896                SRCPATH=`cygpath -m $SRCPATH`
897            fi
898            DSTPATH="$DSTDIR/$DSTFILE"
899            run $ADB_CMD -s "$DEVICE" push "$SRCPATH" "$DSTPATH" &&
900            run $ADB_CMD -s "$DEVICE" shell chmod 0755 $DSTPATH
901            DATAPATHS=
902            if [ -f "$TEST/DATA" ]; then
903                if grep -q -e "$DSTFILE" "$TEST/DATA"; then
904                    DATAPATHS=`grep -e "$DSTFILE" "$TEST/DATA" | awk '{print $2}'`
905                    DATAPATHS=$NDK/$DATAPATHS
906                    for DATA in $(ls $DATAPATHS); do
907                        run $ADB_CMD -s "$DEVICE" push "$DATA" "$DSTDIR"
908                    done
909                fi
910            fi
911            if [ $? != 0 ] ; then
912                dump "ERROR: Could not install $SRCPATH to device $DEVICE!"
913                exit 1
914            fi
915            PROGRAM="`basename $DSTPATH`"
916            dump "Running device test [$CPU_ABI]: $TEST_NAME (`basename $PROGRAM`)"
917            adb_var_shell_cmd "$DEVICE" "" "cd $DSTDIR && LD_LIBRARY_PATH=$DSTDIR ./$PROGRAM"
918            if [ $? != 0 ] ; then
919                dump "   ---> TEST FAILED!!"
920            fi
921            adb_var_shell_cmd "$DEVICE" "" "rm -f $DSTPATH"
922            if [ -n "$DATAPATHS" ]; then
923                for DATA in $(ls $DATAPATHS); do
924                    adb_var_shell_cmd "$DEVICE" "" "rm -f $DSTDIR/`basename $DATA`"
925                done
926            fi
927        done
928        # Cleanup
929        adb_var_shell_cmd "$DEVICE" "" rm -r $DSTDIR
930    }
931
932    for DIR in `ls -d $ROOTDIR/tests/device/*`; do
933        if is_buildable $DIR; then
934            build_device_test $DIR
935        fi
936    done
937
938    # Do we have adb and any device connected here?
939    # If not, we can't run our tests.
940    #
941    SKIP_TESTS=no
942    if [ -z "$ADB_CMD" ] ; then
943        dump "WARNING: No 'adb' in your path!"
944        SKIP_TESTS=yes
945    else
946        # Get list of online devices, turn ' ' in device into '#'
947        ADB_DEVICES=`$ADB_CMD devices | grep -v offline | awk 'NR>1 {gsub(/[ \t]+device$/,""); print;}' | sed '/^$/d' | sort | tr ' ' '#'`
948        ADB_DEVICES=$(echo $ADB_DEVICES | tr '\n' ' ')
949        log2 "ADB online devices (sorted): $ADB_DEVICES"
950        ADB_DEVCOUNT=`echo "$ADB_DEVICES" | wc -w`
951        if [ "$ADB_DEVCOUNT" = "0" ]; then
952            dump "WARNING: No device connected to adb!"
953            SKIP_TESTS=yes
954        else
955            ADB_DEVICES="$ADB_DEVICES "
956            if [ -n "$ANDROID_SERIAL" ] ; then
957                # Expect ANDROID_SERIAL is comma-delimited of one or more devices
958                ANDROID_SERIAL=$(echo "$ANDROID_SERIAL" | tr ' ' '#')  # turn ' ' into '#'
959                ANDROID_SERIAL=$(commas_to_spaces $ANDROID_SERIAL)
960                for SERIAL in $ANDROID_SERIAL; do
961                    if [ "$ADB_DEVICES" = "${ADB_DEVICES%$SERIAL *}" ] ; then
962                        dump "WARNING: Device $SERIAL cannot be found or offline!"
963                        SKIP_TESTS=yes
964                    fi
965                done
966                if [ "$SKIP_TESTS" != "yes" ] ; then
967                    ADB_DEVICES="$ANDROID_SERIAL"
968                fi
969            fi
970        fi
971    fi
972    if [ "$SKIP_TESTS" = "yes" ] ; then
973        dump "SKIPPING RUNNING TESTS ON DEVICE!"
974    else
975        AT_LEAST_CPU_ABI_MATCH=
976        for DEVICE in $ADB_DEVICES; do
977            # undo earlier ' '-to-'#' translation
978            DEVICE=$(echo "$DEVICE" | tr '#' ' ')
979            # get device CPU_ABI and CPU_ABI2, each may contain list of abi, comma-delimited.
980            adb_var_shell_cmd "$DEVICE" CPU_ABI1 getprop ro.product.cpu.abi
981            adb_var_shell_cmd "$DEVICE" CPU_ABI2 getprop ro.product.cpu.abi2
982            CPU_ABIS="$CPU_ABI1,$CPU_ABI2"
983            CPU_ABIS=$(commas_to_spaces $CPU_ABIS)
984            if [ -n "$_NDK_TESTING_ALL_" ]; then
985                if [ "$CPU_ABI1" = "armeabi-v7a" -o "$CPU_ABI2" = "armeabi-v7a" ]; then
986                    CPU_ABIS="$CPU_ABIS armeabi-v7a-hard"
987                fi
988            fi
989            if [ "$CPU_ABIS" = " " ]; then
990              # Very old cupcake-based Android devices don't have these properties
991              # defined. Fortunately, they are all armeabi-based.
992              CPU_ABIS=armeabi
993            fi
994            log "CPU_ABIS=$CPU_ABIS"
995            for CPU_ABI in $CPU_ABIS; do
996                if [ "$ABI" = "default" -o "$ABI" = "$CPU_ABI" -o "$ABI" = "$(find_ndk_unknown_archs)" ] ; then
997                    AT_LEAST_CPU_ABI_MATCH="yes"
998                    for DIR in `ls -d $ROOTDIR/tests/device/*`; do
999                        if is_buildable $DIR; then
1000                            log "Running device test on $DEVICE [$CPU_ABI]: $DIR"
1001                            run_device_test "$DEVICE" "$CPU_ABI" "$DIR" /data/local/tmp
1002                        fi
1003                    done
1004                fi
1005            done
1006        done
1007        if [ "$AT_LEAST_CPU_ABI_MATCH" != "yes" ] ; then
1008            dump "WARNING: No device matches ABI $ABI! SKIPPING RUNNING TESTS ON DEVICE!"
1009        fi
1010    fi
1011fi
1012
1013dump "Cleaning up..."
1014if [ "$ABI" = "$(find_ndk_unknown_archs)" ]; then
1015  # Cleanup some intermediate files for testing
1016  run rm -rf $NDK/$GNUSTL_SUBDIR/$GCC_TOOLCHAIN_VERSION/libs/$ABI
1017  run rm -rf $NDK/$GABIXX_SUBDIR/libs/$ABI
1018  run rm -rf $NDK/$LIBPORTABLE_SUBDIR/libs/$ABI
1019fi
1020rm -rf $BUILD_DIR
1021dump "Done."
1022