1#!/bin/sh
2# //===--------------------------- testit ---------------------------------===//
3# //
4# //                     The LLVM Compiler Infrastructure
5# //
6# // This file is distributed under the University of Illinois Open Source
7# // License. See LICENSE.TXT for details.
8# //
9# //===--------------------------------------------------------------------===//
10
11currentpath=`pwd`
12origpath=$currentpath
13currentdir=`basename $currentpath`
14while [ $currentdir != "test" ]; do
15	if [ $currentdir = "/" ]
16	then
17		echo "current directory must be in or under \"test\"."
18		exit 1
19	fi
20	cd ..
21	currentpath=`pwd`
22	currentdir=`basename $currentpath`
23done
24
25cd ..
26LIBCXX_ROOT=`pwd`
27cd $origpath
28
29VERBOSE=1
30
31run () {
32  if [ "$VERBOSE" -gt 1 ]; then
33    echo "COMMAND: $@"
34  fi
35  case $VERBOSE in
36    0|1)
37      # Hide command output and errors.
38      "$@" >/dev/null 2>&1
39      ;;
40    2)
41      # Only hide command output
42      "$@" >/dev/null
43      ;;
44    *)
45      # Show command output and errors.
46      "$@"
47      ;;
48  esac
49}
50
51run2 () {
52  if [ "$VERBOSE" -gt 2 ]; then
53    echo "COMMAND: $@"
54  fi
55  case $VERBOSE in
56    0|1)
57      # Hide command output and errors.
58      "$@" >/dev/null 2>&1
59      ;;
60    2)
61      # Only hide command output
62      "$@" >/dev/null
63      ;;
64    *)
65      # Show command output and errors.
66      "$@"
67      ;;
68  esac
69}
70
71# The list of valid target abis supported by this script.
72VALID_ABIS="armeabi armeabi-v7a x86 mips"
73
74HOST_OS=`uname -s`
75if [ "$HOST_OS" = "Darwin" ]; then
76    # darwin doesn't have readelf.  hard-code a known one
77    READELF=../../../../../toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/arm-linux-androideabi-readelf
78else
79    READELF=readelf
80fi
81
82DO_HELP=
83DO_STATIC=
84TARGET_ABI=
85TARGET_ARCH=
86if [ -z "$TARGET_TEST_SUBDIR" ]; then
87    TARGET_TEST_SUBDIR="libcxx"
88fi
89TARGET_PATH=/data/local/tmp/$TARGET_TEST_SUBDIR
90CXX=
91WITH_COMPILER_RT=
92LIBCXX_NEEDS_COMPILER_RT=
93for OPT; do
94  case $OPT in
95    --help|-?)
96      DO_HELP=true
97      ;;
98    --abi=*)
99      TARGET_ABI=${OPT##--abi=}
100      ;;
101    --static)
102      DO_STATIC=true
103      ;;
104    --shared)
105      DO_STATIC=
106      ;;
107    --cxx=*)
108      CXX=${OPT##--cxx=}
109      ;;
110    --verbose)
111      VERBOSE=$(( $VERBOSE + 1 ))
112      ;;
113    --with-compiler-rt)
114      WITH_COMPILER_RT=yes
115      ;;
116    -*)
117      echo "Unknown option: $OPT. See --help."
118      exit 1
119      ;;
120    *)
121      echo "This script doesn't take parameters. See --help."
122      exit 1
123      ;;
124  esac
125done
126
127if [ "$DO_HELP" ]; then
128  echo \
129"Usage: $(basename $0) [options]
130
131This script is used to run the libc++ test suite for Android.
132You will need the following things:
133
134  - The prebuild libc++ libraries in your NDK install.
135  - A prebuilt Android toolchain in your path.
136  - The 'adb' tool in your path.
137  - An Android device connected to ADB.
138
139The toolchain and device must match your target ABI. For example, if
140you use --abi=armeabi-v7a, your device must run ARMv7-A Android binaries,
141and arm-linux-androideabi-g++ will be used to compile all tests, unless
142you use --cxx=<command> to override it.
143
144Valid options:
145  --help|-?        Display this message.
146  --abi=<name>     Specify target ABI. Use --abi=list for list.
147  --static         Link against static libc++ library.
148  --cxx=<program>  Override C++ compiler/linker.
149  --verbose        Increase verbosity.
150"
151  exit 0
152fi
153
154# Check target ABI.
155if [ "$TARGET_ABI" = "list" ]; then
156  echo "List of valid target ABIs:"
157  for ABI in $VALID_ABIS; do
158    printf " %s" $ABI
159  done
160  printf "\n"
161  exit 0
162fi
163
164if [ -z "$TARGET_ABI" ]; then
165  echo "ERROR: Please specify a target ABI (--abi=<name>)."
166  exit 1
167fi
168
169FOUND_ABI=
170for ABI in $VALID_ABIS; do
171  if [ "$ABI" = "$TARGET_ABI" ]; then
172    FOUND_ABI=true
173    break
174  fi
175done
176
177if [ -z "$FOUND_ABI" ]; then
178  echo "ERROR: Invalid abi '$TARGET_ABI'. Must be one of: $VALID_ABIS"
179  exit 1
180fi
181
182LIBCXX_LIBS=$(cd $LIBCXX_ROOT/.. && pwd)/libs/$TARGET_ABI
183for LIB in libc++_static.a libc++_shared.so; do
184  if [ ! -f "$LIBCXX_LIBS/$LIB" ]; then
185    echo "ERROR: Missing prebuilt library: $LIBCXX_LIBS/$LIB"
186    echo "Please run: build/tools/build-cxx-stl.sh --stl=libc++"
187    exit 1
188  fi
189done
190
191LIBCOMPILER_RT_LIBS=$(cd "$LIBCXX_ROOT"/../../../android/compiler-rt && pwd)/libs/$TARGET_ABI
192$READELF -d "$LIBCXX_LIBS/libc++_shared.so" | grep NEEDED | grep -q compiler_rt
193if [ $? = 0 ]; then
194  LIBCXX_NEEDS_COMPILER_RT=yes
195fi
196
197if [ "$WITH_COMPILER_RT" = "yes" -o "$LIBCXX_NEEDS_COMPILER_RT" = "yes" ]; then
198  for LIB in libcompiler_rt_static.a libcompiler_rt_shared.so; do
199    if [ ! -f "$LIBCOMPILER_RT_LIBS/$LIB" ]; then
200      echo "ERROR: Missing prebuilt library: $LIBCOMPILER_RT_LIBS/$LIB"
201      echo "Please run: build/tools/build-compiler-rt.sh --ndk-dir=$NDK \
202--src-dir=/tmp/ndk-$USER/src/llvm-3.3/compiler-rt --llvm-version=3.3"
203      exit 1
204    fi
205  done
206fi
207
208# Check or detect C++ toolchain.
209TOOLCHAIN_CFLAGS=
210TOOLCHAIN_LDFLAGS=
211if [ -z "$TOOLCHAIN_PREFIX" ]; then
212  # Compute
213  case $TARGET_ABI in
214    armeabi)
215      TOOLCHAIN_PREFIX=arm-linux-androideabi
216      TOOLCHAIN_CFLAGS="-mthumb"
217      TOOLCHAIN_LDFLAGS="-mthumb"
218      ;;
219    armeabi-v7a)
220      TOOLCHAIN_PREFIX=arm-linux-androideabi
221      TOOLCHAIN_CFLAGS="-march=armv7-a -mthumb -mfpu=vfpv3-d16"
222      TOOLCHAIN_LDFLAGS="-march=armv7-a -mthumb -Wl,--fix-cortex-a8"
223      ;;
224    armeabi-v7a-hard)
225      TOOLCHAIN_PREFIX=arm-linux-androideabi
226      TOOLCHAIN_CFLAGS="-march=armv7-a -mthumb -mfpu=vfpv3-d16 -mhard-float -D_NDK_MATH_NO_SOFTFP=1"
227      TOOLCHAIN_LDFLAGS="-march=armv7-a -mthumb -Wl,--fix-cortex-a8 -Wl,--no-warn-mismatch -lm_hard"
228      ;;
229    x86)
230      TOOLCHAIN_PREFIX=i686-linux-android
231      ;;
232    mips)
233      TOOLCHAIN_PREFIX=mipsel-linux-android
234      ;;
235    *)
236      echo "ERROR: Unknown ABI '$ABI'"
237      exit 1
238      ;;
239  esac
240  if [ -z "$CXX" ]; then
241      CXX=$TOOLCHAIN_PREFIX-g++
242  fi
243fi
244
245REAL_CXX=$(which "$CXX" 2>/dev/null)
246if [ -z "$REAL_CXX" ]; then
247  echo "ERROR: Missing C++ compiler: $CXX"
248  exit 1
249fi
250CC=$CXX
251
252if [ -z "$OPTIONS" ]
253then
254  # Note that some tests use assert() to check condition but -O2 defines assert() to nothing,
255  # unless we specify -UNDEBUG to bring assert() back.
256  OPTIONS="--std=c++11 -O2 -g -funwind-tables -UNDEBUG"
257  if [ "$CXX" != "${CXX%clang++*}" ] ; then
258    OPTIONS="$OPTIONS" # clang3.5 doesn't accept the following: -mllvm -arm-enable-ehabi-descriptors -mllvm -arm-enable-ehabi"
259  else
260    # Some libc++ implementation (eg. list) break TBAA!
261    OPTIONS="$OPTIONS -fno-strict-aliasing"
262  fi
263fi
264
265OPTIONS="$OPTIONS $TOOLCHAIN_CFLAGS $TOOLCHAIN_LDFLAGS"
266OPTIONS="$OPTIONS -I$LIBCXX_ROOT/test/support"
267# llvm-libc++/libcxx/test/lit.cfg line #278 defineds the following for testing only on Linux
268OPTIONS="$OPTIONS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS"
269
270if [ -z "$ADB" ]
271then
272  ADB=adb
273fi
274
275# Run a shell command through ADB, return its status.
276# Variable ERR contains output if $RET is non-zero
277adb_shell () {
278  # We need a temporary file to store the output of our command
279  local CMD_OUT RET
280  ERR=
281  CMD_OUT=$(mktemp /tmp/testit_android-cmdout-XXXXXX)
282  # Run the command, while storing the standard output to CMD_OUT
283  # and appending the exit code as the last line.
284  if [ "$VERBOSE" -gt 2 ]; then
285    echo "COMMAND: $ADB shell $@"
286  fi
287  $ADB shell "$@ ; echo \$?" | sed -e 's![[:cntrl:]]!!g' > $CMD_OUT 2>&1
288  # Get last line in log, which contains the exit code from the command
289  RET=$(sed -e '$!d' $CMD_OUT)
290  # Get output, which corresponds to everything except the last line
291  OUT=$(sed -e '$d' $CMD_OUT)
292  if [ "$RET" != "0" ]; then
293    ERR=$OUT
294  fi
295  if [ "$VERBOSE" -gt 2 ]; then
296    printf "%s" "$OUT"
297  fi
298  rm -f $CMD_OUT
299  return $RET
300}
301
302# Push a given file through ADB.
303# $1: File path
304adb_push () {
305  local FILE=$1
306  local FILE_BASENAME=$(basename "$FILE")
307  run2 $ADB push $FILE $TARGET_PATH/$FILE_BASENAME 2>/dev/null
308}
309
310# Run a given executable through ADB.
311# $1: Executable path
312adb_run () {
313  local EXECUTABLE=$1
314  local EXECUTABLE_BASENAME=$(basename "$EXECUTABLE")
315  run2 $ADB push $EXECUTABLE $TARGET_PATH/$EXECUTABLE_BASENAME 2>/dev/null
316  if [ "$?" != 0 ]; then
317    return 1;
318  fi
319  # Retry up to 10 times if fail is due to "Text file busy"
320  for i in 1 2 3 4 5 6 7 8 9 10; do
321    adb_shell "LD_LIBRARY_PATH=$TARGET_PATH; cd $TARGET_PATH; ./$EXECUTABLE_BASENAME"
322    if [ "$?" = "0" ]; then
323      return 0
324    fi
325    if ! $(echo $ERR | grep -iq "Text file busy"); then
326      if [ "$i" != "1" ]; then
327        # Dump error message to help diagnostics
328        echo "ERR=$ERR"
329      fi
330      break;
331    fi
332    echo "Text file busy.  Re-try $i"
333    sleep 1
334    run2 $ADB push $EXECUTABLE $TARGET_PATH/$EXECUTABLE_BASENAME 2>/dev/null
335    sleep 2  # try again
336  done
337  return 1
338}
339
340adb_shell "rm -rf $TARGET_PATH"
341adb_shell "mkdir -p $TARGET_PATH"
342
343if [ "$DO_STATIC" ]; then
344  # Statically link to ensure the executable can be run easily through ADB
345  # Note that in standalone toolchain libc++_static is renamed to libstdc++, and
346  # compiler adds -lstdc++ implicitly
347  if [ "$WITH_COMPILER_RT" = "yes" ]; then
348    LIBS="-nodefaultlibs -lstdc++ -latomic -ldl -lm -lc -lcompiler_rt_static"
349  else
350    LIBS="-latomic"
351  fi
352else
353  run2 $ADB push $LIBCXX_LIBS/libc++_shared.so $TARGET_PATH 2>/dev/null
354  if [ $? != 0 ]; then
355    echo "ERROR: Can't push shared libc++ to target device!"
356    exit 1
357  fi
358
359  if [ "$WITH_COMPILER_RT" = "yes" -o "$LIBCXX_NEEDS_COMPILER_RT" = "yes" ]; then
360    run2 $ADB push $LIBCOMPILER_RT_LIBS/libcompiler_rt_shared.so $TARGET_PATH 2>/dev/null
361    if [ $? != 0 ]; then
362      echo "ERROR: Can't push shared libcompiler_rt to target device!"
363      exit 1
364    fi
365  fi
366
367  if [ "$WITH_COMPILER_RT" = "yes" ]; then
368    LIBS="-nodefaultlibs -lc++_shared -latomic -ldl -lm -lc -lcompiler_rt_shared"
369  else
370    LIBS="-lc++_shared -latomic"
371  fi
372fi
373
374case $TRIPLE in
375  *-*-mingw* | *-*-cygwin* | *-*-win*)
376    TEST_EXE=test.exe
377    ;;
378  *)
379    TEST_EXE=a.out
380    ;;
381esac
382
383TEST_EXE=/tmp/testit_android-$USER-$$-$TEST_EXE
384
385FAIL=0
386PASS=0
387UNIMPLEMENTED=0
388IMPLEMENTED_FAIL=0
389IMPLEMENTED_PASS=0
390
391# Run tests in current directory, recursively
392#
393# Note that file path containing EQ are symlink to the existing tests whose path contain '=',
394# to workaround an issue in ndk-build which doesn't handle LOCAL_SRC_FILES with '='.
395# See tests/device/test-libc++-static-full/jni/Android.mk  We need to filter out path containing
396# EQ such that we don't run same tests twice
397#
398# An alternative is to do "find . -type f", but this doesn't work in NDK windows package
399# where zip turns symlink into physical file it points to.
400#
401# We also sort the test to make the test report comparable to previous test
402#
403
404afunc() {
405	fail=0
406	pass=0
407	if (ls *.fail.cpp > /dev/null 2>&1)
408	then
409		for FILE in $(ls *.fail.cpp | tr ' ' '\n' | grep -v EQ | sort); do
410			if run $CC $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS -o $TEST_EXE > /dev/null 2>&1
411			then
412				rm $TEST_EXE
413				echo "$FILE should not compile"
414				fail=$(($fail+1))
415			else
416				pass=$(($pass+1))
417			fi
418		done
419	fi
420
421	if (ls *.pass.cpp > /dev/null 2>&1)
422	then
423		if (ls *.dat > /dev/null 2>&1)
424		then
425			adb_shell "rm -f $TARGET_PATH/*.dat"
426			for FILE in $(ls *.dat | tr ' ' '\n' | grep -v EQ | sort); do
427	                      if [ "$VERBOSE" -gt 1 ]; then
428	                          echo "Pushing data: " $FILE
429			      fi
430			      adb_push $FILE
431			      if [ $? != 0 ]; then
432				  echo "Failed to push file $FILE"
433	                      fi
434			done
435		fi
436		for FILE in $(ls *.pass.cpp | tr ' ' '\n' | grep -v EQ | sort); do
437                      if [ "$VERBOSE" -gt 1 ]; then
438                          echo "Running test: " $FILE
439                      fi
440                        COMMAND="( cd $(pwd) && $CC $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS )"
441			if run $CC $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS -o $TEST_EXE
442			then
443				if adb_run $TEST_EXE
444				then
445					rm $TEST_EXE
446					pass=$(($pass+1))
447				else
448					echo "`pwd`/$FILE failed at run time"
449					echo "Compile line was: $COMMAND # run-time"
450					fail=$(($fail+1))
451					rm $TEST_EXE
452				fi
453			else
454				echo "`pwd`/$FILE failed to compile"
455				echo "Compile line was: $COMMAND # compile-time"
456				fail=$(($fail+1))
457			fi
458		done
459	fi
460
461	if [ $fail -gt 0 ]
462	then
463		echo "failed $fail tests in `pwd`"
464		IMPLEMENTED_FAIL=$(($IMPLEMENTED_FAIL+1))
465	fi
466	if [ $pass -gt 0 ]
467	then
468		echo "passed $pass tests in `pwd`"
469		if [ $fail -eq 0 ]
470		then
471			IMPLEMENTED_PASS=$((IMPLEMENTED_PASS+1))
472		fi
473	fi
474	if [ $fail -eq 0 -a $pass -eq 0 ]
475	then
476		echo "not implemented:  `pwd`"
477		UNIMPLEMENTED=$(($UNIMPLEMENTED+1))
478	fi
479
480	FAIL=$(($FAIL+$fail))
481	PASS=$(($PASS+$pass))
482
483	for FILE in $(ls | tr ' ' '\n' | grep -v EQ | sort)
484	do
485		if [ -d "$FILE" ];
486		then
487			cd $FILE
488			afunc
489			cd ..
490		fi
491	done
492}
493
494afunc
495
496echo "****************************************************"
497echo "Results for `pwd`:"
498echo "using `$CC --version`"
499echo "with $OPTIONS $HEADER_INCLUDE $SOURCE_LIB"
500echo "----------------------------------------------------"
501echo "sections without tests   : $UNIMPLEMENTED"
502echo "sections with failures   : $IMPLEMENTED_FAIL"
503echo "sections without failures: $IMPLEMENTED_PASS"
504echo "                       +   ----"
505echo "total number of sections : $(($UNIMPLEMENTED+$IMPLEMENTED_FAIL+$IMPLEMENTED_PASS))"
506echo "----------------------------------------------------"
507echo "number of tests failed   : $FAIL"
508echo "number of tests passed   : $PASS"
509echo "                       +   ----"
510echo "total number of tests    : $(($FAIL+$PASS))"
511echo "****************************************************"
512
513exit $FAIL
514