• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
31PROGNAME=$(basename "$0")
32PROGDIR=$(dirname "$0")
33NDK_ROOT=$(cd "$PROGDIR/../.." && pwd)
34NDK_BUILDTOOLS_PATH=$NDK_ROOT/build/tools
35. $NDK_ROOT/build/tools/prebuilt-common.sh
36
37panic () {
38    echo "ERROR: $@" >&2; exit 1
39}
40
41fail_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#
50ABI=
51HELP=
52LIST_TESTS=
53NO_SYSROOT=
54SYSROOT=
55TEST_SUBDIRS=
56VERBOSE=1
57
58# Parse options
59for 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
93done
94
95if [ "$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
140fi
141
142TMPDIR=/tmp/ndk-$USER/tests/standalone
143mkdir -p "$TMPDIR" && rm -rf "$TMPDIR/*"
144
145BUILD_DIR=$TMPDIR/build
146mkdir -p "$BUILD_DIR"
147
148LOGFILE=$TMPDIR/log.txt
149echo -n "" > $LOGFILE
150
151if [ $VERBOSE -ge 3 ]; then
152    run () {
153        echo "# COMMAND: $@"
154        "$@"
155    }
156elif [ $VERBOSE -ge 2 ]; then
157    run () {
158        echo "# COMMAND: $@" >> $LOGFILE
159        "$@"
160    }
161else
162    run () {
163        echo "# COMMAND[$@]" >> $LOGFILE
164        "$@" >> $LOGFILE 2>&1
165    }
166fi
167
168if [ $VERBOSE -ge 2 ]; then
169    run_script () {
170        $SHELL "$@"
171    }
172else
173    run_script () {
174        $SHELL "$@" >> $LOGFILE 2>&1
175    }
176fi
177
178if [ $VERBOSE -ge 1 ]; then
179    dump () {
180        echo "$@"
181    }
182else
183    dump () {
184        :  # nothing
185    }
186fi
187
188if [ "$HOST_OS" = "cygwin" -o "$HOST_OS" = "windows" ] ; then
189    NULL="NUL"
190else
191    NULL="/dev/null"
192fi
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#
203probe_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
236if [ -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
248fi
249
250if [ -z "$PREFIX" ]; then
251    panic "Please define PREFIX in your environment, or use --prefix=<prefix> option."
252fi
253
254CC=
255CXX=
256CC_TARGET=
257if [ "$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=}
291else
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: }
323fi
324
325if [ -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"
357fi
358
359COMMON_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.
363ABI_MACRO=ABI_$(echo "$ABI" | tr '-' '_')
364COMMON_FLAGS=$COMMON_FLAGS" -D$ABI_MACRO=1"
365
366if [ -n "$NO_SYSROOT" ]; then
367    SYSROOT=
368elif [ -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"
375else
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"
395fi
396
397if [ -z "$CXXFLAGS" ]; then
398    CXXFLAGS=$CFLAGS
399fi
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#
412CXXFLAGS=$CXXFLAGS" -fno-exceptions"
413
414CFLAGS=$COMMON_FLAGS" "$CFLAGS
415CXXFLAGS=$COMMON_FLAGS" "$CXXFLAGS
416
417if [ -z "$TEST_SUBDIRS" ]; then
418    TEST_SUBDIRS=$(cd $PROGDIR && ls -d *)
419fi
420
421COUNT=0
422FAILURES=0
423for 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 ))
467done
468
469if [ "$FAILURES" -eq 0 ]; then
470    dump "$COUNT/$COUNT tests passed. Success."
471    exit 0
472else
473    dump "$FAILURES tests failed out of $COUNT."
474    exit 1
475fi
476