| #!/bin/sh |
| # //===--------------------------- testit ---------------------------------===// |
| # // |
| # // The LLVM Compiler Infrastructure |
| # // |
| # // This file is distributed under the University of Illinois Open Source |
| # // License. See LICENSE.TXT for details. |
| # // |
| # //===--------------------------------------------------------------------===// |
| |
| currentpath=`pwd` |
| origpath=$currentpath |
| currentdir=`basename $currentpath` |
| while [ $currentdir != "test" ]; do |
| if [ $currentdir = "/" ] |
| then |
| echo "current directory must be in or under \"test\"." |
| exit 1 |
| fi |
| cd .. |
| currentpath=`pwd` |
| currentdir=`basename $currentpath` |
| done |
| |
| cd .. |
| LIBCXX_ROOT=`pwd` |
| cd $origpath |
| |
| VERBOSE=1 |
| |
| run () { |
| if [ "$VERBOSE" -gt 1 ]; then |
| echo "COMMAND: $@" |
| fi |
| case $VERBOSE in |
| 0|1) |
| # Hide command output and errors. |
| "$@" >/dev/null 2>&1 |
| ;; |
| 2) |
| # Only hide command output |
| "$@" >/dev/null |
| ;; |
| *) |
| # Show command output and errors. |
| "$@" |
| ;; |
| esac |
| } |
| |
| run2 () { |
| if [ "$VERBOSE" -gt 2 ]; then |
| echo "COMMAND: $@" |
| fi |
| case $VERBOSE in |
| 0|1) |
| # Hide command output and errors. |
| "$@" >/dev/null 2>&1 |
| ;; |
| 2) |
| # Only hide command output |
| "$@" >/dev/null |
| ;; |
| *) |
| # Show command output and errors. |
| "$@" |
| ;; |
| esac |
| } |
| |
| # The list of valid target abis supported by this script. |
| VALID_ABIS="armeabi armeabi-v7a x86 mips" |
| |
| DO_HELP= |
| DO_STATIC= |
| TARGET_ABI= |
| TARGET_ARCH= |
| TARGET_PATH=/data/local/tmp/libcxx |
| CXX= |
| WITH_COMPILER_RT= |
| for OPT; do |
| case $OPT in |
| --help|-?) |
| DO_HELP=true |
| ;; |
| --abi=*) |
| TARGET_ABI=${OPT##--abi=} |
| ;; |
| --static) |
| DO_STATIC=true |
| ;; |
| --shared) |
| DO_STATIC= |
| ;; |
| --cxx=*) |
| CXX=${OPT##--cxx=} |
| ;; |
| --verbose) |
| VERBOSE=$(( $VERBOSE + 1 )) |
| ;; |
| --with-compiler-rt) |
| WITH_COMPILER_RT=yes |
| ;; |
| -*) |
| echo "Unknown option: $OPT. See --help." |
| exit 1 |
| ;; |
| *) |
| echo "This script doesn't take parameters. See --help." |
| exit 1 |
| ;; |
| esac |
| done |
| |
| if [ "$DO_HELP" ]; then |
| echo \ |
| "Usage: $(basename $0) [options] |
| |
| This script is used to run the libc++ test suite for Android. |
| You will need the following things: |
| |
| - The prebuild libc++ libraries in your NDK install. |
| - A prebuilt Android toolchain in your path. |
| - The 'adb' tool in your path. |
| - An Android device connected to ADB. |
| |
| The toolchain and device must match your target ABI. For example, if |
| you use --abi=armeabi-v7a, your device must run ARMv7-A Android binaries, |
| and arm-linux-androideabi-g++ will be used to compile all tests, unless |
| you use --cxx=<command> to override it. |
| |
| Valid options: |
| --help|-? Display this message. |
| --abi=<name> Specify target ABI. Use --abi=list for list. |
| --static Link against static libc++ library. |
| --cxx=<program> Override C++ compiler/linker. |
| --verbose Increase verbosity. |
| " |
| exit 0 |
| fi |
| |
| # Check target ABI. |
| if [ "$TARGET_ABI" = "list" ]; then |
| echo "List of valid target ABIs:" |
| for ABI in $VALID_ABIS; do |
| printf " %s" $ABI |
| done |
| printf "\n" |
| exit 0 |
| fi |
| |
| if [ -z "$TARGET_ABI" ]; then |
| echo "ERROR: Please specify a target ABI (--abi=<name>)." |
| exit 1 |
| fi |
| |
| FOUND_ABI= |
| for ABI in $VALID_ABIS; do |
| if [ "$ABI" = "$TARGET_ABI" ]; then |
| FOUND_ABI=true |
| break |
| fi |
| done |
| |
| if [ -z "$FOUND_ABI" ]; then |
| echo "ERROR: Invalid abi '$TARGET_ABI'. Must be one of: $VALID_ABIS" |
| exit 1 |
| fi |
| |
| LIBCXX_LIBS=$(cd $LIBCXX_ROOT/.. && pwd)/libs/$TARGET_ABI |
| for LIB in libc++_static.a libc++_shared.so; do |
| if [ ! -f "$LIBCXX_LIBS/$LIB" ]; then |
| echo "ERROR: Missing prebuilt library: $LIBCXX_LIBS/$LIB" |
| echo "Please run: build/tools/build-cxx-stl.sh --stl=libc++" |
| exit 1 |
| fi |
| done |
| |
| LIBCOMPILER_RT_LIBS=$(cd "$LIBCXX_ROOT"/../../../android/compiler-rt && pwd)/libs/$TARGET_ABI |
| if [ "$WITH_COMPILER_RT" = "yes" ]; then |
| for LIB in libcompiler_rt_static.a libcompiler_rt_shared.so; do |
| if [ ! -f "$LIBCOMPILER_RT_LIBS/$LIB" ]; then |
| echo "ERROR: Missing prebuilt library: $LIBCOMPILER_RT_LIBS/$LIB" |
| echo "Please run: build/tools/build-compiler-rt.sh --ndk-dir=$NDK \ |
| --src-dir=/tmp/ndk-$USER/src/llvm-3.3/compiler-rt --llvm-version=3.3" |
| exit 1 |
| fi |
| done |
| fi |
| |
| # Check or detect C++ toolchain. |
| TOOLCHAIN_CFLAGS= |
| TOOLCHAIN_LDFLAGS= |
| if [ -z "$TOOLCHAIN_PREFIX" ]; then |
| # Compute |
| case $TARGET_ABI in |
| armeabi) |
| TOOLCHAIN_PREFIX=arm-linux-androideabi |
| TOOLCHAIN_CFLAGS="-mthumb" |
| TOOLCHAIN_LDFLAGS="-mthumb" |
| ;; |
| armeabi-v7a) |
| TOOLCHAIN_PREFIX=arm-linux-androideabi |
| TOOLCHAIN_CFLAGS="-march=armv7-a -mthumb -mfpu=vfpv3-d16" |
| TOOLCHAIN_LDFLAGS="-march=armv7-a -mthumb -Wl,--fix-cortex-a8" |
| ;; |
| armeabi-v7a-hard) |
| TOOLCHAIN_PREFIX=arm-linux-androideabi |
| TOOLCHAIN_CFLAGS="-march=armv7-a -mthumb -mfpu=vfpv3-d16 -mhard-float -D_NDK_MATH_NO_SOFTFP=1" |
| TOOLCHAIN_LDFLAGS="-march=armv7-a -mthumb -Wl,--fix-cortex-a8 -Wl,--no-warn-mismatch -lm_hard" |
| ;; |
| x86) |
| TOOLCHAIN_PREFIX=i686-linux-android |
| ;; |
| mips) |
| TOOLCHAIN_PREFIX=mipsel-linux-android |
| ;; |
| *) |
| echo "ERROR: Unknown ABI '$ABI'" |
| exit 1 |
| ;; |
| esac |
| if [ -z "$CXX" ]; then |
| CXX=$TOOLCHAIN_PREFIX-g++ |
| fi |
| fi |
| |
| REAL_CXX=$(which "$CXX" 2>/dev/null) |
| if [ -z "$REAL_CXX" ]; then |
| echo "ERROR: Missing C++ compiler: $CXX" |
| exit 1 |
| fi |
| CC=$CXX |
| |
| if [ -z "$OPTIONS" ] |
| then |
| OPTIONS="-std=c++11 -O2 -g" |
| # Note that some tests use assert() to check condition but -O2 defines assert() to nothing, |
| # unless we specify -UNDEBUG to bring assert() back. |
| # But currently adding -UNDEBUG crashes both clang3.4 and clang3.3 for test |
| # like libcxx/test/atomics/atomics.types.generic/address.pass.cpp. Define -UNDEBUG |
| # only when we are not using clang. ToDo |
| if [ "$CXX" = "${CXX%%*clang++*}" ] ; then |
| OPTIONS="$OPTIONS -UNDEBUG" |
| fi |
| fi |
| OPTIONS="$OPTIONS $TOOLCHAIN_CFLAGS $TOOLCHAIN_LDFLAGS" |
| OPTIONS="$OPTIONS -I$LIBCXX_ROOT/test/support" |
| # llvm-libc++/libcxx/test/lit.cfg line #278 defineds the following for testing only on Linux |
| OPTIONS="$OPTIONS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS" |
| |
| if [ -z "$ADB" ] |
| then |
| ADB=adb |
| fi |
| |
| # Run a shell command through ADB, return its status. |
| # Variable ERR contains output if $RET is non-zero |
| adb_shell () { |
| # We need a temporary file to store the output of our command |
| local CMD_OUT RET |
| ERR= |
| CMD_OUT=$(mktemp /tmp/testit_android-cmdout-XXXXXX) |
| # Run the command, while storing the standard output to CMD_OUT |
| # and appending the exit code as the last line. |
| if [ "$VERBOSE" -gt 2 ]; then |
| echo "COMMAND: $ADB shell $@" |
| fi |
| $ADB shell "$@ ; echo \$?" | sed -e 's![[:cntrl:]]!!g' > $CMD_OUT 2>&1 |
| # Get last line in log, which contains the exit code from the command |
| RET=$(sed -e '$!d' $CMD_OUT) |
| # Get output, which corresponds to everything except the last line |
| OUT=$(sed -e '$d' $CMD_OUT) |
| if [ "$RET" != "0" ]; then |
| ERR=$OUT |
| fi |
| if [ "$VERBOSE" -gt 2 ]; then |
| printf "%s" "$OUT" |
| fi |
| rm -f $CMD_OUT |
| return $RET |
| } |
| |
| # Push a given file through ADB. |
| # $1: File path |
| adb_push () { |
| local FILE=$1 |
| local FILE_BASENAME=$(basename "$FILE") |
| run2 $ADB push $FILE $TARGET_PATH/$FILE_BASENAME 2>/dev/null |
| } |
| |
| # Run a given executable through ADB. |
| # $1: Executable path |
| adb_run () { |
| local EXECUTABLE=$1 |
| local EXECUTABLE_BASENAME=$(basename "$EXECUTABLE") |
| run2 $ADB push $EXECUTABLE $TARGET_PATH/$EXECUTABLE_BASENAME 2>/dev/null |
| if [ "$?" != 0 ]; then |
| return 1; |
| fi |
| # Retry up to 10 times if fail is due to "Text file busy" |
| for i in 1 2 3 4 5 6 7 8 9 10; do |
| adb_shell "LD_LIBRARY_PATH=$TARGET_PATH; cd $TARGET_PATH; ./$EXECUTABLE_BASENAME" |
| if [ "$?" = "0" ]; then |
| return 0 |
| fi |
| if ! $(echo $ERR | grep -iq "Text file busy"); then |
| if [ "$i" != "1" ]; then |
| # Dump error message to help diagnostics |
| echo "ERR=$ERR" |
| fi |
| break; |
| fi |
| echo "Text file busy. Re-try $i" |
| sleep 1 |
| run2 $ADB push $EXECUTABLE $TARGET_PATH/$EXECUTABLE_BASENAME 2>/dev/null |
| sleep 2 # try again |
| done |
| return 1 |
| } |
| |
| adb_shell "rm -rf $TARGET_PATH" |
| adb_shell "mkdir -p $TARGET_PATH" |
| |
| if [ "$DO_STATIC" ]; then |
| # Statically link to ensure the executable can be run easily through ADB |
| # Note that in standalone toolchain libc++_static is renamed to libstdc++, and |
| # compiler adds -lstdc++ implicitly |
| if [ "$WITH_COMPILER_RT" = "yes" ]; then |
| LIBS="-lcompiler_rt_static -latomic" |
| else |
| LIBS="-latomic" |
| fi |
| else |
| run2 $ADB push $LIBCXX_LIBS/libc++_shared.so $TARGET_PATH 2>/dev/null |
| if [ $? != 0 ]; then |
| echo "ERROR: Can't push shared libc++ to target device!" |
| exit 1 |
| fi |
| if [ "$WITH_COMPILER_RT" = "yes" ]; then |
| run2 $ADB push $LIBCOMPILER_RT_LIBS/libcompiler_rt_shared.so $TARGET_PATH 2>/dev/null |
| if [ $? != 0 ]; then |
| echo "ERROR: Can't push shared libcompiler_rt to target device!" |
| exit 1 |
| fi |
| LIBS="-lc++_shared -lcompiler_rt_shared -latomic" |
| #LIBS="-nodefaultlibs -lc++_shared -lcompiler_rt_shared -latomic -ldl -lc -lm" |
| else |
| LIBS="-lc++_shared -latomic" |
| fi |
| fi |
| |
| case $TRIPLE in |
| *-*-mingw* | *-*-cygwin* | *-*-win*) |
| TEST_EXE=test.exe |
| ;; |
| *) |
| TEST_EXE=a.out |
| ;; |
| esac |
| |
| TEST_EXE=/tmp/testit_android-$USER-$$-$TEST_EXE |
| |
| FAIL=0 |
| PASS=0 |
| UNIMPLEMENTED=0 |
| IMPLEMENTED_FAIL=0 |
| IMPLEMENTED_PASS=0 |
| |
| # Run tests in current directory, recursively |
| # |
| # Note that file path containing EQ are symlink to the existing tests whose path contain '=', |
| # to workaround an issue in ndk-build which doesn't handle LOCAL_SRC_FILES with '='. |
| # See tests/device/test-libc++-static-full/jni/Android.mk We need to filter out path containing |
| # EQ such that we don't run same tests twice |
| # |
| # An alternative is to do "find . -type f", but this doesn't work in NDK windows package |
| # where zip turns symlink into physical file it points to. |
| # |
| # We also sort the test to make the test report comparable to previous test |
| # |
| |
| afunc() { |
| fail=0 |
| pass=0 |
| if (ls *.fail.cpp > /dev/null 2>&1) |
| then |
| for FILE in $(ls *.fail.cpp | tr ' ' '\n' | grep -v EQ | sort); do |
| if run $CC $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS -o $TEST_EXE > /dev/null 2>&1 |
| then |
| rm $TEST_EXE |
| echo "$FILE should not compile" |
| fail=$(($fail+1)) |
| else |
| pass=$(($pass+1)) |
| fi |
| done |
| fi |
| |
| if (ls *.pass.cpp > /dev/null 2>&1) |
| then |
| if (ls *.dat > /dev/null 2>&1) |
| then |
| adb_shell "rm -f $TARGET_PATH/*.dat" |
| for FILE in $(ls *.dat | tr ' ' '\n' | grep -v EQ | sort); do |
| if [ "$VERBOSE" -gt 1 ]; then |
| echo "Pushing data: " $FILE |
| fi |
| adb_push $FILE |
| if [ $? != 0 ]; then |
| echo "Failed to push file $FILE" |
| fi |
| done |
| fi |
| for FILE in $(ls *.pass.cpp | tr ' ' '\n' | grep -v EQ | sort); do |
| if [ "$VERBOSE" -gt 1 ]; then |
| echo "Running test: " $FILE |
| fi |
| COMMAND="( cd $(pwd) && $CC $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS )" |
| if run $CC $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS -o $TEST_EXE |
| then |
| if adb_run $TEST_EXE |
| then |
| rm $TEST_EXE |
| pass=$(($pass+1)) |
| else |
| echo "`pwd`/$FILE failed at run time" |
| echo "Compile line was: $COMMAND # run-time" |
| fail=$(($fail+1)) |
| rm $TEST_EXE |
| fi |
| else |
| echo "`pwd`/$FILE failed to compile" |
| echo "Compile line was: $COMMAND # compile-time" |
| fail=$(($fail+1)) |
| fi |
| done |
| fi |
| |
| if [ $fail -gt 0 ] |
| then |
| echo "failed $fail tests in `pwd`" |
| IMPLEMENTED_FAIL=$(($IMPLEMENTED_FAIL+1)) |
| fi |
| if [ $pass -gt 0 ] |
| then |
| echo "passed $pass tests in `pwd`" |
| if [ $fail -eq 0 ] |
| then |
| IMPLEMENTED_PASS=$((IMPLEMENTED_PASS+1)) |
| fi |
| fi |
| if [ $fail -eq 0 -a $pass -eq 0 ] |
| then |
| echo "not implemented: `pwd`" |
| UNIMPLEMENTED=$(($UNIMPLEMENTED+1)) |
| fi |
| |
| FAIL=$(($FAIL+$fail)) |
| PASS=$(($PASS+$pass)) |
| |
| for FILE in $(ls | tr ' ' '\n' | grep -v EQ | sort) |
| do |
| if [ -d "$FILE" ]; |
| then |
| cd $FILE |
| afunc |
| cd .. |
| fi |
| done |
| } |
| |
| afunc |
| |
| echo "****************************************************" |
| echo "Results for `pwd`:" |
| echo "using `$CC --version`" |
| echo "with $OPTIONS $HEADER_INCLUDE $SOURCE_LIB" |
| echo "----------------------------------------------------" |
| echo "sections without tests : $UNIMPLEMENTED" |
| echo "sections with failures : $IMPLEMENTED_FAIL" |
| echo "sections without failures: $IMPLEMENTED_PASS" |
| echo " + ----" |
| echo "total number of sections : $(($UNIMPLEMENTED+$IMPLEMENTED_FAIL+$IMPLEMENTED_PASS))" |
| echo "----------------------------------------------------" |
| echo "number of tests failed : $FAIL" |
| echo "number of tests passed : $PASS" |
| echo " + ----" |
| echo "total number of tests : $(($FAIL+$PASS))" |
| echo "****************************************************" |
| |
| exit $FAIL |