xref: /aosp_15_r20/external/vixl/tools/test.py (revision f5c631da2f1efdd72b5fd1e20510e4042af13d77)
1*f5c631daSSadaf Ebrahimi#!/usr/bin/env python2.7
2*f5c631daSSadaf Ebrahimi
3*f5c631daSSadaf Ebrahimi# Copyright 2015, VIXL authors
4*f5c631daSSadaf Ebrahimi# All rights reserved.
5*f5c631daSSadaf Ebrahimi#
6*f5c631daSSadaf Ebrahimi# Redistribution and use in source and binary forms, with or without
7*f5c631daSSadaf Ebrahimi# modification, are permitted provided that the following conditions are met:
8*f5c631daSSadaf Ebrahimi#
9*f5c631daSSadaf Ebrahimi#   * Redistributions of source code must retain the above copyright notice,
10*f5c631daSSadaf Ebrahimi#     this list of conditions and the following disclaimer.
11*f5c631daSSadaf Ebrahimi#   * Redistributions in binary form must reproduce the above copyright notice,
12*f5c631daSSadaf Ebrahimi#     this list of conditions and the following disclaimer in the documentation
13*f5c631daSSadaf Ebrahimi#     and/or other materials provided with the distribution.
14*f5c631daSSadaf Ebrahimi#   * Neither the name of ARM Limited nor the names of its contributors may be
15*f5c631daSSadaf Ebrahimi#     used to endorse or promote products derived from this software without
16*f5c631daSSadaf Ebrahimi#     specific prior written permission.
17*f5c631daSSadaf Ebrahimi#
18*f5c631daSSadaf Ebrahimi# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
19*f5c631daSSadaf Ebrahimi# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20*f5c631daSSadaf Ebrahimi# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21*f5c631daSSadaf Ebrahimi# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22*f5c631daSSadaf Ebrahimi# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*f5c631daSSadaf Ebrahimi# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24*f5c631daSSadaf Ebrahimi# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25*f5c631daSSadaf Ebrahimi# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26*f5c631daSSadaf Ebrahimi# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*f5c631daSSadaf Ebrahimi# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*f5c631daSSadaf Ebrahimi
29*f5c631daSSadaf Ebrahimiimport argparse
30*f5c631daSSadaf Ebrahimiimport fcntl
31*f5c631daSSadaf Ebrahimiimport git
32*f5c631daSSadaf Ebrahimiimport itertools
33*f5c631daSSadaf Ebrahimiimport multiprocessing
34*f5c631daSSadaf Ebrahimiimport os
35*f5c631daSSadaf Ebrahimifrom os.path import join
36*f5c631daSSadaf Ebrahimiimport platform
37*f5c631daSSadaf Ebrahimiimport subprocess
38*f5c631daSSadaf Ebrahimiimport sys
39*f5c631daSSadaf Ebrahimiimport time
40*f5c631daSSadaf Ebrahimi
41*f5c631daSSadaf Ebrahimiimport config
42*f5c631daSSadaf Ebrahimiimport clang_format
43*f5c631daSSadaf Ebrahimiimport clang_tidy
44*f5c631daSSadaf Ebrahimiimport lint
45*f5c631daSSadaf Ebrahimiimport printer
46*f5c631daSSadaf Ebrahimiimport test
47*f5c631daSSadaf Ebrahimiimport test_runner
48*f5c631daSSadaf Ebrahimiimport util
49*f5c631daSSadaf Ebrahimi
50*f5c631daSSadaf Ebrahimi
51*f5c631daSSadaf Ebrahimidir_root = config.dir_root
52*f5c631daSSadaf Ebrahimi
53*f5c631daSSadaf Ebrahimi
54*f5c631daSSadaf Ebrahimi# Remove duplicates from a list
55*f5c631daSSadaf Ebrahimidef RemoveDuplicates(values):
56*f5c631daSSadaf Ebrahimi  # Convert the list into a set and back to list
57*f5c631daSSadaf Ebrahimi  # as sets guarantee items are unique.
58*f5c631daSSadaf Ebrahimi  return list(set(values))
59*f5c631daSSadaf Ebrahimi
60*f5c631daSSadaf Ebrahimi
61*f5c631daSSadaf Ebrahimi# Custom argparse.Action to automatically add and handle an 'all' option.
62*f5c631daSSadaf Ebrahimi# If no 'default' value is set, it will default to 'all.
63*f5c631daSSadaf Ebrahimi# If accepted options are set using 'choices' then only these values will be
64*f5c631daSSadaf Ebrahimi# allowed.
65*f5c631daSSadaf Ebrahimi# If they're set using 'soft_choices' then 'all' will default to these values,
66*f5c631daSSadaf Ebrahimi# but other values will also be accepted.
67*f5c631daSSadaf Ebrahimiclass AllChoiceAction(argparse.Action):
68*f5c631daSSadaf Ebrahimi
69*f5c631daSSadaf Ebrahimi  # At least one option was set by the user.
70*f5c631daSSadaf Ebrahimi  WasSetByUser = False
71*f5c631daSSadaf Ebrahimi
72*f5c631daSSadaf Ebrahimi  def __init__(self, **kwargs):
73*f5c631daSSadaf Ebrahimi    if 'choices' in kwargs:
74*f5c631daSSadaf Ebrahimi      assert 'soft_choices' not in kwargs,\
75*f5c631daSSadaf Ebrahimi          "Can't have both 'choices' and 'soft_choices' options"
76*f5c631daSSadaf Ebrahimi      self.all_choices = list(kwargs['choices'])
77*f5c631daSSadaf Ebrahimi      kwargs['choices'].append('all')
78*f5c631daSSadaf Ebrahimi    else:
79*f5c631daSSadaf Ebrahimi      self.all_choices = kwargs['soft_choices']
80*f5c631daSSadaf Ebrahimi      kwargs['help'] += ' Supported values: {' + ','.join(
81*f5c631daSSadaf Ebrahimi          ['all'] + self.all_choices) + '}'
82*f5c631daSSadaf Ebrahimi      del kwargs['soft_choices']
83*f5c631daSSadaf Ebrahimi    if 'default' not in kwargs:
84*f5c631daSSadaf Ebrahimi      kwargs['default'] = self.all_choices
85*f5c631daSSadaf Ebrahimi    super(AllChoiceAction, self).__init__(**kwargs)
86*f5c631daSSadaf Ebrahimi
87*f5c631daSSadaf Ebrahimi  def __call__(self, parser, namespace, values, option_string=None):
88*f5c631daSSadaf Ebrahimi    AllChoiceAction.WasSetByUser = True
89*f5c631daSSadaf Ebrahimi    if 'all' in values:
90*f5c631daSSadaf Ebrahimi      # Substitute 'all' by the actual values.
91*f5c631daSSadaf Ebrahimi      values = self.all_choices + [value for value in values if value != 'all']
92*f5c631daSSadaf Ebrahimi
93*f5c631daSSadaf Ebrahimi    setattr(namespace, self.dest, RemoveDuplicates(values))
94*f5c631daSSadaf Ebrahimi
95*f5c631daSSadaf Ebrahimi
96*f5c631daSSadaf Ebrahimidef BuildOptions():
97*f5c631daSSadaf Ebrahimi  args = argparse.ArgumentParser(
98*f5c631daSSadaf Ebrahimi    description =
99*f5c631daSSadaf Ebrahimi    '''This tool runs all tests matching the specified filters for multiple
100*f5c631daSSadaf Ebrahimi    environment, build options, and runtime options configurations.''',
101*f5c631daSSadaf Ebrahimi    # Print default values.
102*f5c631daSSadaf Ebrahimi    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
103*f5c631daSSadaf Ebrahimi
104*f5c631daSSadaf Ebrahimi  args.add_argument('filters', metavar='filter', nargs='*',
105*f5c631daSSadaf Ebrahimi                    help='Run tests matching all of the (regexp) filters.')
106*f5c631daSSadaf Ebrahimi
107*f5c631daSSadaf Ebrahimi  # We automatically build the script options from the options to be tested.
108*f5c631daSSadaf Ebrahimi  test_arguments = args.add_argument_group(
109*f5c631daSSadaf Ebrahimi    'Test options',
110*f5c631daSSadaf Ebrahimi    'These options indicate what should be tested')
111*f5c631daSSadaf Ebrahimi  test_arguments.add_argument(
112*f5c631daSSadaf Ebrahimi      '--negative_testing',
113*f5c631daSSadaf Ebrahimi      help='Tests with negative testing enabled.',
114*f5c631daSSadaf Ebrahimi      action='store_const',
115*f5c631daSSadaf Ebrahimi      const='on',
116*f5c631daSSadaf Ebrahimi      default='off')
117*f5c631daSSadaf Ebrahimi  test_arguments.add_argument(
118*f5c631daSSadaf Ebrahimi      '--compiler',
119*f5c631daSSadaf Ebrahimi      help='Test for the specified compilers.',
120*f5c631daSSadaf Ebrahimi      soft_choices=config.tested_compilers,
121*f5c631daSSadaf Ebrahimi      action=AllChoiceAction,
122*f5c631daSSadaf Ebrahimi      nargs="+")
123*f5c631daSSadaf Ebrahimi  test_arguments.add_argument(
124*f5c631daSSadaf Ebrahimi      '--mode',
125*f5c631daSSadaf Ebrahimi      help='Test with the specified build modes.',
126*f5c631daSSadaf Ebrahimi      choices=config.build_options_modes,
127*f5c631daSSadaf Ebrahimi      action=AllChoiceAction,
128*f5c631daSSadaf Ebrahimi      nargs="+")
129*f5c631daSSadaf Ebrahimi  test_arguments.add_argument(
130*f5c631daSSadaf Ebrahimi      '--std',
131*f5c631daSSadaf Ebrahimi      help='Test with the specified C++ standard.',
132*f5c631daSSadaf Ebrahimi      soft_choices=config.tested_cpp_standards,
133*f5c631daSSadaf Ebrahimi      action=AllChoiceAction,
134*f5c631daSSadaf Ebrahimi      nargs="+")
135*f5c631daSSadaf Ebrahimi  test_arguments.add_argument(
136*f5c631daSSadaf Ebrahimi      '--target',
137*f5c631daSSadaf Ebrahimi      help='Test with the specified isa enabled.',
138*f5c631daSSadaf Ebrahimi      soft_choices=config.build_options_target,
139*f5c631daSSadaf Ebrahimi      action=AllChoiceAction,
140*f5c631daSSadaf Ebrahimi      nargs="+")
141*f5c631daSSadaf Ebrahimi
142*f5c631daSSadaf Ebrahimi  general_arguments = args.add_argument_group('General options')
143*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--dry-run', action='store_true',
144*f5c631daSSadaf Ebrahimi                                 help='''Don't actually build or run anything,
145*f5c631daSSadaf Ebrahimi                                 but print the configurations that would be
146*f5c631daSSadaf Ebrahimi                                 tested.''')
147*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--verbose', action='store_true',
148*f5c631daSSadaf Ebrahimi                                 help='''Print extra information.''')
149*f5c631daSSadaf Ebrahimi  general_arguments.add_argument(
150*f5c631daSSadaf Ebrahimi    '--jobs', '-j', metavar='N', type=int, nargs='?',
151*f5c631daSSadaf Ebrahimi    default=multiprocessing.cpu_count(),
152*f5c631daSSadaf Ebrahimi    const=multiprocessing.cpu_count(),
153*f5c631daSSadaf Ebrahimi    help='''Runs the tests using N jobs. If the option is set but no value is
154*f5c631daSSadaf Ebrahimi    provided, the script will use as many jobs as it thinks useful.''')
155*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--clang-format',
156*f5c631daSSadaf Ebrahimi                                 default=clang_format.DEFAULT_CLANG_FORMAT,
157*f5c631daSSadaf Ebrahimi                                 help='Path to clang-format.')
158*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--clang-tidy',
159*f5c631daSSadaf Ebrahimi                                 default=clang_tidy.DEFAULT_CLANG_TIDY,
160*f5c631daSSadaf Ebrahimi                                 help='Path to clang-tidy.')
161*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--nobench', action='store_true',
162*f5c631daSSadaf Ebrahimi                                 help='Do not run benchmarks.')
163*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--nolint', action='store_true',
164*f5c631daSSadaf Ebrahimi                                 help='Do not run the linter.')
165*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--noclang-format', action='store_true',
166*f5c631daSSadaf Ebrahimi                                 help='Do not run clang-format.')
167*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--noclang-tidy', action='store_true',
168*f5c631daSSadaf Ebrahimi                                 help='Do not run clang-tidy.')
169*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--notest', action='store_true',
170*f5c631daSSadaf Ebrahimi                                 help='Do not run tests.')
171*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--nocheck-code-coverage', action='store_true',
172*f5c631daSSadaf Ebrahimi                                 help='Do not check code coverage results log.')
173*f5c631daSSadaf Ebrahimi  general_arguments.add_argument('--fail-early', action='store_true',
174*f5c631daSSadaf Ebrahimi                                 help='Exit as soon as a test fails.')
175*f5c631daSSadaf Ebrahimi  general_arguments.add_argument(
176*f5c631daSSadaf Ebrahimi    '--under_valgrind', action='store_true',
177*f5c631daSSadaf Ebrahimi    help='''Run the test-runner commands under Valgrind.
178*f5c631daSSadaf Ebrahimi            Note that a few tests are known to fail because of
179*f5c631daSSadaf Ebrahimi            issues in Valgrind''')
180*f5c631daSSadaf Ebrahimi  return args.parse_args()
181*f5c631daSSadaf Ebrahimi
182*f5c631daSSadaf Ebrahimi
183*f5c631daSSadaf Ebrahimidef RunCommand(command, environment_options = None):
184*f5c631daSSadaf Ebrahimi  # Create a copy of the environment. We do not want to pollute the environment
185*f5c631daSSadaf Ebrahimi  # of future commands run.
186*f5c631daSSadaf Ebrahimi  environment = os.environ.copy()
187*f5c631daSSadaf Ebrahimi
188*f5c631daSSadaf Ebrahimi  printable_command = ''
189*f5c631daSSadaf Ebrahimi  if environment_options:
190*f5c631daSSadaf Ebrahimi    # Add the environment options to the environment:
191*f5c631daSSadaf Ebrahimi    environment.update(environment_options)
192*f5c631daSSadaf Ebrahimi    printable_command += ' ' + DictToString(environment_options) + ' '
193*f5c631daSSadaf Ebrahimi  printable_command += ' '.join(command)
194*f5c631daSSadaf Ebrahimi
195*f5c631daSSadaf Ebrahimi  printable_command_orange = \
196*f5c631daSSadaf Ebrahimi    printer.COLOUR_ORANGE + printable_command + printer.NO_COLOUR
197*f5c631daSSadaf Ebrahimi  printer.PrintOverwritableLine(printable_command_orange)
198*f5c631daSSadaf Ebrahimi  sys.stdout.flush()
199*f5c631daSSadaf Ebrahimi
200*f5c631daSSadaf Ebrahimi  # Start a process for the command.
201*f5c631daSSadaf Ebrahimi  # Interleave `stderr` and `stdout`.
202*f5c631daSSadaf Ebrahimi  p = subprocess.Popen(command,
203*f5c631daSSadaf Ebrahimi                       stdout=subprocess.PIPE,
204*f5c631daSSadaf Ebrahimi                       stderr=subprocess.STDOUT,
205*f5c631daSSadaf Ebrahimi                       env=environment)
206*f5c631daSSadaf Ebrahimi
207*f5c631daSSadaf Ebrahimi  # We want to be able to display a continuously updated 'work indicator' while
208*f5c631daSSadaf Ebrahimi  # the process is running. Since the process can hang if the `stdout` pipe is
209*f5c631daSSadaf Ebrahimi  # full, we need to pull from it regularly. We cannot do so via the
210*f5c631daSSadaf Ebrahimi  # `readline()` function because it is blocking, and would thus cause the
211*f5c631daSSadaf Ebrahimi  # indicator to not be updated properly. So use file control mechanisms
212*f5c631daSSadaf Ebrahimi  # instead.
213*f5c631daSSadaf Ebrahimi  indicator = ' (still working: %d seconds elapsed)'
214*f5c631daSSadaf Ebrahimi
215*f5c631daSSadaf Ebrahimi  # Mark the process output as non-blocking.
216*f5c631daSSadaf Ebrahimi  flags = fcntl.fcntl(p.stdout, fcntl.F_GETFL)
217*f5c631daSSadaf Ebrahimi  fcntl.fcntl(p.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
218*f5c631daSSadaf Ebrahimi
219*f5c631daSSadaf Ebrahimi  t_start = time.time()
220*f5c631daSSadaf Ebrahimi  t_current = t_start
221*f5c631daSSadaf Ebrahimi  t_last_indication = t_start
222*f5c631daSSadaf Ebrahimi  t_current = t_start
223*f5c631daSSadaf Ebrahimi  process_output = ''
224*f5c631daSSadaf Ebrahimi
225*f5c631daSSadaf Ebrahimi  # Keep looping as long as the process is running.
226*f5c631daSSadaf Ebrahimi  while p.poll() is None:
227*f5c631daSSadaf Ebrahimi    # Avoid polling too often.
228*f5c631daSSadaf Ebrahimi    time.sleep(0.1)
229*f5c631daSSadaf Ebrahimi    # Update the progress indicator.
230*f5c631daSSadaf Ebrahimi    t_current = time.time()
231*f5c631daSSadaf Ebrahimi    if (t_current - t_start >= 2) and (t_current - t_last_indication >= 1):
232*f5c631daSSadaf Ebrahimi      printer.PrintOverwritableLine(
233*f5c631daSSadaf Ebrahimi        printable_command_orange + indicator % int(t_current - t_start))
234*f5c631daSSadaf Ebrahimi      sys.stdout.flush()
235*f5c631daSSadaf Ebrahimi      t_last_indication = t_current
236*f5c631daSSadaf Ebrahimi    # Pull from the process output.
237*f5c631daSSadaf Ebrahimi    while True:
238*f5c631daSSadaf Ebrahimi      try:
239*f5c631daSSadaf Ebrahimi        line = os.read(p.stdout.fileno(), 1024)
240*f5c631daSSadaf Ebrahimi      except OSError:
241*f5c631daSSadaf Ebrahimi        line = ''
242*f5c631daSSadaf Ebrahimi        break
243*f5c631daSSadaf Ebrahimi      if line == '': break
244*f5c631daSSadaf Ebrahimi      process_output += line
245*f5c631daSSadaf Ebrahimi
246*f5c631daSSadaf Ebrahimi  # The process has exited. Don't forget to retrieve the rest of its output.
247*f5c631daSSadaf Ebrahimi  out, err = p.communicate()
248*f5c631daSSadaf Ebrahimi  rc = p.poll()
249*f5c631daSSadaf Ebrahimi  process_output += out
250*f5c631daSSadaf Ebrahimi
251*f5c631daSSadaf Ebrahimi  printable_command += ' (took %d seconds)' % int(t_current - t_start)
252*f5c631daSSadaf Ebrahimi  if rc == 0:
253*f5c631daSSadaf Ebrahimi    printer.Print(printer.COLOUR_GREEN + printable_command + printer.NO_COLOUR)
254*f5c631daSSadaf Ebrahimi  else:
255*f5c631daSSadaf Ebrahimi    printer.Print(printer.COLOUR_RED + printable_command + printer.NO_COLOUR)
256*f5c631daSSadaf Ebrahimi    printer.Print(process_output)
257*f5c631daSSadaf Ebrahimi  return rc
258*f5c631daSSadaf Ebrahimi
259*f5c631daSSadaf Ebrahimi
260*f5c631daSSadaf Ebrahimidef RunLinter(jobs):
261*f5c631daSSadaf Ebrahimi  return lint.RunLinter(map(lambda x: join(dir_root, x),
262*f5c631daSSadaf Ebrahimi                        util.get_source_files()),
263*f5c631daSSadaf Ebrahimi                        jobs = args.jobs, progress_prefix = 'cpp lint: ')
264*f5c631daSSadaf Ebrahimi
265*f5c631daSSadaf Ebrahimi
266*f5c631daSSadaf Ebrahimidef RunClangFormat(clang_path, jobs):
267*f5c631daSSadaf Ebrahimi  return clang_format.ClangFormatFiles(util.get_source_files(),
268*f5c631daSSadaf Ebrahimi                                       clang_path,
269*f5c631daSSadaf Ebrahimi                                       jobs = jobs,
270*f5c631daSSadaf Ebrahimi                                       progress_prefix = 'clang-format: ')
271*f5c631daSSadaf Ebrahimi
272*f5c631daSSadaf Ebrahimidef RunClangTidy(clang_path, jobs):
273*f5c631daSSadaf Ebrahimi  return clang_tidy.ClangTidyFiles(util.get_source_files(),
274*f5c631daSSadaf Ebrahimi                                   clang_path,
275*f5c631daSSadaf Ebrahimi                                   jobs = jobs,
276*f5c631daSSadaf Ebrahimi                                   progress_prefix = 'clang-tidy: ')
277*f5c631daSSadaf Ebrahimi
278*f5c631daSSadaf Ebrahimidef CheckCodeCoverage():
279*f5c631daSSadaf Ebrahimi  command = ['tools/check_recent_coverage.sh']
280*f5c631daSSadaf Ebrahimi  return RunCommand(command)
281*f5c631daSSadaf Ebrahimi
282*f5c631daSSadaf Ebrahimidef BuildAll(build_options, jobs, environment_options):
283*f5c631daSSadaf Ebrahimi  scons_command = ['scons', '-C', dir_root, 'all', '-j', str(jobs)]
284*f5c631daSSadaf Ebrahimi  if util.IsCommandAvailable('ccache'):
285*f5c631daSSadaf Ebrahimi    scons_command += ['compiler_wrapper=ccache']
286*f5c631daSSadaf Ebrahimi    # Fixes warnings for ccache 3.3.1 and lower:
287*f5c631daSSadaf Ebrahimi    environment_options = environment_options.copy()
288*f5c631daSSadaf Ebrahimi    environment_options["CCACHE_CPP2"] = 'yes'
289*f5c631daSSadaf Ebrahimi  scons_command += DictToString(build_options).split()
290*f5c631daSSadaf Ebrahimi  return RunCommand(scons_command, environment_options)
291*f5c631daSSadaf Ebrahimi
292*f5c631daSSadaf Ebrahimi
293*f5c631daSSadaf Ebrahimidef CanRunAarch64(options, args):
294*f5c631daSSadaf Ebrahimi  for target in options['target']:
295*f5c631daSSadaf Ebrahimi    if target in ['aarch64', 'a64']:
296*f5c631daSSadaf Ebrahimi      return True
297*f5c631daSSadaf Ebrahimi
298*f5c631daSSadaf Ebrahimi  return False
299*f5c631daSSadaf Ebrahimi
300*f5c631daSSadaf Ebrahimi
301*f5c631daSSadaf Ebrahimidef CanRunAarch32(options, args):
302*f5c631daSSadaf Ebrahimi  for target in options['target']:
303*f5c631daSSadaf Ebrahimi    if target in ['aarch32', 'a32', 't32']:
304*f5c631daSSadaf Ebrahimi      return True
305*f5c631daSSadaf Ebrahimi  return False
306*f5c631daSSadaf Ebrahimi
307*f5c631daSSadaf Ebrahimi
308*f5c631daSSadaf Ebrahimidef RunBenchmarks(options, args):
309*f5c631daSSadaf Ebrahimi  rc = 0
310*f5c631daSSadaf Ebrahimi  if CanRunAarch32(options, args):
311*f5c631daSSadaf Ebrahimi    benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch32_benchmarks)
312*f5c631daSSadaf Ebrahimi    for bench in benchmark_names:
313*f5c631daSSadaf Ebrahimi      rc |= RunCommand(
314*f5c631daSSadaf Ebrahimi        [os.path.realpath(
315*f5c631daSSadaf Ebrahimi          join(config.dir_build_latest, 'benchmarks/aarch32', bench)), '10'])
316*f5c631daSSadaf Ebrahimi  if CanRunAarch64(options, args):
317*f5c631daSSadaf Ebrahimi    benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch64_benchmarks)
318*f5c631daSSadaf Ebrahimi    for bench in benchmark_names:
319*f5c631daSSadaf Ebrahimi      rc |= RunCommand(
320*f5c631daSSadaf Ebrahimi        [util.relrealpath(
321*f5c631daSSadaf Ebrahimi            join(config.dir_build_latest,
322*f5c631daSSadaf Ebrahimi                'benchmarks/aarch64', bench)), '10'])
323*f5c631daSSadaf Ebrahimi  return rc
324*f5c631daSSadaf Ebrahimi
325*f5c631daSSadaf Ebrahimi
326*f5c631daSSadaf Ebrahimi
327*f5c631daSSadaf Ebrahimi# It is a precommit run if the user did not specify any of the
328*f5c631daSSadaf Ebrahimi# options that would affect the automatically generated combinations.
329*f5c631daSSadaf Ebrahimidef IsPrecommitRun(args):
330*f5c631daSSadaf Ebrahimi  return args.negative_testing == "off" and not AllChoiceAction.WasSetByUser
331*f5c631daSSadaf Ebrahimi
332*f5c631daSSadaf Ebrahimi# Generate a list of all the possible combinations of the passed list:
333*f5c631daSSadaf Ebrahimi# ListCombinations( a = [a0, a1], b = [b0, b1] ) will return
334*f5c631daSSadaf Ebrahimi# [ {a : a0, b : b0}, {a : a0, b : b1}, {a: a1, b : b0}, {a : a1, b : b1}]
335*f5c631daSSadaf Ebrahimidef ListCombinations(**kwargs):
336*f5c631daSSadaf Ebrahimi  # End of recursion: no options passed
337*f5c631daSSadaf Ebrahimi  if not kwargs:
338*f5c631daSSadaf Ebrahimi    return [{}]
339*f5c631daSSadaf Ebrahimi  option, values = kwargs.popitem()
340*f5c631daSSadaf Ebrahimi  configs = ListCombinations(**kwargs)
341*f5c631daSSadaf Ebrahimi  retval = []
342*f5c631daSSadaf Ebrahimi  if not isinstance(values, list):
343*f5c631daSSadaf Ebrahimi    values = [values]
344*f5c631daSSadaf Ebrahimi  for value in values:
345*f5c631daSSadaf Ebrahimi    for config in configs:
346*f5c631daSSadaf Ebrahimi      new_config = config.copy()
347*f5c631daSSadaf Ebrahimi      new_config[option] = value
348*f5c631daSSadaf Ebrahimi      retval.append(new_config)
349*f5c631daSSadaf Ebrahimi  return retval
350*f5c631daSSadaf Ebrahimi
351*f5c631daSSadaf Ebrahimi# Convert a dictionary into a space separated string
352*f5c631daSSadaf Ebrahimi# {a : a0, b : b0} --> "a=a0 b=b0"
353*f5c631daSSadaf Ebrahimidef DictToString(options):
354*f5c631daSSadaf Ebrahimi  return " ".join(
355*f5c631daSSadaf Ebrahimi      ["{}={}".format(option, value) for option, value in options.items()])
356*f5c631daSSadaf Ebrahimi
357*f5c631daSSadaf Ebrahimi
358*f5c631daSSadaf Ebrahimiif __name__ == '__main__':
359*f5c631daSSadaf Ebrahimi  util.require_program('scons')
360*f5c631daSSadaf Ebrahimi
361*f5c631daSSadaf Ebrahimi  args = BuildOptions()
362*f5c631daSSadaf Ebrahimi
363*f5c631daSSadaf Ebrahimi  rc = util.ReturnCode(args.fail_early, printer.Print)
364*f5c631daSSadaf Ebrahimi
365*f5c631daSSadaf Ebrahimi  if args.under_valgrind:
366*f5c631daSSadaf Ebrahimi    util.require_program('valgrind')
367*f5c631daSSadaf Ebrahimi
368*f5c631daSSadaf Ebrahimi  if not args.nocheck_code_coverage:
369*f5c631daSSadaf Ebrahimi    rc.Combine(CheckCodeCoverage())
370*f5c631daSSadaf Ebrahimi
371*f5c631daSSadaf Ebrahimi  tests = test_runner.TestQueue()
372*f5c631daSSadaf Ebrahimi  if not args.nolint and not args.dry_run:
373*f5c631daSSadaf Ebrahimi    rc.Combine(RunLinter(args.jobs))
374*f5c631daSSadaf Ebrahimi
375*f5c631daSSadaf Ebrahimi  if not args.noclang_format and not args.dry_run:
376*f5c631daSSadaf Ebrahimi    rc.Combine(RunClangFormat(args.clang_format, args.jobs))
377*f5c631daSSadaf Ebrahimi
378*f5c631daSSadaf Ebrahimi  if not args.noclang_tidy and not args.dry_run:
379*f5c631daSSadaf Ebrahimi    rc.Combine(RunClangTidy(args.clang_tidy, args.jobs))
380*f5c631daSSadaf Ebrahimi
381*f5c631daSSadaf Ebrahimi  list_options = []
382*f5c631daSSadaf Ebrahimi  if IsPrecommitRun(args):
383*f5c631daSSadaf Ebrahimi    # Maximize the coverage for precommit testing.
384*f5c631daSSadaf Ebrahimi
385*f5c631daSSadaf Ebrahimi    # Debug builds with negative testing and all targets enabled.
386*f5c631daSSadaf Ebrahimi    list_options += ListCombinations(
387*f5c631daSSadaf Ebrahimi        compiler = args.compiler,
388*f5c631daSSadaf Ebrahimi        negative_testing = 'on',
389*f5c631daSSadaf Ebrahimi        std = args.std,
390*f5c631daSSadaf Ebrahimi        mode = 'debug',
391*f5c631daSSadaf Ebrahimi        target = 'a64,a32,t32')
392*f5c631daSSadaf Ebrahimi
393*f5c631daSSadaf Ebrahimi    # Release builds with all targets enabled.
394*f5c631daSSadaf Ebrahimi    list_options += ListCombinations(
395*f5c631daSSadaf Ebrahimi        compiler = args.compiler,
396*f5c631daSSadaf Ebrahimi        negative_testing = 'off',
397*f5c631daSSadaf Ebrahimi        std = args.std,
398*f5c631daSSadaf Ebrahimi        mode = 'release',
399*f5c631daSSadaf Ebrahimi        target = 'a64,a32,t32')
400*f5c631daSSadaf Ebrahimi
401*f5c631daSSadaf Ebrahimi    # Debug builds for individual targets.
402*f5c631daSSadaf Ebrahimi    list_options += ListCombinations(
403*f5c631daSSadaf Ebrahimi        compiler = args.compiler[0],
404*f5c631daSSadaf Ebrahimi        negative_testing = 'off',
405*f5c631daSSadaf Ebrahimi        std = args.std,
406*f5c631daSSadaf Ebrahimi        mode = 'debug',
407*f5c631daSSadaf Ebrahimi        target = ['a32', 't32', 'a64'])
408*f5c631daSSadaf Ebrahimi  else:
409*f5c631daSSadaf Ebrahimi    list_options = ListCombinations(
410*f5c631daSSadaf Ebrahimi        compiler = args.compiler,
411*f5c631daSSadaf Ebrahimi        negative_testing = args.negative_testing,
412*f5c631daSSadaf Ebrahimi        std = args.std,
413*f5c631daSSadaf Ebrahimi        mode = args.mode,
414*f5c631daSSadaf Ebrahimi        target = args.target)
415*f5c631daSSadaf Ebrahimi
416*f5c631daSSadaf Ebrahimi  for options in list_options:
417*f5c631daSSadaf Ebrahimi    if (args.dry_run):
418*f5c631daSSadaf Ebrahimi      print(DictToString(options))
419*f5c631daSSadaf Ebrahimi      continue
420*f5c631daSSadaf Ebrahimi    # Convert 'compiler' into an environment variable:
421*f5c631daSSadaf Ebrahimi    environment_options = {'CXX': options['compiler']}
422*f5c631daSSadaf Ebrahimi    del options['compiler']
423*f5c631daSSadaf Ebrahimi
424*f5c631daSSadaf Ebrahimi    # Avoid going through the build stage if we are not using the build
425*f5c631daSSadaf Ebrahimi    # result.
426*f5c631daSSadaf Ebrahimi    if not (args.notest and args.nobench):
427*f5c631daSSadaf Ebrahimi      build_rc = BuildAll(options, args.jobs, environment_options)
428*f5c631daSSadaf Ebrahimi      # Don't run the tests for this configuration if the build failed.
429*f5c631daSSadaf Ebrahimi      if build_rc != 0:
430*f5c631daSSadaf Ebrahimi        rc.Combine(build_rc)
431*f5c631daSSadaf Ebrahimi        continue
432*f5c631daSSadaf Ebrahimi
433*f5c631daSSadaf Ebrahimi      # Use the realpath of the test executable so that the commands printed
434*f5c631daSSadaf Ebrahimi      # can be copy-pasted and run.
435*f5c631daSSadaf Ebrahimi      test_executable = util.relrealpath(
436*f5c631daSSadaf Ebrahimi        join(config.dir_build_latest, 'test', 'test-runner'))
437*f5c631daSSadaf Ebrahimi
438*f5c631daSSadaf Ebrahimi      if not args.notest:
439*f5c631daSSadaf Ebrahimi        printer.Print(test_executable)
440*f5c631daSSadaf Ebrahimi        tests.AddTests(
441*f5c631daSSadaf Ebrahimi            test_executable,
442*f5c631daSSadaf Ebrahimi            args.filters,
443*f5c631daSSadaf Ebrahimi            list(),
444*f5c631daSSadaf Ebrahimi            args.under_valgrind)
445*f5c631daSSadaf Ebrahimi
446*f5c631daSSadaf Ebrahimi      if not args.nobench:
447*f5c631daSSadaf Ebrahimi        rc.Combine(RunBenchmarks(options, args))
448*f5c631daSSadaf Ebrahimi
449*f5c631daSSadaf Ebrahimi  rc.Combine(tests.Run(args.jobs, args.verbose))
450*f5c631daSSadaf Ebrahimi  if not args.dry_run:
451*f5c631daSSadaf Ebrahimi    rc.PrintStatus()
452*f5c631daSSadaf Ebrahimi
453*f5c631daSSadaf Ebrahimi  sys.exit(rc.Value)
454