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