475 lines
12 KiB
Bash
Executable file
475 lines
12 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# Copyright (C) 2012 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
# This script is used to run a series of tests on a given standalone
|
|
# toolchain. You need to define the following variables before calling it:
|
|
#
|
|
# PREFIX Full binary prefix to the toolchain binaries,
|
|
# e.g. '/path/to/toolchain/bin/arm-linux-androideabi-'
|
|
# This script will use ${PREFIX}gcc to invoke the compiler,
|
|
# ${PREFIX}ar for the archiver, etc...
|
|
#
|
|
# CFLAGS Compiler flags for C programs.
|
|
# CXXFLAGS Compiler flags for C++ programs.
|
|
# LDFLAGS Linker flags (passed to ${PREFIX}gcc, not ${PREFIX}ld)
|
|
#
|
|
|
|
PROGNAME=$(basename "$0")
|
|
PROGDIR=$(dirname "$0")
|
|
NDK_ROOT=$(cd "$PROGDIR/../.." && pwd)
|
|
NDK_BUILDTOOLS_PATH=$NDK_ROOT/build/tools
|
|
. $NDK_ROOT/build/tools/prebuilt-common.sh
|
|
|
|
panic () {
|
|
echo "ERROR: $@" >&2; exit 1
|
|
}
|
|
|
|
fail_panic () {
|
|
if [ $? != 0 ]; then panic "$@"; fi
|
|
}
|
|
|
|
|
|
# Command-line processing
|
|
#
|
|
# Note: try to keep in alphabetical order, same for the --option cases below.
|
|
#
|
|
ABI=
|
|
HELP=
|
|
LIST_TESTS=
|
|
NO_SYSROOT=
|
|
SYSROOT=
|
|
TEST_SUBDIRS=
|
|
VERBOSE=1
|
|
|
|
# Parse options
|
|
for opt; do
|
|
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
|
|
case $opt in
|
|
--abi=*)
|
|
ABI=$optarg
|
|
;;
|
|
--help|-h|-?)
|
|
HELP=true
|
|
;;
|
|
--list)
|
|
LIST_TESTS=true
|
|
;;
|
|
--no-sysroot)
|
|
NO_SYSROOT=true
|
|
;;
|
|
--prefix=*)
|
|
PREFIX=$optarg
|
|
;;
|
|
--quiet|-q)
|
|
VERBOSE=$(( $VERBOSE - 1 ))
|
|
;;
|
|
--sysroot=*)
|
|
SYSROOT=$optarg
|
|
;;
|
|
--verbose|-v)
|
|
VERBOSE=$(( $VERBOSE + 1 ))
|
|
;;
|
|
-*)
|
|
panic "Unknown option '$opt'. See --help for list of valid ones."
|
|
;;
|
|
*)
|
|
TEST_SUBDIRS=$TEST_SUBDIRS" "$opt
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ "$HELP" ]; then
|
|
echo "Usage: $PROGNAME [options] [testname+]"
|
|
echo ""
|
|
echo "Run a set of unit tests to check that a given Android NDK toolchain works"
|
|
echo "as expected. Useful to catch regressions when generating new toolchain"
|
|
echo "binaries."
|
|
echo ""
|
|
echo "You can pass the full path to the toolchain either with the --prefix"
|
|
echo "option, or by defining PREFIX in your environment before calling this script."
|
|
echo "For example:"
|
|
echo ""
|
|
echo " $PROGNAME --prefix=\$NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi"
|
|
echo ""
|
|
echo "The prefix can also be the full-path to the \$TARGET-gcc or \$TARGET-g++ program "
|
|
echo ""
|
|
echo "The script will automatically use an NDK-provided sysroot, but you can specify an"
|
|
echo "alternate one with the --sysroot=<path> option. You can also use --no-sysroot if"
|
|
echo "the toolchain already provides its own sysroot (e.g. if it is a standalone toolchain"
|
|
echo "generated with make-standalone-toolchain.sh)."
|
|
echo ""
|
|
echo "The target ABI is normally auto-detected from the toolchain, but you can specify an"
|
|
echo "alternative one with the --abi=<name> option. This is only useful on ARM, where the"
|
|
echo "default ABI is 'armeabi' targetting the ARMv5TE instruction set. If you want to check"
|
|
echo "the generation of ARMv7-A machine code, use the following:"
|
|
echo ""
|
|
echo " --abi=armeabi-v7a"
|
|
echo ""
|
|
echo "When called without any arguments, the script will run all known toolchain tests."
|
|
echo "You can restrict the list of tests by passing them on the command-line. Use --list"
|
|
echo "to display the list of all tests that are relevant for your current ABI."
|
|
echo ""
|
|
echo "More information about each test can be displayed by using --verbose."
|
|
echo ""
|
|
echo "Valid options:"
|
|
echo ""
|
|
echo " --help|-h|-? Print this message."
|
|
echo " --verbose|-v Increase verbosity."
|
|
echo " --quiet|-q Decrease verbosity."
|
|
echo " --list List all available tests for current ABI."
|
|
echo " --prefix=<prefix> Specify full toolchain binary prefix."
|
|
echo " --sysroot=<path> Specify alternate sysroot."
|
|
echo " --no-sysroot Do not use a sysroot."
|
|
echo " --abi=<name> Specify target ABI name."
|
|
echo ""
|
|
exit 0
|
|
fi
|
|
|
|
TMPDIR=/tmp/ndk-$USER/tests/standalone
|
|
mkdir -p "$TMPDIR" && rm -rf "$TMPDIR/*"
|
|
|
|
BUILD_DIR=$TMPDIR/build
|
|
mkdir -p "$BUILD_DIR"
|
|
|
|
LOGFILE=$TMPDIR/log.txt
|
|
echo -n "" > $LOGFILE
|
|
|
|
if [ $VERBOSE -ge 3 ]; then
|
|
run () {
|
|
echo "# COMMAND: $@"
|
|
"$@"
|
|
}
|
|
elif [ $VERBOSE -ge 2 ]; then
|
|
run () {
|
|
echo "# COMMAND: $@" >> $LOGFILE
|
|
"$@"
|
|
}
|
|
else
|
|
run () {
|
|
echo "# COMMAND[$@]" >> $LOGFILE
|
|
"$@" >> $LOGFILE 2>&1
|
|
}
|
|
fi
|
|
|
|
if [ $VERBOSE -ge 2 ]; then
|
|
run_script () {
|
|
$SHELL "$@"
|
|
}
|
|
else
|
|
run_script () {
|
|
$SHELL "$@" >> $LOGFILE 2>&1
|
|
}
|
|
fi
|
|
|
|
if [ $VERBOSE -ge 1 ]; then
|
|
dump () {
|
|
echo "$@"
|
|
}
|
|
else
|
|
dump () {
|
|
: # nothing
|
|
}
|
|
fi
|
|
|
|
if [ "$HOST_OS" = "cygwin" -o "$HOST_OS" = "windows" ] ; then
|
|
NULL="NUL"
|
|
else
|
|
NULL="/dev/null"
|
|
fi
|
|
|
|
# Probe a given sub-directory and see if it contains valid test files.
|
|
# $1: sub-directory path
|
|
# Return: 0 on success, 1 otherwise
|
|
#
|
|
# This can also sets the following global variables:
|
|
# TEST_TYPE
|
|
# SCRIPT
|
|
# SOURCES
|
|
#
|
|
probe_test_subdir ()
|
|
{
|
|
local DIR="$1"
|
|
|
|
TEST_TYPE=
|
|
SCRIPT=
|
|
SOURCES=
|
|
|
|
if [ -f "$DIR/run.sh" ]; then
|
|
TEST_TYPE=script
|
|
SCRIPT=run.sh
|
|
|
|
elif [ -f "$DIR/run-$ABI.sh" ]; then
|
|
TEST_TYPE=script
|
|
SCRIPT=run-$ABI.sh
|
|
|
|
elif [ -f "$DIR/main.c" ]; then
|
|
TEST_TYPE=c_executable
|
|
SOURCES=main.c
|
|
|
|
elif [ -f "$DIR/main.cpp" ]; then
|
|
TEST_TYPE=cxx_executable
|
|
SOURCES=main.cpp
|
|
|
|
else
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
|
|
# Handle --list option now, then exit
|
|
if [ -n "$LIST_TESTS" ]; then
|
|
echo "List of available toolchain tests:"
|
|
if [ -z "$ABI" ]; then
|
|
ABI=armeabi
|
|
fi
|
|
for TEST_SUBDIR in $(cd $PROGDIR && ls -d *); do
|
|
SUBDIR=$PROGDIR/$TEST_SUBDIR
|
|
if probe_test_subdir "$SUBDIR"; then
|
|
echo " $TEST_SUBDIR"
|
|
fi
|
|
done
|
|
exit 0
|
|
fi
|
|
|
|
if [ -z "$PREFIX" ]; then
|
|
panic "Please define PREFIX in your environment, or use --prefix=<prefix> option."
|
|
fi
|
|
|
|
CC=
|
|
CXX=
|
|
CC_TARGET=
|
|
if [ "$PREFIX" = "${PREFIX%clang}" ]; then
|
|
# Test GCC
|
|
# Remove -gcc or -g++ from prefix if any
|
|
PREFIX=${PREFIX%-gcc}
|
|
PREFIX=${PREFIX%-g++}
|
|
|
|
# Add a trailing dash to the prefix, if there isn't any
|
|
PREFIX=${PREFIX%-}-
|
|
|
|
GCC=${PREFIX}gcc
|
|
if [ ! -f "$GCC" ]; then
|
|
panic "Missing compiler, please fix your prefix definition: $GCC"
|
|
fi
|
|
|
|
GCC=$(which $GCC 2>$NULL)
|
|
if [ -z "$GCC" -o ! -f "$GCC" ]; then
|
|
panic "Bad compiler path: ${PREFIX}gcc"
|
|
fi
|
|
|
|
# Remove trailing .exe if any
|
|
GCC=${GCC%${HOST_EXE}}
|
|
|
|
GCCDIR=$(dirname "$GCC")
|
|
GCCBASE=$(basename "$GCC")
|
|
|
|
GCCDIR=$(cd "$GCCDIR" && pwd)
|
|
GCC=$GCCDIR/$GCCBASE
|
|
|
|
PREFIX=${GCC%%gcc}
|
|
|
|
CC=${PREFIX}gcc
|
|
CXX=${PREFIX}g++
|
|
CC_TARGET=$($GCC -v 2>&1 | tr ' ' '\n' | grep -e --target=)
|
|
CC_TARGET=${CC_TARGET##--target=}
|
|
else
|
|
# Test Clang
|
|
# Remove clang or clang++ from prefix if any
|
|
PREFIX=${PREFIX%clang}
|
|
PREFIX=${PREFIX%clang++}
|
|
|
|
CLANG=${PREFIX}clang
|
|
if [ ! -f "$CLANG" ]; then
|
|
panic "Missing compiler, please fix your prefix definition: $CLANG"
|
|
fi
|
|
|
|
CLANGDIR=$(dirname "$CLANG")
|
|
CLANGBASE=$(basename "$CLANG")
|
|
|
|
CLANGDIR=$(cd "$CLANGDIR" && pwd)
|
|
CLANG=$CLANGDIR/$CLANGBASE
|
|
|
|
PREFIX=${CLANG%%clang}
|
|
|
|
# Find *-ld in the same directory eventaully usable as ${PREFIX}-ld
|
|
GNU_LD=$(cd $CLANGDIR && ls *-ld${HOST_EXE})
|
|
GNU_LD=$CLANGDIR/$GNU_LD
|
|
if [ ! -f "$GNU_LD" ]; then
|
|
panic "Missing linker in the same directory as clang/clang++: $CLANGDIR"
|
|
fi
|
|
|
|
PREFIX=${GNU_LD%ld${HOST_EXE}}
|
|
|
|
CC=$CLANG
|
|
CXX=${CLANG%clang}clang++
|
|
CC_TARGET=$($CLANG -v 2>&1 | grep Target:)
|
|
CC_TARGET=${CC_TARGET##Target: }
|
|
fi
|
|
|
|
if [ -z "$ABI" ]; then
|
|
# Auto-detect target CPU architecture
|
|
dump "Auto-detected target configuration: $CC_TARGET"
|
|
case $CC_TARGET in
|
|
arm*-linux-androideabi)
|
|
ABI=armeabi
|
|
ARCH=arm
|
|
;;
|
|
i686*-linux-android)
|
|
ABI=x86
|
|
ARCH=x86
|
|
;;
|
|
mipsel*-linux-android)
|
|
ABI=mips
|
|
ARCH=mips
|
|
;;
|
|
aarch64*-linux-android)
|
|
ABI=arm64-v8a
|
|
ARCH=arm64
|
|
;;
|
|
x86_64*-linux-android)
|
|
ABI=x86_64
|
|
ARCH=x86_64
|
|
;;
|
|
mips64el*-linux-android)
|
|
ABI=mips64
|
|
ARCH=mips64
|
|
;;
|
|
*)
|
|
panic "Unknown target architecture '$CC_TARGET', please use --abi=<name> to manually specify ABI."
|
|
esac
|
|
dump "Auto-config: --abi=$ABI"
|
|
fi
|
|
|
|
COMMON_FLAGS=
|
|
|
|
# Ensure ABI_<abi> is defined as a compiler macro when building test programs.
|
|
# as a compiler macro when building all test programs.
|
|
ABI_MACRO=ABI_$(echo "$ABI" | tr '-' '_')
|
|
COMMON_FLAGS=$COMMON_FLAGS" -D$ABI_MACRO=1"
|
|
|
|
if [ -n "$NO_SYSROOT" ]; then
|
|
SYSROOT=
|
|
elif [ -n "$SYSROOT" ]; then
|
|
if [ ! -d "$SYSROOT" ]; then
|
|
panic "Sysroot directory does not exist: $SYSROOT"
|
|
fi
|
|
# Sysroot must be absolute path
|
|
SYSROOT=$(cd $SYSROOT && pwd)
|
|
COMMON_FLAGS=$COMMON_FLAGS" --sysroot=$SYSROOT"
|
|
else
|
|
# Auto-detect sysroot
|
|
PLATFORM="android-"$(get_default_api_level_for_arch $ARCH)
|
|
SYSROOT=$NDK_ROOT/platforms/$PLATFORM/arch-$ARCH
|
|
if [ ! -d "$SYSROOT" ]; then
|
|
panic "Can't find sysroot file, use --sysroot to point to valid one: $SYSROOT"
|
|
fi
|
|
if [ ! -f "$SYSROOT/usr/lib/libc.so" ]; then
|
|
panic "Incomplete sysroot, use --sysroot to point to valid one: $SYSROOT"
|
|
fi
|
|
if [ "$HOST_OS" = "cygwin" ]; then
|
|
SYSROOT=`cygpath -m $SYSROOT`
|
|
else
|
|
if [ "$HOST_OS" = "windows" -a "$OSTYPE" = "msys" ]; then
|
|
# use -W specific to MSys to get windows path
|
|
SYSROOT=$(cd $SYSROOT ; pwd -W)
|
|
fi
|
|
fi
|
|
dump "Auto-config: --sysroot=$SYSROOT"
|
|
COMMON_FLAGS=$COMMON_FLAGS" --sysroot=$SYSROOT"
|
|
fi
|
|
|
|
if [ -z "$CXXFLAGS" ]; then
|
|
CXXFLAGS=$CFLAGS
|
|
fi
|
|
|
|
# NOTE: We need to add -fno-exceptions, otherwise some toolchains compile
|
|
# with exception support by default, and the test programs fail to
|
|
# link due to an undefined reference to __gxx_personality_v0.
|
|
#
|
|
# This symbol is normally part of libsupc++ which is not available
|
|
# if you don't have the GNU libstdc++ installed into your toolchain
|
|
# directory.
|
|
#
|
|
# Affects the x86 and mips toolchains, but not the ARM one.
|
|
# Not sure if we want exceptions enabled by default or not.
|
|
#
|
|
CXXFLAGS=$CXXFLAGS" -fno-exceptions"
|
|
|
|
CFLAGS=$COMMON_FLAGS" "$CFLAGS
|
|
CXXFLAGS=$COMMON_FLAGS" "$CXXFLAGS
|
|
|
|
if [ -z "$TEST_SUBDIRS" ]; then
|
|
TEST_SUBDIRS=$(cd $PROGDIR && ls -d *)
|
|
fi
|
|
|
|
COUNT=0
|
|
FAILURES=0
|
|
for TEST_SUBDIR in $TEST_SUBDIRS; do
|
|
SUBDIR=$PROGDIR/$TEST_SUBDIR
|
|
|
|
if ! probe_test_subdir "$SUBDIR"; then
|
|
continue
|
|
fi
|
|
|
|
rm -rf "$BUILD_DIR"/* &&
|
|
cp -RL "$SUBDIR"/* "$BUILD_DIR/"
|
|
fail_panic "Could not copy test files to $BUILD_DIR !?"
|
|
|
|
dump_n "Running $TEST_SUBDIR test... "
|
|
|
|
case $TEST_TYPE in
|
|
script)
|
|
(
|
|
export PREFIX CC CXX CFLAGS CXXFLAGS LDFLAGS VERBOSE ABI NULL
|
|
run cd "$BUILD_DIR" && run_script $SCRIPT
|
|
)
|
|
RET=$?
|
|
;;
|
|
|
|
c_executable)
|
|
(
|
|
run cd "$BUILD_DIR" && run $CC $LDFLAGS $CFLAGS -o $NULL $SOURCES
|
|
)
|
|
RET=$?
|
|
;;
|
|
|
|
cxx_executable)
|
|
(
|
|
run cd "$BUILD_DIR" && run $CXX $LDFLAGS $CXXFLAGS -o $NULL $SOURCES
|
|
)
|
|
RET=$?
|
|
;;
|
|
esac
|
|
|
|
if [ "$RET" != 0 ]; then
|
|
dump "KO"
|
|
FAILURES=$(( $FAILURES + 1 ))
|
|
else
|
|
dump "ok"
|
|
fi
|
|
COUNT=$(( $COUNT + 1 ))
|
|
done
|
|
|
|
if [ "$FAILURES" -eq 0 ]; then
|
|
dump "$COUNT/$COUNT tests passed. Success."
|
|
exit 0
|
|
else
|
|
dump "$FAILURES tests failed out of $COUNT."
|
|
exit 1
|
|
fi
|