diff --git a/Makefile b/Makefile index 9a17d6baa5..d0cfd81391 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ GYPFLAGS ?= TESTFLAGS ?= ANDROID_NDK_ROOT ?= ANDROID_TOOL_PREFIX = $(ANDROID_NDK_ROOT)/toolchain/bin/arm-linux-androideabi +ANDROID_V8 ?= /data/local/v8 # Special build flags. Use them like this: "make library=shared" @@ -107,7 +108,7 @@ endif # - every combination ., e.g. "ia32.release" # - "native": current host's architecture, release mode # - any of the above with .check appended, e.g. "ia32.release.check" -# - "android": cross-compile for Android/ARM (release mode) +# - "android": cross-compile for Android/ARM # - default (no target specified): build all DEFAULT_ARCHES and MODES # - "check": build all targets and run all tests # - ".clean" for any in ARCHES @@ -120,6 +121,7 @@ endif ARCHES = ia32 x64 arm mips DEFAULT_ARCHES = ia32 x64 arm MODES = release debug +ANDROID_MODES = android.release android.debug # List of files that trigger Makefile regeneration: GYPFILES = build/all.gyp build/common.gypi build/standalone.gypi \ @@ -166,8 +168,9 @@ native: $(OUTDIR)/Makefile.native CXX="$(CXX)" LINK="$(LINK)" BUILDTYPE=Release \ builddir="$(shell pwd)/$(OUTDIR)/$@" -# TODO(jkummerow): add "android.debug" when we need it. -android android.release: $(OUTDIR)/Makefile.android +android: $(ANDROID_MODES) + +$(ANDROID_MODES): $(OUTDIR)/Makefile.android @$(MAKE) -C "$(OUTDIR)" -f Makefile.android \ CXX="$(ANDROID_TOOL_PREFIX)-g++" \ AR="$(ANDROID_TOOL_PREFIX)-ar" \ @@ -175,8 +178,9 @@ android android.release: $(OUTDIR)/Makefile.android CC="$(ANDROID_TOOL_PREFIX)-gcc" \ LD="$(ANDROID_TOOL_PREFIX)-ld" \ LINK="$(ANDROID_TOOL_PREFIX)-g++" \ - BUILDTYPE=Release \ - builddir="$(shell pwd)/$(OUTDIR)/android.release" + BUILDTYPE=$(shell echo $(subst .,,$(suffix $@)) | \ + python -c "print raw_input().capitalize()") \ + builddir="$(shell pwd)/$(OUTDIR)/$@" # Test targets. check: all @@ -196,6 +200,17 @@ $(CHECKS): $$(basename $$@) @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \ --arch-and-mode=$(basename $@) $(TESTFLAGS) +$(addsuffix .sync, $(ANDROID_MODES)): $$(basename $$@) + @tools/android-sync.sh $(basename $@) $(OUTDIR) \ + $(shell pwd) $(ANDROID_V8) + +$(addsuffix .check, $(ANDROID_MODES)): $$(basename $$@).sync + @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \ + --arch-and-mode=$(basename $@) \ + --special-command="tools/android-run.py @" + +android.check: android.release.check android.debug.check + native.check: native @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR)/native \ --arch-and-mode=. $(TESTFLAGS) diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index fc111ab94b..a2fa0aa713 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -54,7 +54,7 @@ test-profile-generator/RecordStackTraceAtStartProfiling: PASS || FAIL test-weakmaps/Shrinking: FAIL ############################################################################## -[ $arch == arm ] +[ $arch == arm || $arch == android ] # We cannot assume that we can throw OutOfMemory exceptions in all situations. # Apparently our ARM box is in such a state. Skip the test as it also runs for diff --git a/test/cctest/testcfg.py b/test/cctest/testcfg.py index f1387e8a4f..532edfc26d 100644 --- a/test/cctest/testcfg.py +++ b/test/cctest/testcfg.py @@ -93,7 +93,8 @@ class CcTestConfiguration(test.TestConfiguration): if utils.IsWindows(): executable += '.exe' executable = join(self.context.buildspace, executable) - output = test.Execute([executable, '--list'], self.context) + full_command = self.context.processor([executable, '--list']) + output = test.Execute(full_command, self.context) if output.exit_code != 0: print output.stdout print output.stderr diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status index 2d54cf01e1..e14a543d4f 100644 --- a/test/mjsunit/mjsunit.status +++ b/test/mjsunit/mjsunit.status @@ -49,28 +49,27 @@ regress/regress-create-exception: PASS, SKIP if $mode == debug ############################################################################## # This one uses a built-in that's only present in debug mode. It takes # too long to run in debug mode on ARM and MIPS. -fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm || $arch == mips) +fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm || $arch == android || $arch == mips) -big-object-literal: PASS, SKIP if ($arch == arm) +big-object-literal: PASS, SKIP if ($arch == arm || $arch == android) # Issue 488: this test sometimes times out. array-constructor: PASS || TIMEOUT # Very slow on ARM and MIPS, contains no architecture dependent code. -unicode-case-overoptimization: PASS, TIMEOUT if ($arch == arm || $arch == mips) +unicode-case-overoptimization: PASS, TIMEOUT if ($arch == arm || $arch == android || $arch == mips) # Test Crankshaft compilation time. Expected to take too long in debug mode. regress/regress-1969: PASS, SKIP if $mode == debug ############################################################################## -[ $isolates ] - # This test sets the umask on a per-process basis and hence cannot be # used in multi-threaded runs. -d8-os: SKIP +# On android there is no /tmp directory. +d8-os: PASS, SKIP if ($isolates || $arch == android) ############################################################################## -[ $arch == arm ] +[ $arch == arm || $arch == android ] # Slow tests which times out in debug mode. try: PASS, SKIP if $mode == debug diff --git a/tools/android-run.py b/tools/android-run.py new file mode 100755 index 0000000000..881630a23f --- /dev/null +++ b/tools/android-run.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# +# Copyright 2012 the V8 project authors. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This script executes the passed command line on Android device +# using 'adb shell' command. Unfortunately, 'adb shell' always +# returns exit code 0, ignoring the exit code of executed command. +# Since we need to return non-zero exit code if the command failed, +# we augment the passed command line with exit code checking statement +# and output special error string in case of non-zero exit code. +# Then we parse the output of 'adb shell' and look for that error string. + +import os +from os.path import join, dirname, abspath +import subprocess +import sys +import tempfile + +def Check(output, errors): + failed = any([s.startswith('/system/bin/sh:') or s.startswith('Error') + for s in output.split('\n')]) + return 1 if failed else 0 + +def Execute(cmdline): + (fd_out, outname) = tempfile.mkstemp() + (fd_err, errname) = tempfile.mkstemp() + process = subprocess.Popen( + args=cmdline, + shell=True, + stdout=fd_out, + stderr=fd_err, + ) + exit_code = process.wait() + os.close(fd_out) + os.close(fd_err) + output = file(outname).read() + errors = file(errname).read() + os.unlink(outname) + os.unlink(errname) + sys.stdout.write(output) + sys.stderr.write(errors) + return exit_code or Check(output, errors) + +def Escape(arg): + def ShouldEscape(): + for x in arg: + if not x.isalnum() and x != '-' and x != '_': + return True + return False + + return arg if not ShouldEscape() else '"%s"' % (arg.replace('"', '\\"')) + +def WriteToTemporaryFile(data): + (fd, fname) = tempfile.mkstemp() + os.close(fd) + tmp_file = open(fname, "w") + tmp_file.write(data) + tmp_file.close() + return fname + +def Main(): + if (len(sys.argv) == 1): + print("Usage: %s " % sys.argv[0]) + return 1 + workspace = abspath(join(dirname(sys.argv[0]), '..')) + android_workspace = os.getenv("ANDROID_V8", "/data/local/v8") + args = [Escape(arg) for arg in sys.argv[1:]] + script = (" ".join(args) + "\n" + "if [ $? -ne 0 ]\n" + " then echo \"Error returned by test\";\n" + "fi\n") + script = script.replace(workspace, android_workspace) + script_file = WriteToTemporaryFile(script) + android_script_file = android_workspace + "/" + script_file + command = ("adb push '%s' %s;" % (script_file, android_script_file) + + "adb shell 'sh %s';" % android_script_file + + "adb shell 'rm %s'" % android_script_file) + error_code = Execute(command) + os.unlink(script_file) + return error_code + +if __name__ == '__main__': + sys.exit(Main()) diff --git a/tools/android-sync.sh b/tools/android-sync.sh new file mode 100755 index 0000000000..90fa3180ed --- /dev/null +++ b/tools/android-sync.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# Copyright 2012 the V8 project authors. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This script pushes android binaries and test data to the device. +# The first argument can be either "android.release" or "android.debug". +# The second argument is a relative path to the output directory with binaries. +# The third argument is the absolute path to the V8 directory on the host. +# The fourth argument is the absolute path to the V8 directory on the device. + +if [ ${#@} -lt 4 ] ; then + echo "Error: need 4 arguments" + exit 1 +fi + +ARCH_MODE=$1 +OUTDIR=$2 +HOST_V8=$3 +ANDROID_V8=$4 + +function sync_file { + local FILE=$1 + local ANDROID_HASH=$(adb shell "md5 \"$ANDROID_V8/$FILE\"") + local HOST_HASH=$(md5sum "$HOST_V8/$FILE") + if [ "${ANDROID_HASH%% *}" != "${HOST_HASH%% *}" ]; then + adb push "$HOST_V8/$FILE" "$ANDROID_V8/$FILE" &> /dev/null + fi + echo -n "." +} + +function sync_dir { + local DIR=$1 + echo -n "sync to $ANDROID_V8/$DIR" + for FILE in $(find "$HOST_V8/$DIR" -type f); do + local RELATIVE_FILE=${FILE:${#HOST_V8}} + sync_file "$RELATIVE_FILE" + done + echo "" +} + +echo -n "sync to $ANDROID_V8/$OUTDIR/$ARCH_MODE" +sync_file "$OUTDIR/$ARCH_MODE/cctest" +sync_file "$OUTDIR/$ARCH_MODE/d8" +sync_file "$OUTDIR/$ARCH_MODE/preparser" +echo "" +echo -n "sync to $ANDROID_V8/tools" +sync_file tools/consarray.js +sync_file tools/codemap.js +sync_file tools/csvparser.js +sync_file tools/profile.js +sync_file tools/splaytree.js +echo "" +sync_dir test/message +sync_dir test/mjsunit +sync_dir test/preparser diff --git a/tools/test-wrapper-gypbuild.py b/tools/test-wrapper-gypbuild.py index 6de021bc54..5d3c7e4c61 100755 --- a/tools/test-wrapper-gypbuild.py +++ b/tools/test-wrapper-gypbuild.py @@ -148,7 +148,7 @@ def ProcessOptions(options): print "Unknown mode %s" % mode return False for arch in options.arch: - if not arch in ['ia32', 'x64', 'arm', 'mips']: + if not arch in ['ia32', 'x64', 'arm', 'mips', 'android']: print "Unknown architecture %s" % arch return False if options.buildbot: diff --git a/tools/test.py b/tools/test.py index 5131ad7617..d3bfb5b8b5 100755 --- a/tools/test.py +++ b/tools/test.py @@ -140,9 +140,9 @@ def EscapeCommand(command): parts = [] for part in command: if ' ' in part: - # Escape spaces. We may need to escape more characters for this - # to work properly. - parts.append('"%s"' % part) + # Escape spaces and double quotes. We may need to escape more characters + # for this to work properly. + parts.append('"%s"' % part.replace('"', '\\"')) else: parts.append(part) return " ".join(parts) @@ -1283,7 +1283,7 @@ def ProcessOptions(options): options.scons_flags.append("arch=" + options.arch) # Simulators are slow, therefore allow a longer default timeout. if options.timeout == -1: - if options.arch == 'arm' or options.arch == 'mips': + if options.arch in ['android', 'arm', 'mips']: options.timeout = 2 * TIMEOUT_DEFAULT; else: options.timeout = TIMEOUT_DEFAULT;