VIXL Release 1.0
Refer to the README.md and LICENCE files for details.
diff --git a/tools/cross_build_gcc.sh b/tools/cross_build_gcc.sh
new file mode 100755
index 0000000..3a365d9
--- /dev/null
+++ b/tools/cross_build_gcc.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# Copyright 2013, ARM Limited
+# 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 ARM Limited 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 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.
+
+if [ "$#" -lt 1 ]; then
+ echo "Usage: tools/cross_build_gcc.sh <GCC prefix> [scons arguments ...]"
+ exit 1
+fi
+
+export CXX=$1g++
+export AR=$1ar
+export RANLIB=$1ranlib
+export CC=$1gcc
+export LD=$1ld
+
+OK=1
+if [ ! -x "$CXX" ]; then
+ echo "Error: $CXX does not exist or is not executable."
+ OK=0
+fi
+if [ ! -x "$AR" ]; then
+ echo "Error: $AR does not exist or is not executable."
+ OK=0
+fi
+if [ ! -x "$RANLIB" ]; then
+ echo "Error: $RANLIB does not exist or is not executable."
+ OK=0
+fi
+if [ ! -x "$CC" ]; then
+ echo "Error: $CC does not exist or is not executable."
+ OK=0
+fi
+if [ ! -x "$LD" ]; then
+ echo "Error: $LD does not exist or is not executable."
+ OK=0
+fi
+if [ $OK -ne 1 ]; then
+ exit 1
+fi
+
+
+shift
+scons $@
diff --git a/tools/git.py b/tools/git.py
new file mode 100644
index 0000000..b661d11
--- /dev/null
+++ b/tools/git.py
@@ -0,0 +1,75 @@
+# Copyright 2013 ARM Limited
+# 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 ARM Limited 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 ARM LIMITED 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 ARM LIMITED 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.
+
+import re
+import util
+import os.path
+
+def is_git_repository_root():
+ return os.path.isdir('.git')
+
+def get_current_branch():
+ status, branches = util.getstatusoutput('git branch')
+ if status != 0: util.abort('Failed to run git branch.')
+ match = re.search("^\* (.*)$", branches, re.MULTILINE)
+ if not match: util.abort('Failed to find the current branch.')
+
+ branch = match.group(1);
+
+ # If we are not on a named branch, return the hash of the HEAD commit.
+ # This can occur (for example) if a specific revision is checked out by
+ # commit hash, or during a rebase.
+ if branch == '(no branch)':
+ status, commit = util.getstatusoutput('git log -1 --pretty=format:"%H"')
+ if status != 0: util.abort('Failed to run git log.')
+ match = re.search('^[0-9a-fA-F]{40}$', commit, re.MULTILINE)
+ if not match: util.abort('Failed to find the current revision.')
+ branch = match.group(0)
+
+ return branch
+
+
+def get_tracked_files():
+ command = 'git ls-tree '
+ branch = get_current_branch()
+ options = ' -r --full-tree --name-only'
+
+ status, tracked = util.getstatusoutput(command + branch + options)
+ if status != 0: util.abort('Failed to list tracked files.')
+
+ return tracked
+
+
+# Get untracked files in src/, test/, and tools/.
+def get_untracked_files():
+ status, output = util.getstatusoutput('git status -s')
+ if status != 0: util.abort('Failed to get git status.')
+
+ untracked_regexp = re.compile('\?\?.*(src/|test/|tools/).*(.cc$|.h$)')
+ files_in_watched_folder = lambda n: untracked_regexp.search(n) != None
+ untracked_files = filter(files_in_watched_folder, output.split('\n'))
+
+ return untracked_files
diff --git a/tools/make_instruction_doc.pl b/tools/make_instruction_doc.pl
new file mode 100755
index 0000000..a244962
--- /dev/null
+++ b/tools/make_instruction_doc.pl
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+
+# Copyright 2013, ARM Limited
+# 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 ARM Limited 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 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.
+
+# Assembler header file.
+my $hfile = "src/a64/assembler-a64.h";
+
+# Extra pseudo instructions added to AArch64.
+my @extras = qw/bind debug dci dc32 dc64/;
+
+my %inst = (); # Global hash of instructions.
+
+$/ = '';
+open(IN, "<$hfile") or die("Can't open header file $header.\n");
+while(<IN>)
+{
+ # Find a function formatted like an instruction.
+ if(my($t) = /^ ((?:void|inline void) [a-z0-9]{1,6})\(/mgp)
+ {
+ my $before = ${^PREMATCH};
+ my $after = ${^POSTMATCH};
+
+ # Extract the instruction.
+ my($i) = $t =~ /(?:void|inline void) ([a-z0-9]{1,6})/;
+
+ # Extract the comment from before the function.
+ my($d) = $before =~ /.* \/\/ ([A-Z].+?\.)$/;
+
+ # Extract and tidy up the function prototype.
+ my($p) = $after =~ /(.*?\))/ms;
+ $p =~ s/\n/\n /g;
+ $p = "$t(".$p;
+
+ # Establish the type of the instruction.
+ my $type = 'integer';
+ ($i =~ /^f/) and $type = 'float';
+ ($i ~~ @extras) and $type = 'pseudo';
+
+ # Push the results into a hash keyed by prototype string.
+ $inst{$p}->{'type'} = $type;
+ $inst{$p}->{'mnemonic'} = $i;
+ $inst{$p}->{'description'} = $d;
+ }
+}
+close(IN);
+
+print <<HEADER;
+VIXL Supported Instruction List
+===============================
+
+This is a list of the AArch64 instructions supported by the VIXL assembler,
+disassembler and simulator. The simulator may not support all floating point
+operations to the precision required by AArch64 - please check the simulator
+source code for details.
+
+HEADER
+
+print describe_insts('AArch64 integer instructions', 'integer');
+print describe_insts('AArch64 floating point instructions', 'float');
+print describe_insts('Additional or pseudo instructions', 'pseudo');
+
+# Sort instructions by mnemonic and then description.
+sub inst_sort
+{
+ $inst{$a}->{'mnemonic'} cmp $inst{$b}->{'mnemonic'} ||
+ $inst{$a}->{'description'} cmp $inst{$b}->{'description'};
+}
+
+# Return a Markdown formatted list of instructions of a particular type.
+sub describe_insts
+{
+ my($title, $type) = @_;
+ my $result = '';
+ $result .= "$title\n";
+ $result .= '-' x length($title);
+ $result .= "\n\n";
+
+ foreach my $i (sort inst_sort keys(%inst))
+ {
+ next if($inst{$i}->{'type'} ne $type);
+ $result .= sprintf("### %s ###\n\n%s\n\n", $inst{$i}->{'mnemonic'}, $inst{$i}->{'description'});
+ $result .= " $i\n\n\n";
+ }
+ $result .= "\n";
+ return $result
+}
+
+
diff --git a/tools/presubmit.py b/tools/presubmit.py
new file mode 100755
index 0000000..6632e4b
--- /dev/null
+++ b/tools/presubmit.py
@@ -0,0 +1,202 @@
+#!/usr/bin/env python2.7
+
+# Copyright 2013, ARM Limited
+# 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 ARM Limited 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 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.
+
+import os
+import sys
+import argparse
+import re
+
+import util
+import git
+
+# Google's cpplint.py from depot_tools is the linter used here.
+CPP_LINTER_RULES = '''
+build/class
+build/deprecated
+build/endif_comment
+build/forward_decl
+build/include_order
+build/printf_format
+build/storage_class
+legal/copyright
+readability/boost
+readability/braces
+readability/casting
+readability/constructors
+readability/fn_size
+readability/function
+readability/multiline_comment
+readability/multiline_string
+readability/streams
+readability/utf8
+runtime/arrays
+runtime/casting
+runtime/deprecated_fn
+runtime/explicit
+runtime/int
+runtime/memset
+runtime/mutex
+runtime/nonconf
+runtime/printf
+runtime/printf_format
+runtime/references
+runtime/rtti
+runtime/sizeof
+runtime/string
+runtime/virtual
+runtime/vlog
+whitespace/blank_line
+whitespace/braces
+whitespace/comma
+whitespace/comments
+whitespace/end_of_line
+whitespace/ending_newline
+whitespace/indent
+whitespace/labels
+whitespace/line_length
+whitespace/newline
+whitespace/operators
+whitespace/parens
+whitespace/tab
+whitespace/todo
+'''.split()
+
+
+def BuildOptions():
+ result = argparse.ArgumentParser(description='Run the linter and unit tests.')
+ result.add_argument('--verbose', '-v', action='store_true',
+ help='Print all tests output at the end.')
+ result.add_argument('--notest', action='store_true',
+ help='Do not run tests. Run the linter only.')
+ result.add_argument('--nolint', action='store_true',
+ help='Do not run the linter. Run the tests only.')
+ result.add_argument('--noclean', action='store_true',
+ help='Do not clean before build.')
+ result.add_argument('--jobs', '-j', metavar='N', type=int, default=1,
+ help='Allow N jobs at once.')
+ return result.parse_args()
+
+
+def CleanBuildSystem():
+ status, output = util.getstatusoutput('scons mode=release --clean')
+ if status != 0: util.abort('Failed to clean in release mode.')
+ status, output = util.getstatusoutput('scons mode=debug --clean')
+ if status != 0: util.abort('Failed to clean in debug mode.')
+
+
+class Test:
+ def __init__(self, name, command, get_summary):
+ self.name = name
+ self.command = command
+ self.get_summary = get_summary
+ self.output = 'NOT RUN'
+ self.status = 'NOT RUN'
+ self.summary = 'NOT RUN'
+
+ def Run(self):
+ retcode, self.output = util.getstatusoutput(self.command)
+ self.status = 'PASS' if retcode == 0 else 'FAILED'
+ self.summary = self.get_summary(self.output)
+
+ def PrintOutcome(self):
+ print(('%s :'.ljust(20 - len(self.name)) + '%s\n' + ' ' * 18 + '%s')
+ %(self.name, self.status, self.summary))
+
+ def PrintOutput(self):
+ print('\n\n### OUTPUT of ' + self.name)
+ print(self.output)
+
+
+class Tester:
+ def __init__(self):
+ self.tests = []
+
+ def AddTest(self, test):
+ self.tests.append(test)
+
+ def RunAll(self, verbose):
+ for test in self.tests:
+ test.Run()
+ test.PrintOutcome()
+
+ if verbose:
+ for test in self.tests:
+ test.PrintOutput()
+
+
+if __name__ == '__main__':
+ original_dir = os.path.abspath('.')
+ # $ROOT/tools/presubmit.py
+ root_dir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
+ os.chdir(root_dir)
+ args = BuildOptions()
+
+ if not args.nolint and not git.is_git_repository_root():
+ print 'WARNING: This is not a Git repository. The linter will not run.'
+ args.nolint = True
+
+ tester = Tester()
+ if not args.nolint:
+ lint_args = '--filter=-,+' + ',+'.join(CPP_LINTER_RULES) + ' '
+ tracked_files = git.get_tracked_files().split()
+ tracked_files = filter(util.is_cpp_filename, tracked_files)
+ tracked_files = ' '.join(tracked_files)
+ lint = Test('cpp lint',
+ 'cpplint.py ' + lint_args + tracked_files,
+ util.last_line)
+ tester.AddTest(lint)
+ if not args.notest:
+ release = Test('cctest release',
+ './tools/test.py --mode=release --jobs=%d' % args.jobs,
+ util.last_line)
+ debug = Test('cctest debug',
+ './tools/test.py --mode=debug --jobs=%d' % args.jobs,
+ util.last_line)
+ tester.AddTest(release)
+ tester.AddTest(debug)
+
+ if not args.noclean:
+ CleanBuildSystem()
+
+ tester.RunAll(args.verbose)
+
+ # If the linter failed, print its output. We don't do the same for the debug
+ # or release tests because they're easy to run by themselves. In verbose mode,
+ # the output is printed automatically in tester.RunAll().
+ if not args.nolint and lint.status == 'FAILED' and not args.verbose:
+ lint.PrintOutput()
+
+ if git.is_git_repository_root():
+ untracked_files = git.get_untracked_files()
+ if untracked_files:
+ print '\nWARNING: The following files are untracked:'
+ for f in untracked_files:
+ print f.lstrip('?')
+
+ # Restore original directory.
+ os.chdir(original_dir)
diff --git a/tools/test.py b/tools/test.py
new file mode 100755
index 0000000..cf20385
--- /dev/null
+++ b/tools/test.py
@@ -0,0 +1,247 @@
+#!/usr/bin/env python2.7
+
+# Copyright 2013, ARM Limited
+# 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 ARM Limited 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 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.
+
+import os
+import sys
+import argparse
+import re
+import subprocess
+import threading
+import time
+import util
+
+
+def BuildOptions():
+ result = argparse.ArgumentParser(description = 'Unit test tool')
+ result.add_argument('name_filters', metavar='name filters', nargs='*',
+ help='Tests matching any of the regexp filters will be run.')
+ result.add_argument('--mode', action='store', choices=['release', 'debug', 'coverage'],
+ default='release', help='Build mode')
+ result.add_argument('--simulator', action='store', choices=['on', 'off'],
+ default='on', help='Use the builtin a64 simulator')
+ result.add_argument('--timeout', action='store', type=int, default=5,
+ help='Timeout (in seconds) for each cctest (5sec default).')
+ result.add_argument('--nobuild', action='store_true',
+ help='Do not (re)build the tests')
+ result.add_argument('--jobs', '-j', metavar='N', type=int, default=1,
+ help='Allow N jobs at once.')
+ return result.parse_args()
+
+
+def BuildRequiredObjects(arguments):
+ status, output = util.getstatusoutput('scons ' +
+ 'mode=' + arguments.mode + ' ' +
+ 'simulator=' + arguments.simulator + ' ' +
+ 'target=cctest ' +
+ '--jobs=' + str(arguments.jobs))
+
+ if status != 0:
+ print(output)
+ util.abort('Failed bulding cctest')
+
+
+# Display the run progress:
+# [time| progress|+ passed|- failed]
+def UpdateProgress(start_time, passed, failed, card):
+ minutes, seconds = divmod(time.time() - start_time, 60)
+ progress = float(passed + failed) / card * 100
+ passed_colour = '\x1b[32m' if passed != 0 else ''
+ failed_colour = '\x1b[31m' if failed != 0 else ''
+ indicator = '\r[%02d:%02d| %3d%%|' + passed_colour + '+ %d\x1b[0m|' + failed_colour + '- %d\x1b[0m]'
+ sys.stdout.write(indicator % (minutes, seconds, progress, passed, failed))
+
+
+def PrintError(s):
+ # Print the error on a new line.
+ sys.stdout.write('\n')
+ print(s)
+ sys.stdout.flush()
+
+
+# List all tests matching any of the provided filters.
+def ListTests(cctest, filters):
+ status, output = util.getstatusoutput(cctest + ' --list')
+ if status != 0: util.abort('Failed to list all tests')
+
+ available_tests = output.split()
+ if filters:
+ filters = map(re.compile, filters)
+ def is_selected(test_name):
+ for e in filters:
+ if e.search(test_name):
+ return True
+ return False
+
+ return filter(is_selected, available_tests)
+ else:
+ return available_tests
+
+
+# A class representing a cctest.
+class CCtest:
+ cctest = None
+
+ def __init__(self, name, options = None):
+ self.name = name
+ self.options = options
+ self.process = None
+ self.stdout = None
+ self.stderr = None
+
+ def Command(self):
+ command = '%s %s' % (CCtest.cctest, self.name)
+ if self.options is not None:
+ command = '%s %s' % (commnad, ' '.join(options))
+
+ return command
+
+ # Run the test.
+ # Use a thread to be able to control the test.
+ def Run(self, arguments):
+ command = [CCtest.cctest, self.name]
+ if self.options is not None:
+ command += self.options
+
+ def execute():
+ self.process = subprocess.Popen(command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ self.stdout, self.stderr = self.process.communicate()
+
+ thread = threading.Thread(target=execute)
+ retcode = -1
+ # Append spaces to hide the previous test name if longer.
+ sys.stdout.write(' ' + self.name + ' ' * 20)
+ sys.stdout.flush()
+ # Start the test with a timeout.
+ thread.start()
+ thread.join(arguments.timeout)
+ if thread.is_alive():
+ # Too slow! Terminate.
+ PrintError('### TIMEOUT %s\nCOMMAND:\n%s' % (self.name, self.Command()))
+ # If timeout was too small the thread may not have run and self.process
+ # is still None. Therefore check.
+ if (self.process):
+ self.process.terminate()
+ # Allow 1 second to terminate. Else, exterminate!
+ thread.join(1)
+ if thread.is_alive():
+ thread.kill()
+ thread.join()
+ # retcode is already set for failure.
+ else:
+ # Check the return status of the test.
+ retcode = self.process.poll()
+ if retcode != 0:
+ PrintError('### FAILED %s\nSTDERR:\n%s\nSTDOUT:\n%s\nCOMMAND:\n%s'
+ % (self.name, self.stderr.decode(), self.stdout.decode(),
+ self.Command()))
+
+ return retcode
+
+
+# Run all tests in the list 'tests'.
+def RunTests(cctest, tests, arguments):
+ CCtest.cctest = cctest
+ card = len(tests)
+ passed = 0
+ failed = 0
+
+ if card == 0:
+ print('No test to run')
+ return 0
+
+ # When the simulator is on the tests are ran twice: with and without the
+ # debugger.
+ if arguments.simulator:
+ card *= 2
+
+ print('Running %d tests... (timeout = %ds)' % (card, arguments.timeout))
+ start_time = time.time()
+
+ # Initialize the progress indicator.
+ UpdateProgress(start_time, 0, 0, card)
+ for e in tests:
+ variants = [CCtest(e)]
+ if arguments.simulator: variants.append(CCtest(e, ['--debugger']))
+ for v in variants:
+ retcode = v.Run(arguments)
+ # Update the counters and progress indicator.
+ if retcode == 0:
+ passed += 1
+ else:
+ failed += 1
+ UpdateProgress(start_time, passed, failed, card)
+
+ return failed
+
+
+if __name__ == '__main__':
+ original_dir = os.path.abspath('.')
+ # $ROOT/tools/test.py
+ root_dir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
+ os.chdir(root_dir)
+
+ # Parse the arguments and build the executable.
+ args = BuildOptions()
+ if not args.nobuild:
+ BuildRequiredObjects(args)
+
+ # The test binary.
+ cctest = os.path.join(root_dir, 'cctest')
+ if args.simulator == 'on':
+ cctest += '_sim'
+ if args.mode == 'debug':
+ cctest += '_g'
+ elif args.mode == 'coverage':
+ cctest += '_gcov'
+
+ # List available tests.
+ tests = ListTests(cctest, args.name_filters)
+
+ # Delete coverage data files.
+ if args.mode == 'coverage':
+ status, output = util.getstatusoutput('find obj/coverage -name "*.gcda" -exec rm {} \;')
+
+ # Run the tests.
+ status = RunTests(cctest, tests, args)
+ sys.stdout.write('\n')
+
+ # Print coverage information.
+ if args.mode == 'coverage':
+ cmd = 'tggcov -R summary_all,untested_functions_per_file obj/coverage/src/aarch64'
+ p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ print(stdout)
+
+ # Restore original directory.
+ os.chdir(original_dir)
+
+ sys.exit(status)
+
diff --git a/tools/util.py b/tools/util.py
new file mode 100644
index 0000000..2e84d9a
--- /dev/null
+++ b/tools/util.py
@@ -0,0 +1,56 @@
+# Copyright 2013, ARM Limited
+# 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 ARM Limited 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 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.
+
+import sys
+import subprocess
+import shlex
+import re
+
+
+def abort(message):
+ print('ABORTING: ' + message)
+ sys.exit(1)
+
+
+# Emulate python3 subprocess.getstatusoutput.
+def getstatusoutput(command):
+ try:
+ args = shlex.split(command)
+ output = subprocess.check_output(args, stderr=subprocess.STDOUT)
+ return 0, output.rstrip('\n')
+ except subprocess.CalledProcessError as e:
+ return e.returncode, e.output.rstrip('\n')
+
+
+def last_line(text):
+ lines = text.split('\n')
+ last = lines[-1].split('\r')
+ return last[-1]
+
+
+CPP_EXT_REGEXP = re.compile('\.cc$|\.h$')
+def is_cpp_filename(filename):
+ return CPP_EXT_REGEXP.search(filename) != None