1 #!/bin/sh 2 # 3 # Copyright (C) 2012 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 18 # This script is used to run a series of tests on a given standalone 19 # toolchain. You need to define the following variables before calling it: 20 # 21 # PREFIX Full binary prefix to the toolchain binaries, 22 # e.g. '/path/to/toolchain/bin/arm-linux-androideabi-' 23 # This script will use ${PREFIX}gcc to invoke the compiler, 24 # ${PREFIX}ar for the archiver, etc... 25 # 26 # CFLAGS Compiler flags for C programs. 27 # CXXFLAGS Compiler flags for C++ programs. 28 # LDFLAGS Linker flags (passed to ${PREFIX}gcc, not ${PREFIX}ld) 29 # 30 31 PROGNAME=$(basename "$0") 32 PROGDIR=$(dirname "$0") 33 NDK_ROOT=$(cd "$PROGDIR/../.." && pwd) 34 NDK_BUILDTOOLS_PATH=$NDK_ROOT/build/tools 35 . $NDK_ROOT/build/tools/prebuilt-common.sh 36 37 panic () { 38 echo "ERROR: $@" >&2; exit 1 39 } 40 41 fail_panic () { 42 if [ $? != 0 ]; then panic "$@"; fi 43 } 44 45 46 # Command-line processing 47 # 48 # Note: try to keep in alphabetical order, same for the --option cases below. 49 # 50 ABI= 51 HELP= 52 LIST_TESTS= 53 NO_SYSROOT= 54 SYSROOT= 55 TEST_SUBDIRS= 56 VERBOSE=1 57 58 # Parse options 59 for opt; do 60 optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'` 61 case $opt in 62 --abi=*) 63 ABI=$optarg 64 ;; 65 --help|-h|-?) 66 HELP=true 67 ;; 68 --list) 69 LIST_TESTS=true 70 ;; 71 --no-sysroot) 72 NO_SYSROOT=true 73 ;; 74 --prefix=*) 75 PREFIX=$optarg 76 ;; 77 --quiet|-q) 78 VERBOSE=$(( $VERBOSE - 1 )) 79 ;; 80 --sysroot=*) 81 SYSROOT=$optarg 82 ;; 83 --verbose|-v) 84 VERBOSE=$(( $VERBOSE + 1 )) 85 ;; 86 -*) 87 panic "Unknown option '$opt'. See --help for list of valid ones." 88 ;; 89 *) 90 TEST_SUBDIRS=$TEST_SUBDIRS" "$opt 91 ;; 92 esac 93 done 94 95 if [ "$HELP" ]; then 96 echo "Usage: $PROGNAME [options] [testname+]" 97 echo "" 98 echo "Run a set of unit tests to check that a given Android NDK toolchain works" 99 echo "as expected. Useful to catch regressions when generating new toolchain" 100 echo "binaries." 101 echo "" 102 echo "You can pass the full path to the toolchain either with the --prefix" 103 echo "option, or by defining PREFIX in your environment before calling this script." 104 echo "For example:" 105 echo "" 106 echo " $PROGNAME --prefix=\$NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi" 107 echo "" 108 echo "The prefix can also be the full-path to the \$TARGET-gcc or \$TARGET-g++ program " 109 echo "" 110 echo "The script will automatically use an NDK-provided sysroot, but you can specify an" 111 echo "alternate one with the --sysroot=<path> option. You can also use --no-sysroot if" 112 echo "the toolchain already provides its own sysroot (e.g. if it is a standalone toolchain" 113 echo "generated with make-standalone-toolchain.sh)." 114 echo "" 115 echo "The target ABI is normally auto-detected from the toolchain, but you can specify an" 116 echo "alternative one with the --abi=<name> option. This is only useful on ARM, where the" 117 echo "default ABI is 'armeabi' targetting the ARMv5TE instruction set. If you want to check" 118 echo "the generation of ARMv7-A machine code, use the following:" 119 echo "" 120 echo " --abi=armeabi-v7a" 121 echo "" 122 echo "When called without any arguments, the script will run all known toolchain tests." 123 echo "You can restrict the list of tests by passing them on the command-line. Use --list" 124 echo "to display the list of all tests that are relevant for your current ABI." 125 echo "" 126 echo "More information about each test can be displayed by using --verbose." 127 echo "" 128 echo "Valid options:" 129 echo "" 130 echo " --help|-h|-? Print this message." 131 echo " --verbose|-v Increase verbosity." 132 echo " --quiet|-q Decrease verbosity." 133 echo " --list List all available tests for current ABI." 134 echo " --prefix=<prefix> Specify full toolchain binary prefix." 135 echo " --sysroot=<path> Specify alternate sysroot." 136 echo " --no-sysroot Do not use a sysroot." 137 echo " --abi=<name> Specify target ABI name." 138 echo "" 139 exit 0 140 fi 141 142 TMPDIR=/tmp/ndk-$USER/tests/standalone 143 mkdir -p "$TMPDIR" && rm -rf "$TMPDIR/*" 144 145 BUILD_DIR=$TMPDIR/build 146 mkdir -p "$BUILD_DIR" 147 148 LOGFILE=$TMPDIR/log.txt 149 echo -n "" > $LOGFILE 150 151 if [ $VERBOSE -ge 3 ]; then 152 run () { 153 echo "# COMMAND: $@" 154 "$@" 155 } 156 elif [ $VERBOSE -ge 2 ]; then 157 run () { 158 echo "# COMMAND: $@" >> $LOGFILE 159 "$@" 160 } 161 else 162 run () { 163 echo "# COMMAND[$@]" >> $LOGFILE 164 "$@" >> $LOGFILE 2>&1 165 } 166 fi 167 168 if [ $VERBOSE -ge 2 ]; then 169 run_script () { 170 $SHELL "$@" 171 } 172 else 173 run_script () { 174 $SHELL "$@" >> $LOGFILE 2>&1 175 } 176 fi 177 178 if [ $VERBOSE -ge 1 ]; then 179 dump () { 180 echo "$@" 181 } 182 else 183 dump () { 184 : # nothing 185 } 186 fi 187 188 if [ "$HOST_OS" = "cygwin" -o "$HOST_OS" = "windows" ] ; then 189 NULL="NUL" 190 else 191 NULL="/dev/null" 192 fi 193 194 # Probe a given sub-directory and see if it contains valid test files. 195 # $1: sub-directory path 196 # Return: 0 on success, 1 otherwise 197 # 198 # This can also sets the following global variables: 199 # TEST_TYPE 200 # SCRIPT 201 # SOURCES 202 # 203 probe_test_subdir () 204 { 205 local DIR="$1" 206 207 TEST_TYPE= 208 SCRIPT= 209 SOURCES= 210 211 if [ -f "$DIR/run.sh" ]; then 212 TEST_TYPE=script 213 SCRIPT=run.sh 214 215 elif [ -f "$DIR/run-$ABI.sh" ]; then 216 TEST_TYPE=script 217 SCRIPT=run-$ABI.sh 218 219 elif [ -f "$DIR/main.c" ]; then 220 TEST_TYPE=c_executable 221 SOURCES=main.c 222 223 elif [ -f "$DIR/main.cpp" ]; then 224 TEST_TYPE=cxx_executable 225 SOURCES=main.cpp 226 227 else 228 return 1 229 fi 230 231 return 0 232 } 233 234 235 # Handle --list option now, then exit 236 if [ -n "$LIST_TESTS" ]; then 237 echo "List of available toolchain tests:" 238 if [ -z "$ABI" ]; then 239 ABI=armeabi 240 fi 241 for TEST_SUBDIR in $(cd $PROGDIR && ls -d *); do 242 SUBDIR=$PROGDIR/$TEST_SUBDIR 243 if probe_test_subdir "$SUBDIR"; then 244 echo " $TEST_SUBDIR" 245 fi 246 done 247 exit 0 248 fi 249 250 if [ -z "$PREFIX" ]; then 251 panic "Please define PREFIX in your environment, or use --prefix=<prefix> option." 252 fi 253 254 CC= 255 CXX= 256 CC_TARGET= 257 if [ "$PREFIX" = "${PREFIX%clang}" ]; then 258 # Test GCC 259 # Remove -gcc or -g++ from prefix if any 260 PREFIX=${PREFIX%-gcc} 261 PREFIX=${PREFIX%-g++} 262 263 # Add a trailing dash to the prefix, if there isn't any 264 PREFIX=${PREFIX%-}- 265 266 GCC=${PREFIX}gcc 267 if [ ! -f "$GCC" ]; then 268 panic "Missing compiler, please fix your prefix definition: $GCC" 269 fi 270 271 GCC=$(which $GCC 2>$NULL) 272 if [ -z "$GCC" -o ! -f "$GCC" ]; then 273 panic "Bad compiler path: ${PREFIX}gcc" 274 fi 275 276 # Remove trailing .exe if any 277 GCC=${GCC%${HOST_EXE}} 278 279 GCCDIR=$(dirname "$GCC") 280 GCCBASE=$(basename "$GCC") 281 282 GCCDIR=$(cd "$GCCDIR" && pwd) 283 GCC=$GCCDIR/$GCCBASE 284 285 PREFIX=${GCC%%gcc} 286 287 CC=${PREFIX}gcc 288 CXX=${PREFIX}g++ 289 CC_TARGET=$($GCC -v 2>&1 | tr ' ' '\n' | grep -e --target=) 290 CC_TARGET=${CC_TARGET##--target=} 291 else 292 # Test Clang 293 # Remove clang or clang++ from prefix if any 294 PREFIX=${PREFIX%clang} 295 PREFIX=${PREFIX%clang++} 296 297 CLANG=${PREFIX}clang 298 if [ ! -f "$CLANG" ]; then 299 panic "Missing compiler, please fix your prefix definition: $CLANG" 300 fi 301 302 CLANGDIR=$(dirname "$CLANG") 303 CLANGBASE=$(basename "$CLANG") 304 305 CLANGDIR=$(cd "$CLANGDIR" && pwd) 306 CLANG=$CLANGDIR/$CLANGBASE 307 308 PREFIX=${CLANG%%clang} 309 310 # Find *-ld in the same directory eventaully usable as ${PREFIX}-ld 311 GNU_LD=$(cd $CLANGDIR && ls *-ld${HOST_EXE}) 312 GNU_LD=$CLANGDIR/$GNU_LD 313 if [ ! -f "$GNU_LD" ]; then 314 panic "Missing linker in the same directory as clang/clang++: $CLANGDIR" 315 fi 316 317 PREFIX=${GNU_LD%ld${HOST_EXE}} 318 319 CC=$CLANG 320 CXX=${CLANG%clang}clang++ 321 CC_TARGET=$($CLANG -v 2>&1 | grep Target:) 322 CC_TARGET=${CC_TARGET##Target: } 323 fi 324 325 if [ -z "$ABI" ]; then 326 # Auto-detect target CPU architecture 327 dump "Auto-detected target configuration: $CC_TARGET" 328 case $CC_TARGET in 329 arm*-linux-androideabi) 330 ABI=armeabi 331 ARCH=arm 332 ;; 333 i686*-linux-android) 334 ABI=x86 335 ARCH=x86 336 ;; 337 mipsel*-linux-android) 338 ABI=mips 339 ARCH=mips 340 ;; 341 aarch64*-linux-android) 342 ABI=arm64-v8a 343 ARCH=arm64 344 ;; 345 x86_64*-linux-android) 346 ABI=x86_64 347 ARCH=x86_64 348 ;; 349 mips64el*-linux-android) 350 ABI=mips64 351 ARCH=mips64 352 ;; 353 *) 354 panic "Unknown target architecture '$CC_TARGET', please use --abi=<name> to manually specify ABI." 355 esac 356 dump "Auto-config: --abi=$ABI" 357 fi 358 359 COMMON_FLAGS= 360 361 # Ensure ABI_<abi> is defined as a compiler macro when building test programs. 362 # as a compiler macro when building all test programs. 363 ABI_MACRO=ABI_$(echo "$ABI" | tr '-' '_') 364 COMMON_FLAGS=$COMMON_FLAGS" -D$ABI_MACRO=1" 365 366 if [ -n "$NO_SYSROOT" ]; then 367 SYSROOT= 368 elif [ -n "$SYSROOT" ]; then 369 if [ ! -d "$SYSROOT" ]; then 370 panic "Sysroot directory does not exist: $SYSROOT" 371 fi 372 # Sysroot must be absolute path 373 SYSROOT=$(cd $SYSROOT && pwd) 374 COMMON_FLAGS=$COMMON_FLAGS" --sysroot=$SYSROOT" 375 else 376 # Auto-detect sysroot 377 PLATFORM="android-"$(get_default_api_level_for_arch $ARCH) 378 SYSROOT=$NDK_ROOT/platforms/$PLATFORM/arch-$ARCH 379 if [ ! -d "$SYSROOT" ]; then 380 panic "Can't find sysroot file, use --sysroot to point to valid one: $SYSROOT" 381 fi 382 if [ ! -f "$SYSROOT/usr/lib/libc.so" ]; then 383 panic "Incomplete sysroot, use --sysroot to point to valid one: $SYSROOT" 384 fi 385 if [ "$HOST_OS" = "cygwin" ]; then 386 SYSROOT=`cygpath -m $SYSROOT` 387 else 388 if [ "$HOST_OS" = "windows" -a "$OSTYPE" = "msys" ]; then 389 # use -W specific to MSys to get windows path 390 SYSROOT=$(cd $SYSROOT ; pwd -W) 391 fi 392 fi 393 dump "Auto-config: --sysroot=$SYSROOT" 394 COMMON_FLAGS=$COMMON_FLAGS" --sysroot=$SYSROOT" 395 fi 396 397 if [ -z "$CXXFLAGS" ]; then 398 CXXFLAGS=$CFLAGS 399 fi 400 401 # NOTE: We need to add -fno-exceptions, otherwise some toolchains compile 402 # with exception support by default, and the test programs fail to 403 # link due to an undefined reference to __gxx_personality_v0. 404 # 405 # This symbol is normally part of libsupc++ which is not available 406 # if you don't have the GNU libstdc++ installed into your toolchain 407 # directory. 408 # 409 # Affects the x86 and mips toolchains, but not the ARM one. 410 # Not sure if we want exceptions enabled by default or not. 411 # 412 CXXFLAGS=$CXXFLAGS" -fno-exceptions" 413 414 CFLAGS=$COMMON_FLAGS" "$CFLAGS 415 CXXFLAGS=$COMMON_FLAGS" "$CXXFLAGS 416 417 if [ -z "$TEST_SUBDIRS" ]; then 418 TEST_SUBDIRS=$(cd $PROGDIR && ls -d *) 419 fi 420 421 COUNT=0 422 FAILURES=0 423 for TEST_SUBDIR in $TEST_SUBDIRS; do 424 SUBDIR=$PROGDIR/$TEST_SUBDIR 425 426 if ! probe_test_subdir "$SUBDIR"; then 427 continue 428 fi 429 430 rm -rf "$BUILD_DIR"/* && 431 cp -RL "$SUBDIR"/* "$BUILD_DIR/" 432 fail_panic "Could not copy test files to $BUILD_DIR !?" 433 434 dump_n "Running $TEST_SUBDIR test... " 435 436 case $TEST_TYPE in 437 script) 438 ( 439 export PREFIX CC CXX CFLAGS CXXFLAGS LDFLAGS VERBOSE ABI NULL 440 run cd "$BUILD_DIR" && run_script $SCRIPT 441 ) 442 RET=$? 443 ;; 444 445 c_executable) 446 ( 447 run cd "$BUILD_DIR" && run $CC $LDFLAGS $CFLAGS -o $NULL $SOURCES 448 ) 449 RET=$? 450 ;; 451 452 cxx_executable) 453 ( 454 run cd "$BUILD_DIR" && run $CXX $LDFLAGS $CXXFLAGS -o $NULL $SOURCES 455 ) 456 RET=$? 457 ;; 458 esac 459 460 if [ "$RET" != 0 ]; then 461 dump "KO" 462 FAILURES=$(( $FAILURES + 1 )) 463 else 464 dump "ok" 465 fi 466 COUNT=$(( $COUNT + 1 )) 467 done 468 469 if [ "$FAILURES" -eq 0 ]; then 470 dump "$COUNT/$COUNT tests passed. Success." 471 exit 0 472 else 473 dump "$FAILURES tests failed out of $COUNT." 474 exit 1 475 fi 476