1#!/usr/bin/env python2.7 2 3# Copyright 2015, ARM Limited 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 9# * Redistributions of source code must retain the above copyright notice, 10# this list of conditions and the following disclaimer. 11# * Redistributions in binary form must reproduce the above copyright notice, 12# this list of conditions and the following disclaimer in the documentation 13# and/or other materials provided with the distribution. 14# * Neither the name of ARM Limited nor the names of its contributors may be 15# used to endorse or promote products derived from this software without 16# specific prior written permission. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29import os 30import sys 31import argparse 32import re 33import platform 34import subprocess 35import multiprocessing 36 37import git 38import printer 39import test 40import util 41 42 43SUPPORTED_COMPILERS = ['g++', 'clang++'] 44OBJ_DIR = './obj' 45 46 47def BuildOptions(): 48 result = argparse.ArgumentParser( 49 description='Run the linter and unit tests.', 50 # Print default values. 51 formatter_class=argparse.ArgumentDefaultsHelpFormatter) 52 result.add_argument('--verbose', '-v', action='store_true', 53 help='Print all tests output at the end.') 54 result.add_argument('--notest', action='store_true', 55 help='Do not run tests. Run the linter only.') 56 result.add_argument('--nolint', action='store_true', 57 help='Do not run the linter. Run the tests only.') 58 result.add_argument('--noclean', action='store_true', 59 help='Do not clean before build.') 60 result.add_argument('--fast', action='store_true', 61 help='Only test with one toolchain') 62 result.add_argument('--jobs', '-j', metavar='N', type=int, nargs='?', 63 default=1, const=multiprocessing.cpu_count(), 64 help='''Run the tests using N jobs. If the option is set 65 but no value is provided, the script will use as many jobs 66 as it thinks useful.''') 67 sim_default = 'off' if platform.machine() == 'aarch64' else 'on' 68 result.add_argument('--simulator', action='store', choices=['on', 'off'], 69 default=sim_default, 70 help='Explicitly enable or disable the simulator.') 71 return result.parse_args() 72 73 74def check_supported(compiler, mode, std): 75 if compiler not in SUPPORTED_COMPILERS: 76 print 'Invalid compiler.' 77 sys.exit(1) 78 if mode not in ['release', 'debug']: 79 print 'Invalid mode.' 80 sys.exit(1) 81 if std not in ['c++98', 'c++11']: 82 print 'Invalid c++ standard.' 83 sys.exit(1) 84 85 86def initalize_compiler_list(): 87 compiler_list = [] 88 for compiler in SUPPORTED_COMPILERS: 89 if util.has_compiler(compiler) and (len(compiler_list) == 0 or not args.fast): 90 compiler_list.append(compiler) 91 else: 92 # This warning suffices for args.fast too. 93 print 'WARNING: Skipping ' + compiler + ' tests.' 94 if len(compiler_list) == 0: 95 util.abort('Found no supported compilers') 96 return compiler_list 97 98 99def CleanBuildSystem(compiler): 100 def clean(compiler, mode, std): 101 check_supported(compiler, mode, std) 102 os.environ['CXX'] = compiler 103 if args.verbose: 104 print 'Cleaning ' + compiler + ' ' + std + ' ' \ 105 + mode + ' mode test...' 106 command = 'scons mode=%s std=%s simulator=%s all --clean' % \ 107 (mode, std, args.simulator) 108 status, output = util.getstatusoutput(command) 109 if status != 0: 110 print(output) 111 util.abort('Failed cleaning test: ' + command) 112 113 clean(compiler, 'debug', 'c++98') 114 clean(compiler, 'debug', 'c++11') 115 clean(compiler, 'release', 'c++98') 116 clean(compiler, 'release', 'c++11') 117 118 119def BuildEverything(compiler): 120 def build(compiler, mode, std): 121 check_supported(compiler, mode, std) 122 os.environ['CXX'] = compiler 123 if args.verbose: 124 print 'Building ' + compiler + ' ' + std + ' ' \ 125 + mode + ' mode test...' 126 if args.jobs == 1: 127 print '- This may take a while. Pass `-j` to use multiple threads.' 128 command = 'scons mode=%s std=%s simulator=%s all -j%u' % \ 129 (mode, std, args.simulator, args.jobs) 130 status, output = util.getstatusoutput(command) 131 if status != 0: 132 print(output) 133 util.abort('Failed building test: ' + command) 134 135 print 'Building ' + compiler + ' tests...' 136 build(compiler, 'debug', 'c++98') 137 build(compiler, 'debug', 'c++11') 138 build(compiler, 'release', 'c++98') 139 build(compiler, 'release', 'c++11') 140 141 142NOT_RUN = 'NOT RUN' 143PASSED = 'PASSED' 144FAILED = 'FAILED' 145 146class Test: 147 def __init__(self, name): 148 self.name = name 149 self.status = NOT_RUN 150 151 def name_prefix(self): 152 return '%-40s : ' % self.name 153 154 155class Tester: 156 def __init__(self): 157 self.tests = [] 158 159 def AddTest(self, test): 160 self.tests.append(test) 161 162 def RunAll(self): 163 result = PASSED 164 for test in self.tests: 165 if args.verbose: print('Running ' + test.name + '...') 166 test.Run() 167 if test.status != PASSED: result = FAILED 168 print('Presubmit tests ' + result + '.') 169 170 171class VIXLTest(Test): 172 def __init__(self, compiler, mode, std, simulator, debugger = False, verbose = False): 173 check_supported(compiler, mode, std) 174 self.verbose = verbose 175 self.debugger = debugger 176 self.compiler = compiler 177 self.mode = mode 178 self.std = std 179 180 name = 'test ' + compiler + ' ' + std + ' ' + mode 181 if simulator: 182 name += ' (%s)' % ('debugger' if debugger else 'simulator') 183 Test.__init__(self, name) 184 185 self.exe = 'test-runner' 186 if simulator: 187 self.exe += '_sim' 188 if mode == 'debug': 189 self.exe += '_g' 190 191 def Run(self): 192 self.status = PASSED 193 command = os.path.join(OBJ_DIR, self.mode, self.compiler, 194 self.std, self.exe) 195 manifest = test.ReadManifest(command, [], self.debugger, False, self.verbose) 196 retcode = test.RunTests(manifest, jobs = args.jobs, 197 verbose = self.verbose, debugger = self.debugger, 198 progress_prefix = self.name_prefix()) 199 printer.EnsureNewLine() 200 if retcode != 0: 201 self.status = FAILED 202 203 204class LintTest(Test): 205 def __init__(self): 206 name = 'cpp lint' 207 Test.__init__(self, name) 208 209 def Run(self): 210 if not lint.IsCppLintAvailable(): 211 self.status = FAILED 212 print self.name_prefix() + FAILED + ''' 213cpplint.py not found. Please ensure the depot tools are installed and in your 214PATH. See http://dev.chromium.org/developers/how-tos/install-depot-tools for 215details.''' 216 return 217 218 n_errors = lint.LintFiles(lint.default_tracked_files, 219 jobs = args.jobs, verbose = args.verbose, 220 progress_prefix = self.name_prefix()) 221 self.status = PASSED if n_errors == 0 else FAILED 222 223 224class BenchTest(Test): 225 def __init__(self, compiler, mode, std, simulator): 226 check_supported(compiler, mode, std) 227 self.compiler = compiler 228 self.mode = mode 229 self.std = std 230 231 name = 'benchmarks ' + compiler + ' ' + std + ' ' + mode 232 Test.__init__(self, name) 233 self.exe_suffix = '' 234 if simulator: 235 self.exe_suffix += '_sim' 236 if mode == 'debug': 237 self.exe_suffix += '_g' 238 239 def Run(self): 240 benchmarks = ['bench-dataop', 'bench-branch', 'bench-branch-link', 241 'bench-branch-masm', 'bench-branch-link-masm'] 242 self.status = PASSED 243 for bench in benchmarks: 244 command = os.path.join(OBJ_DIR, self.mode, self.compiler, self.std, 245 bench + self.exe_suffix) 246 (rc, out) = util.getstatusoutput(command) 247 if rc != 0: 248 self.status = FAILED 249 print self.name_prefix() + 'Failed to run `' + command + '`' 250 print self.name_prefix() + self.status 251 252 253 254if __name__ == '__main__': 255 original_dir = os.path.abspath('.') 256 # $ROOT/tools/presubmit.py 257 root_dir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) 258 os.chdir(root_dir) 259 args = BuildOptions() 260 261 if not args.nolint and not git.is_git_repository_root(): 262 print 'WARNING: This is not a Git repository. The linter will not run.' 263 args.nolint = True 264 265 if not args.nolint: 266 import lint 267 LintTest().Run() 268 269 if not args.notest: 270 tester = Tester() 271 compiler_list = initalize_compiler_list() 272 273 for compiler in compiler_list: 274 if not args.noclean: 275 CleanBuildSystem(compiler) 276 BuildEverything(compiler) 277 278 if args.simulator == 'on': 279 # mode, std, sim, debugger, verbose 280 tester.AddTest(VIXLTest(compiler, 'release', 'c++98', True, True, args.verbose)) 281 tester.AddTest(VIXLTest(compiler, 'debug', 'c++98', True, True, args.verbose)) 282 tester.AddTest(VIXLTest(compiler, 'release', 'c++98', True, False, args.verbose)) 283 tester.AddTest(VIXLTest(compiler, 'debug', 'c++98', True, False, args.verbose)) 284 tester.AddTest(VIXLTest(compiler, 'release', 'c++11', True, True, args.verbose)) 285 tester.AddTest(VIXLTest(compiler, 'debug', 'c++11', True, True, args.verbose)) 286 tester.AddTest(VIXLTest(compiler, 'release', 'c++11', True, False, args.verbose)) 287 tester.AddTest(VIXLTest(compiler, 'debug', 'c++11', True, False, args.verbose)) 288 tester.AddTest(BenchTest(compiler,'release', 'c++98', True)) 289 tester.AddTest(BenchTest(compiler,'debug', 'c++98', True)) 290 tester.AddTest(BenchTest(compiler,'release', 'c++11', True)) 291 tester.AddTest(BenchTest(compiler,'debug', 'c++11', True)) 292 else: 293 tester.AddTest(VIXLTest(compiler, 'release', 'c++98', False, False, args.verbose)) 294 tester.AddTest(VIXLTest(compiler, 'debug', 'c++98', False, False, args.verbose)) 295 tester.AddTest(VIXLTest(compiler, 'release', 'c++11', False, False, args.verbose)) 296 tester.AddTest(VIXLTest(compiler, 'debug', 'c++11', False, False, args.verbose)) 297 tester.AddTest(BenchTest(compiler,'release', 'c++98', False)) 298 tester.AddTest(BenchTest(compiler,'debug', 'c++98', False)) 299 tester.AddTest(BenchTest(compiler,'release', 'c++11', False)) 300 tester.AddTest(BenchTest(compiler,'debug', 'c++11', False)) 301 302 tester.RunAll() 303 304 if git.is_git_repository_root(): 305 untracked_files = git.get_untracked_files() 306 if untracked_files: 307 print '\nWARNING: The following files are untracked:' 308 for f in untracked_files: 309 print f.lstrip('?') 310