1b8021494Sopenharmony_ci# Copyright 2015, VIXL authors
2b8021494Sopenharmony_ci# All rights reserved.
3b8021494Sopenharmony_ci#
4b8021494Sopenharmony_ci# Redistribution and use in source and binary forms, with or without
5b8021494Sopenharmony_ci# modification, are permitted provided that the following conditions are met:
6b8021494Sopenharmony_ci#
7b8021494Sopenharmony_ci#   * Redistributions of source code must retain the above copyright notice,
8b8021494Sopenharmony_ci#     this list of conditions and the following disclaimer.
9b8021494Sopenharmony_ci#   * Redistributions in binary form must reproduce the above copyright notice,
10b8021494Sopenharmony_ci#     this list of conditions and the following disclaimer in the documentation
11b8021494Sopenharmony_ci#     and/or other materials provided with the distribution.
12b8021494Sopenharmony_ci#   * Neither the name of ARM Limited nor the names of its contributors may be
13b8021494Sopenharmony_ci#     used to endorse or promote products derived from this software without
14b8021494Sopenharmony_ci#     specific prior written permission.
15b8021494Sopenharmony_ci#
16b8021494Sopenharmony_ci# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17b8021494Sopenharmony_ci# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18b8021494Sopenharmony_ci# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19b8021494Sopenharmony_ci# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20b8021494Sopenharmony_ci# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21b8021494Sopenharmony_ci# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22b8021494Sopenharmony_ci# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23b8021494Sopenharmony_ci# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24b8021494Sopenharmony_ci# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25b8021494Sopenharmony_ci# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26b8021494Sopenharmony_ci
27b8021494Sopenharmony_ciimport glob
28b8021494Sopenharmony_ciimport itertools
29b8021494Sopenharmony_ciimport os
30b8021494Sopenharmony_cifrom os.path import join
31b8021494Sopenharmony_ciimport platform
32b8021494Sopenharmony_ciimport subprocess
33b8021494Sopenharmony_ciimport sys
34b8021494Sopenharmony_cifrom collections import OrderedDict
35b8021494Sopenharmony_ci
36b8021494Sopenharmony_ciroot_dir = os.path.dirname(File('SConstruct').rfile().abspath)
37b8021494Sopenharmony_cisys.path.insert(0, join(root_dir, 'tools'))
38b8021494Sopenharmony_ciimport config
39b8021494Sopenharmony_ciimport util
40b8021494Sopenharmony_ci
41b8021494Sopenharmony_cifrom SCons.Errors import UserError
42b8021494Sopenharmony_ci
43b8021494Sopenharmony_ci
44b8021494Sopenharmony_ciHelp('''
45b8021494Sopenharmony_ciBuild system for the VIXL project.
46b8021494Sopenharmony_ciSee README.md for documentation and details about the build system.
47b8021494Sopenharmony_ci''')
48b8021494Sopenharmony_ci
49b8021494Sopenharmony_ci
50b8021494Sopenharmony_ci# We track top-level targets to automatically generate help and alias them.
51b8021494Sopenharmony_ciclass VIXLTargets:
52b8021494Sopenharmony_ci  def __init__(self):
53b8021494Sopenharmony_ci    self.targets = []
54b8021494Sopenharmony_ci    self.help_messages = []
55b8021494Sopenharmony_ci  def Add(self, target, help_message):
56b8021494Sopenharmony_ci    self.targets.append(target)
57b8021494Sopenharmony_ci    self.help_messages.append(help_message)
58b8021494Sopenharmony_ci  def Help(self):
59b8021494Sopenharmony_ci    res = ""
60b8021494Sopenharmony_ci    for i in range(len(self.targets)):
61b8021494Sopenharmony_ci      res += '\t{0:<{1}}{2:<{3}}\n'.format(
62b8021494Sopenharmony_ci        'scons ' + self.targets[i],
63b8021494Sopenharmony_ci        len('scons ') + max(map(len, self.targets)),
64b8021494Sopenharmony_ci        ' : ' + self.help_messages[i],
65b8021494Sopenharmony_ci        len(' : ') + max(map(len, self.help_messages)))
66b8021494Sopenharmony_ci    return res
67b8021494Sopenharmony_ci
68b8021494Sopenharmony_citop_level_targets = VIXLTargets()
69b8021494Sopenharmony_ci
70b8021494Sopenharmony_ci
71b8021494Sopenharmony_ci
72b8021494Sopenharmony_ci# Build options ----------------------------------------------------------------
73b8021494Sopenharmony_ci
74b8021494Sopenharmony_ci# Store all the options in a dictionary.
75b8021494Sopenharmony_ci# The SConstruct will check the build variables and construct the build
76b8021494Sopenharmony_ci# environment as appropriate.
77b8021494Sopenharmony_cioptions = {
78b8021494Sopenharmony_ci    'all' : { # Unconditionally processed.
79b8021494Sopenharmony_ci      'CCFLAGS' : ['-Wall',
80b8021494Sopenharmony_ci                   '-Werror',
81b8021494Sopenharmony_ci                   '-fdiagnostics-show-option',
82b8021494Sopenharmony_ci                   '-Wextra',
83b8021494Sopenharmony_ci                   '-Wredundant-decls',
84b8021494Sopenharmony_ci                   '-pedantic',
85b8021494Sopenharmony_ci                   '-Wwrite-strings',
86b8021494Sopenharmony_ci                   '-Wunused',
87b8021494Sopenharmony_ci                   '-Wshadow',
88b8021494Sopenharmony_ci                   '-Wno-missing-noreturn'],
89b8021494Sopenharmony_ci      'CPPPATH' : [config.dir_src_vixl]
90b8021494Sopenharmony_ci      },
91b8021494Sopenharmony_ci#   'build_option:value' : {
92b8021494Sopenharmony_ci#     'environment_key' : 'values to append'
93b8021494Sopenharmony_ci#     },
94b8021494Sopenharmony_ci    'mode:debug' : {
95b8021494Sopenharmony_ci      'CCFLAGS' : ['-DVIXL_DEBUG', '-O0']
96b8021494Sopenharmony_ci      },
97b8021494Sopenharmony_ci    'mode:release' : {
98b8021494Sopenharmony_ci      'CCFLAGS' : ['-O3'],
99b8021494Sopenharmony_ci      },
100b8021494Sopenharmony_ci    'simulator:aarch64' : {
101b8021494Sopenharmony_ci      'CCFLAGS' : ['-DVIXL_INCLUDE_SIMULATOR_AARCH64'],
102b8021494Sopenharmony_ci      },
103b8021494Sopenharmony_ci    'symbols:on' : {
104b8021494Sopenharmony_ci      'CCFLAGS' : ['-g'],
105b8021494Sopenharmony_ci      'LINKFLAGS' : ['-g']
106b8021494Sopenharmony_ci      },
107b8021494Sopenharmony_ci    'negative_testing:on' : {
108b8021494Sopenharmony_ci      'CCFLAGS' : ['-DVIXL_NEGATIVE_TESTING']
109b8021494Sopenharmony_ci      },
110b8021494Sopenharmony_ci    'code_buffer_allocator:mmap' : {
111b8021494Sopenharmony_ci      'CCFLAGS' : ['-DVIXL_CODE_BUFFER_MMAP']
112b8021494Sopenharmony_ci      },
113b8021494Sopenharmony_ci    'code_buffer_allocator:malloc' : {
114b8021494Sopenharmony_ci      'CCFLAGS' : ['-DVIXL_CODE_BUFFER_MALLOC']
115b8021494Sopenharmony_ci      },
116b8021494Sopenharmony_ci    'ubsan:on' : {
117b8021494Sopenharmony_ci      'CCFLAGS': ['-fsanitize=undefined'],
118b8021494Sopenharmony_ci      'LINKFLAGS': ['-fsanitize=undefined']
119b8021494Sopenharmony_ci      },
120b8021494Sopenharmony_ci    'coverage:on' : {
121b8021494Sopenharmony_ci      'CCFLAGS': ['-fprofile-instr-generate', '-fcoverage-mapping'],
122b8021494Sopenharmony_ci      'LINKFLAGS': ['-fprofile-instr-generate', '-fcoverage-mapping']
123b8021494Sopenharmony_ci      }
124b8021494Sopenharmony_ci    }
125b8021494Sopenharmony_ci
126b8021494Sopenharmony_ci
127b8021494Sopenharmony_ci# A `DefaultVariable` has a default value that depends on elements not known
128b8021494Sopenharmony_ci# when variables are first evaluated.
129b8021494Sopenharmony_ci# Each `DefaultVariable` has a handler that will compute the default value for
130b8021494Sopenharmony_ci# the given environment.
131b8021494Sopenharmony_cidef modifiable_flags_handler(env):
132b8021494Sopenharmony_ci  env['modifiable_flags'] = \
133b8021494Sopenharmony_ci      'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
134b8021494Sopenharmony_ci
135b8021494Sopenharmony_ci
136b8021494Sopenharmony_cidef symbols_handler(env):
137b8021494Sopenharmony_ci  env['symbols'] = 'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
138b8021494Sopenharmony_ci
139b8021494Sopenharmony_cidef Is32BitHost(env):
140b8021494Sopenharmony_ci  return env['host_arch'] in ['aarch32', 'i386']
141b8021494Sopenharmony_ci
142b8021494Sopenharmony_cidef IsAArch64Host(env):
143b8021494Sopenharmony_ci  return env['host_arch'] == 'aarch64'
144b8021494Sopenharmony_ci
145b8021494Sopenharmony_cidef CanTargetA32(env):
146b8021494Sopenharmony_ci  return 'a32' in env['target']
147b8021494Sopenharmony_ci
148b8021494Sopenharmony_cidef CanTargetT32(env):
149b8021494Sopenharmony_ci  return 't32' in env['target']
150b8021494Sopenharmony_ci
151b8021494Sopenharmony_cidef CanTargetAArch32(env):
152b8021494Sopenharmony_ci  return CanTargetA32(env) or CanTargetT32(env)
153b8021494Sopenharmony_ci
154b8021494Sopenharmony_cidef CanTargetA64(env):
155b8021494Sopenharmony_ci  return 'a64' in env['target']
156b8021494Sopenharmony_ci
157b8021494Sopenharmony_cidef CanTargetAArch64(env):
158b8021494Sopenharmony_ci  return CanTargetA64(env)
159b8021494Sopenharmony_ci
160b8021494Sopenharmony_ci
161b8021494Sopenharmony_ci# By default, include the simulator only if AArch64 is targeted and we are not
162b8021494Sopenharmony_ci# building VIXL natively for AArch64.
163b8021494Sopenharmony_cidef simulator_handler(env):
164b8021494Sopenharmony_ci  if not IsAArch64Host(env) and CanTargetAArch64(env):
165b8021494Sopenharmony_ci    env['simulator'] = 'aarch64'
166b8021494Sopenharmony_ci  else:
167b8021494Sopenharmony_ci    env['simulator'] = 'none'
168b8021494Sopenharmony_ci
169b8021494Sopenharmony_ci
170b8021494Sopenharmony_ci# 'mmap' is required for use with 'mprotect', which is needed for the tests
171b8021494Sopenharmony_ci# (when running natively), so we use it by default where we can.
172b8021494Sopenharmony_cidef code_buffer_allocator_handler(env):
173b8021494Sopenharmony_ci  directives = util.GetCompilerDirectives(env)
174b8021494Sopenharmony_ci  if '__linux__' in directives:
175b8021494Sopenharmony_ci    env['code_buffer_allocator'] = 'mmap'
176b8021494Sopenharmony_ci  else:
177b8021494Sopenharmony_ci    env['code_buffer_allocator'] = 'malloc'
178b8021494Sopenharmony_ci
179b8021494Sopenharmony_ci# A validator checks the consistency of provided options against the environment.
180b8021494Sopenharmony_cidef default_validator(env):
181b8021494Sopenharmony_ci  pass
182b8021494Sopenharmony_ci
183b8021494Sopenharmony_ci
184b8021494Sopenharmony_cidef simulator_validator(env):
185b8021494Sopenharmony_ci  if env['simulator'] == 'aarch64' and not CanTargetAArch64(env):
186b8021494Sopenharmony_ci    raise UserError('Building an AArch64 simulator implies that VIXL targets '
187b8021494Sopenharmony_ci                    'AArch64. Set `target` to include `aarch64` or `a64`.')
188b8021494Sopenharmony_ci
189b8021494Sopenharmony_ci
190b8021494Sopenharmony_ci# Default variables may depend on each other, therefore we need this dictionary
191b8021494Sopenharmony_ci# to be ordered.
192b8021494Sopenharmony_civars_default_handlers = OrderedDict({
193b8021494Sopenharmony_ci    # variable_name    : [ 'default val', 'handler', 'validator']
194b8021494Sopenharmony_ci    'symbols'          : [ 'mode==debug', symbols_handler, default_validator ],
195b8021494Sopenharmony_ci    'modifiable_flags' : [ 'mode==debug', modifiable_flags_handler, default_validator],
196b8021494Sopenharmony_ci    'simulator'        : [ 'on if the target architectures include AArch64 but '
197b8021494Sopenharmony_ci                           'the host is not AArch64, else off',
198b8021494Sopenharmony_ci                           simulator_handler, simulator_validator ],
199b8021494Sopenharmony_ci    'code_buffer_allocator' : [ 'mmap with __linux__, malloc otherwise',
200b8021494Sopenharmony_ci                                code_buffer_allocator_handler, default_validator ]
201b8021494Sopenharmony_ci    })
202b8021494Sopenharmony_ci
203b8021494Sopenharmony_ci
204b8021494Sopenharmony_cidef DefaultVariable(name, help, allowed_values):
205b8021494Sopenharmony_ci  help = '%s (%s)' % (help, '|'.join(allowed_values))
206b8021494Sopenharmony_ci  default_value = vars_default_handlers[name][0]
207b8021494Sopenharmony_ci  def validator(name, value, env):
208b8021494Sopenharmony_ci    if value != default_value and value not in allowed_values:
209b8021494Sopenharmony_ci        raise UserError('Invalid value for option {name}: {value}.  '
210b8021494Sopenharmony_ci                        'Valid values are: {allowed_values}'.format(
211b8021494Sopenharmony_ci                            name, value, allowed_values))
212b8021494Sopenharmony_ci  return (name, help, default_value, validator)
213b8021494Sopenharmony_ci
214b8021494Sopenharmony_ci
215b8021494Sopenharmony_cidef SortListVariable(iterator):
216b8021494Sopenharmony_ci  # Previously this code relied on the order of items in a list
217b8021494Sopenharmony_ci  # converted from a set. However in Python 3 the order changes each run.
218b8021494Sopenharmony_ci  # Here we do a custom partial sort to ensure that the build directory
219b8021494Sopenharmony_ci  # name is stable, the same across Python 2 and 3, and the same as the
220b8021494Sopenharmony_ci  # old code.
221b8021494Sopenharmony_ci  result = list(sorted(iterator))
222b8021494Sopenharmony_ci  result = sorted(result, key=lambda x: x == 't32', reverse=True)
223b8021494Sopenharmony_ci  result = sorted(result, key=lambda x: x == 'a32', reverse=True)
224b8021494Sopenharmony_ci  result = sorted(result, key=lambda x: x == 'a64', reverse=True)
225b8021494Sopenharmony_ci  return result
226b8021494Sopenharmony_ci
227b8021494Sopenharmony_ci
228b8021494Sopenharmony_cidef AliasedListVariable(name, help, default_value, allowed_values, aliasing):
229b8021494Sopenharmony_ci  help = '%s (all|auto|comma-separated list) (any combination from [%s])' % \
230b8021494Sopenharmony_ci         (help, ', '.join(allowed_values))
231b8021494Sopenharmony_ci
232b8021494Sopenharmony_ci  def validator(name, value, env):
233b8021494Sopenharmony_ci    # Here list has been converted to space separated strings.
234b8021494Sopenharmony_ci    if value == '': return  # auto
235b8021494Sopenharmony_ci    for v in value.split():
236b8021494Sopenharmony_ci      if v not in allowed_values:
237b8021494Sopenharmony_ci        raise UserError('Invalid value for %s: %s' % (name, value))
238b8021494Sopenharmony_ci
239b8021494Sopenharmony_ci  def converter(value):
240b8021494Sopenharmony_ci    if value == 'auto': return []
241b8021494Sopenharmony_ci    if value == 'all':
242b8021494Sopenharmony_ci      translated = [aliasing[v] for v in allowed_values]
243b8021494Sopenharmony_ci      return SortListVariable(itertools.chain.from_iterable(translated))
244b8021494Sopenharmony_ci    # The validator is run later hence the get.
245b8021494Sopenharmony_ci    translated = [aliasing.get(v, v) for v in value.split(',')]
246b8021494Sopenharmony_ci    return SortListVariable(itertools.chain.from_iterable(translated))
247b8021494Sopenharmony_ci
248b8021494Sopenharmony_ci  return (name, help, default_value, validator, converter)
249b8021494Sopenharmony_ci
250b8021494Sopenharmony_ci
251b8021494Sopenharmony_civars = Variables()
252b8021494Sopenharmony_ci# Define command line build options.
253b8021494Sopenharmony_civars.AddVariables(
254b8021494Sopenharmony_ci    AliasedListVariable('target', 'Target ISA/Architecture', 'auto',
255b8021494Sopenharmony_ci                        ['aarch32', 'a32', 't32', 'aarch64', 'a64'],
256b8021494Sopenharmony_ci                        {'aarch32' : ['a32', 't32'],
257b8021494Sopenharmony_ci                         'a32' : ['a32'], 't32' : ['t32'],
258b8021494Sopenharmony_ci                         'aarch64' : ['a64'], 'a64' : ['a64']}),
259b8021494Sopenharmony_ci    EnumVariable('mode', 'Build mode',
260b8021494Sopenharmony_ci                 'release', allowed_values=config.build_options_modes),
261b8021494Sopenharmony_ci    EnumVariable('ubsan', 'Enable undefined behavior checks',
262b8021494Sopenharmony_ci                 'off', allowed_values=['on', 'off']),
263b8021494Sopenharmony_ci    EnumVariable('coverage', 'Enable code coverage measurement',
264b8021494Sopenharmony_ci                 'off', allowed_values=['on', 'off']),
265b8021494Sopenharmony_ci    EnumVariable('negative_testing',
266b8021494Sopenharmony_ci                  'Enable negative testing (needs exceptions)',
267b8021494Sopenharmony_ci                 'off', allowed_values=['on', 'off']),
268b8021494Sopenharmony_ci    DefaultVariable('symbols', 'Include debugging symbols in the binaries',
269b8021494Sopenharmony_ci                    ['on', 'off']),
270b8021494Sopenharmony_ci    DefaultVariable('simulator', 'Simulators to include', ['aarch64', 'none']),
271b8021494Sopenharmony_ci    DefaultVariable('code_buffer_allocator',
272b8021494Sopenharmony_ci                    'Configure the allocation mechanism in the CodeBuffer',
273b8021494Sopenharmony_ci                    ['malloc', 'mmap']),
274b8021494Sopenharmony_ci    ('std',
275b8021494Sopenharmony_ci     'C++ standard. The standards tested are: %s.' % \
276b8021494Sopenharmony_ci     ', '.join(config.tested_cpp_standards),
277b8021494Sopenharmony_ci     config.tested_cpp_standards[0]),
278b8021494Sopenharmony_ci    ('compiler_wrapper', 'Command to prefix to the C and C++ compiler (e.g ccache)', '')
279b8021494Sopenharmony_ci    )
280b8021494Sopenharmony_ci
281b8021494Sopenharmony_ci# We use 'variant directories' to avoid recompiling multiple times when build
282b8021494Sopenharmony_ci# options are changed, different build paths are used depending on the options
283b8021494Sopenharmony_ci# set. These are the options that should be reflected in the build directory
284b8021494Sopenharmony_ci# path.
285b8021494Sopenharmony_cioptions_influencing_build_path = [
286b8021494Sopenharmony_ci  'target', 'mode', 'symbols', 'compiler', 'std', 'simulator', 'negative_testing',
287b8021494Sopenharmony_ci  'code_buffer_allocator'
288b8021494Sopenharmony_ci]
289b8021494Sopenharmony_ci
290b8021494Sopenharmony_ci
291b8021494Sopenharmony_ci
292b8021494Sopenharmony_ci# Build helpers ----------------------------------------------------------------
293b8021494Sopenharmony_ci
294b8021494Sopenharmony_cidef RetrieveEnvironmentVariables(env):
295b8021494Sopenharmony_ci  for key in ['CC', 'CXX', 'AR', 'RANLIB', 'LD']:
296b8021494Sopenharmony_ci    if os.getenv(key): env[key] = os.getenv(key)
297b8021494Sopenharmony_ci  if os.getenv('LD_LIBRARY_PATH'): env['LIBPATH'] = os.getenv('LD_LIBRARY_PATH')
298b8021494Sopenharmony_ci  if os.getenv('CCFLAGS'):
299b8021494Sopenharmony_ci    env.Append(CCFLAGS = os.getenv('CCFLAGS').split())
300b8021494Sopenharmony_ci  if os.getenv('CXXFLAGS'):
301b8021494Sopenharmony_ci    env.Append(CXXFLAGS = os.getenv('CXXFLAGS').split())
302b8021494Sopenharmony_ci  if os.getenv('LINKFLAGS'):
303b8021494Sopenharmony_ci    env.Append(LINKFLAGS = os.getenv('LINKFLAGS').split())
304b8021494Sopenharmony_ci
305b8021494Sopenharmony_ci# The architecture targeted by default will depend on the compiler being
306b8021494Sopenharmony_ci# used. 'host_arch' is extracted from the compiler while 'target' can be
307b8021494Sopenharmony_ci# set by the user.
308b8021494Sopenharmony_ci# By default, we target both AArch32 and AArch64 unless the compiler targets a
309b8021494Sopenharmony_ci# 32-bit architecture. At the moment, we cannot build VIXL's AArch64 support on
310b8021494Sopenharmony_ci# a 32-bit platform.
311b8021494Sopenharmony_ci# TODO: Port VIXL to build on a 32-bit platform.
312b8021494Sopenharmony_cidef target_handler(env):
313b8021494Sopenharmony_ci  # Auto detect
314b8021494Sopenharmony_ci  if Is32BitHost(env):
315b8021494Sopenharmony_ci    # We use list(set(...)) to keep the same order as if it was specify as
316b8021494Sopenharmony_ci    # an option.
317b8021494Sopenharmony_ci    env['target'] = SortListVariable(['a32', 't32'])
318b8021494Sopenharmony_ci  else:
319b8021494Sopenharmony_ci    env['target'] = SortListVariable(['a64', 'a32', 't32'])
320b8021494Sopenharmony_ci
321b8021494Sopenharmony_ci
322b8021494Sopenharmony_cidef target_validator(env):
323b8021494Sopenharmony_ci  # TODO: Port VIXL64 to work on a 32-bit platform.
324b8021494Sopenharmony_ci  if Is32BitHost(env) and CanTargetAArch64(env):
325b8021494Sopenharmony_ci    raise UserError('Building VIXL for AArch64 in 32-bit is not supported. Set '
326b8021494Sopenharmony_ci                    '`target` to `aarch32`')
327b8021494Sopenharmony_ci
328b8021494Sopenharmony_ci
329b8021494Sopenharmony_ci# The target option is handled differently from the rest.
330b8021494Sopenharmony_cidef ProcessTargetOption(env):
331b8021494Sopenharmony_ci  if env['target'] == []: target_handler(env)
332b8021494Sopenharmony_ci
333b8021494Sopenharmony_ci  if 'a32' in env['target']: env['CCFLAGS'] += ['-DVIXL_INCLUDE_TARGET_A32']
334b8021494Sopenharmony_ci  if 't32' in env['target']: env['CCFLAGS'] += ['-DVIXL_INCLUDE_TARGET_T32']
335b8021494Sopenharmony_ci  if 'a64' in env['target']: env['CCFLAGS'] += ['-DVIXL_INCLUDE_TARGET_A64']
336b8021494Sopenharmony_ci
337b8021494Sopenharmony_ci  target_validator(env)
338b8021494Sopenharmony_ci
339b8021494Sopenharmony_ci
340b8021494Sopenharmony_cidef ProcessBuildOptions(env):
341b8021494Sopenharmony_ci  # 'all' is unconditionally processed.
342b8021494Sopenharmony_ci  if 'all' in options:
343b8021494Sopenharmony_ci    for var in options['all']:
344b8021494Sopenharmony_ci      if var in env and env[var]:
345b8021494Sopenharmony_ci        env[var] += options['all'][var]
346b8021494Sopenharmony_ci      else:
347b8021494Sopenharmony_ci        env[var] = options['all'][var]
348b8021494Sopenharmony_ci
349b8021494Sopenharmony_ci  # The target option *must* be processed before the options defined in
350b8021494Sopenharmony_ci  # vars_default_handlers.
351b8021494Sopenharmony_ci  ProcessTargetOption(env)
352b8021494Sopenharmony_ci
353b8021494Sopenharmony_ci  # Other build options must match 'option:value'
354b8021494Sopenharmony_ci  env_dict = env.Dictionary()
355b8021494Sopenharmony_ci
356b8021494Sopenharmony_ci  # First apply the default variables handlers in order.
357b8021494Sopenharmony_ci  for key, value in vars_default_handlers.items():
358b8021494Sopenharmony_ci    default = value[0]
359b8021494Sopenharmony_ci    handler = value[1]
360b8021494Sopenharmony_ci    if env_dict.get(key) == default:
361b8021494Sopenharmony_ci      handler(env_dict)
362b8021494Sopenharmony_ci
363b8021494Sopenharmony_ci  # Second, run the series of validators, to check for errors.
364b8021494Sopenharmony_ci  for _, value in vars_default_handlers.items():
365b8021494Sopenharmony_ci    validator = value[2]
366b8021494Sopenharmony_ci    validator(env)
367b8021494Sopenharmony_ci
368b8021494Sopenharmony_ci  for key in env_dict.keys():
369b8021494Sopenharmony_ci    # Then update the environment according to the value of the variable.
370b8021494Sopenharmony_ci    key_val_couple = key + ':%s' % env_dict[key]
371b8021494Sopenharmony_ci    if key_val_couple in options:
372b8021494Sopenharmony_ci      for var in options[key_val_couple]:
373b8021494Sopenharmony_ci        env[var] += options[key_val_couple][var]
374b8021494Sopenharmony_ci
375b8021494Sopenharmony_ci
376b8021494Sopenharmony_cidef ConfigureEnvironmentForCompiler(env):
377b8021494Sopenharmony_ci  compiler = util.CompilerInformation(env)
378b8021494Sopenharmony_ci  if compiler == 'clang':
379b8021494Sopenharmony_ci    # These warnings only work for Clang.
380b8021494Sopenharmony_ci    # -Wimplicit-fallthrough only works when compiling the code base as C++11 or
381b8021494Sopenharmony_ci    # newer. The compiler does not complain if the option is passed when
382b8021494Sopenharmony_ci    # compiling earlier C++ standards.
383b8021494Sopenharmony_ci    env.Append(CPPFLAGS = ['-Wimplicit-fallthrough', '-Wshorten-64-to-32'])
384b8021494Sopenharmony_ci
385b8021494Sopenharmony_ci    # The '-Wunreachable-code' flag breaks builds for clang 3.4.
386b8021494Sopenharmony_ci    if compiler != 'clang-3.4':
387b8021494Sopenharmony_ci      env.Append(CPPFLAGS = ['-Wunreachable-code'])
388b8021494Sopenharmony_ci
389b8021494Sopenharmony_ci    if env['ubsan'] == 'on':
390b8021494Sopenharmony_ci      env.Append(LINKFLAGS = ['-fuse-ld=lld'])
391b8021494Sopenharmony_ci
392b8021494Sopenharmony_ci  # GCC 4.8 has a bug which produces a warning saying that an anonymous Operand
393b8021494Sopenharmony_ci  # object might be used uninitialized:
394b8021494Sopenharmony_ci  #   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57045
395b8021494Sopenharmony_ci  # The bug does not seem to appear in GCC 4.7, or in debug builds with GCC 4.8.
396b8021494Sopenharmony_ci  if env['mode'] == 'release':
397b8021494Sopenharmony_ci    if compiler == 'gcc-4.8':
398b8021494Sopenharmony_ci      env.Append(CPPFLAGS = ['-Wno-maybe-uninitialized'])
399b8021494Sopenharmony_ci
400b8021494Sopenharmony_ci  # GCC 6 and higher is able to detect throwing from inside a destructor and
401b8021494Sopenharmony_ci  # reports a warning. However, if negative testing is enabled then assertions
402b8021494Sopenharmony_ci  # will throw exceptions.
403b8021494Sopenharmony_ci  if env['negative_testing'] == 'on' and env['mode'] == 'debug' \
404b8021494Sopenharmony_ci      and compiler >= 'gcc-6':
405b8021494Sopenharmony_ci    env.Append(CPPFLAGS = ['-Wno-terminate'])
406b8021494Sopenharmony_ci
407b8021494Sopenharmony_ci  # Suggest missing override keywords on methods.
408b8021494Sopenharmony_ci  if compiler >= 'gcc-5':
409b8021494Sopenharmony_ci    env.Append(CPPFLAGS = ['-Wsuggest-override'])
410b8021494Sopenharmony_ci  elif compiler >= 'clang-3.6':
411b8021494Sopenharmony_ci    env.Append(CPPFLAGS = ['-Winconsistent-missing-override'])
412b8021494Sopenharmony_ci
413b8021494Sopenharmony_ci
414b8021494Sopenharmony_cidef ConfigureEnvironment(env):
415b8021494Sopenharmony_ci  RetrieveEnvironmentVariables(env)
416b8021494Sopenharmony_ci  env['compiler'] = env['CXX']
417b8021494Sopenharmony_ci  if env['compiler_wrapper'] != '':
418b8021494Sopenharmony_ci    env['CXX'] = env['compiler_wrapper'] + ' ' + env['CXX']
419b8021494Sopenharmony_ci    env['CC'] = env['compiler_wrapper'] + ' ' + env['CC']
420b8021494Sopenharmony_ci  env['host_arch'] = util.GetHostArch(env)
421b8021494Sopenharmony_ci  ProcessBuildOptions(env)
422b8021494Sopenharmony_ci  if 'std' in env:
423b8021494Sopenharmony_ci    env.Append(CPPFLAGS = ['-std=' + env['std']])
424b8021494Sopenharmony_ci    std_path = env['std']
425b8021494Sopenharmony_ci  ConfigureEnvironmentForCompiler(env)
426b8021494Sopenharmony_ci
427b8021494Sopenharmony_ci
428b8021494Sopenharmony_cidef TargetBuildDir(env):
429b8021494Sopenharmony_ci  # Build-time option values are embedded in the build path to avoid requiring a
430b8021494Sopenharmony_ci  # full build when an option changes.
431b8021494Sopenharmony_ci  build_dir = config.dir_build
432b8021494Sopenharmony_ci  for option in options_influencing_build_path:
433b8021494Sopenharmony_ci    option_value = ''.join(env[option]) if option in env else ''
434b8021494Sopenharmony_ci    build_dir = join(build_dir, option + '_'+ option_value)
435b8021494Sopenharmony_ci  return build_dir
436b8021494Sopenharmony_ci
437b8021494Sopenharmony_ci
438b8021494Sopenharmony_cidef PrepareVariantDir(location, build_dir):
439b8021494Sopenharmony_ci  location_build_dir = join(build_dir, location)
440b8021494Sopenharmony_ci  VariantDir(location_build_dir, location)
441b8021494Sopenharmony_ci  return location_build_dir
442b8021494Sopenharmony_ci
443b8021494Sopenharmony_ci
444b8021494Sopenharmony_cidef VIXLLibraryTarget(env):
445b8021494Sopenharmony_ci  build_dir = TargetBuildDir(env)
446b8021494Sopenharmony_ci  # Create a link to the latest build directory.
447b8021494Sopenharmony_ci  # Use `-r` to avoid failure when `latest` exists and is a directory.
448b8021494Sopenharmony_ci  subprocess.check_call(["rm", "-rf", config.dir_build_latest])
449b8021494Sopenharmony_ci  util.ensure_dir(build_dir)
450b8021494Sopenharmony_ci  subprocess.check_call(["ln", "-s", build_dir, config.dir_build_latest])
451b8021494Sopenharmony_ci  # Source files are in `src` and in `src/aarch64/`.
452b8021494Sopenharmony_ci  variant_dir_vixl = PrepareVariantDir(join('src'), build_dir)
453b8021494Sopenharmony_ci  sources = [Glob(join(variant_dir_vixl, '*.cc'))]
454b8021494Sopenharmony_ci  if CanTargetAArch32(env):
455b8021494Sopenharmony_ci    variant_dir_aarch32 = PrepareVariantDir(join('src', 'aarch32'), build_dir)
456b8021494Sopenharmony_ci    sources.append(Glob(join(variant_dir_aarch32, '*.cc')))
457b8021494Sopenharmony_ci  if CanTargetAArch64(env):
458b8021494Sopenharmony_ci    variant_dir_aarch64 = PrepareVariantDir(join('src', 'aarch64'), build_dir)
459b8021494Sopenharmony_ci    sources.append(Glob(join(variant_dir_aarch64, '*.cc')))
460b8021494Sopenharmony_ci  return env.Library(join(build_dir, 'vixl'), sources)
461b8021494Sopenharmony_ci
462b8021494Sopenharmony_ci
463b8021494Sopenharmony_ci
464b8021494Sopenharmony_ci# Build ------------------------------------------------------------------------
465b8021494Sopenharmony_ci
466b8021494Sopenharmony_ci# The VIXL library, built by default.
467b8021494Sopenharmony_cienv = Environment(variables = vars,
468b8021494Sopenharmony_ci                  BUILDERS = {
469b8021494Sopenharmony_ci                      'Markdown': Builder(action = 'markdown $SOURCE > $TARGET',
470b8021494Sopenharmony_ci                                          suffix = '.html')
471b8021494Sopenharmony_ci                  }, ENV = os.environ)
472b8021494Sopenharmony_ci# Abort the build if any command line option is unknown or invalid.
473b8021494Sopenharmony_ciunknown_build_options = vars.UnknownVariables()
474b8021494Sopenharmony_ciif unknown_build_options:
475b8021494Sopenharmony_ci  print('Unknown build options: ' + str(unknown_build_options.keys()))
476b8021494Sopenharmony_ci  Exit(1)
477b8021494Sopenharmony_ci
478b8021494Sopenharmony_ciif env['negative_testing'] == 'on' and env['mode'] != 'debug':
479b8021494Sopenharmony_ci  print('negative_testing only works in debug mode')
480b8021494Sopenharmony_ci  Exit(1)
481b8021494Sopenharmony_ci
482b8021494Sopenharmony_ciConfigureEnvironment(env)
483b8021494Sopenharmony_ciHelp(vars.GenerateHelpText(env))
484b8021494Sopenharmony_cilibvixl = VIXLLibraryTarget(env)
485b8021494Sopenharmony_ciDefault(libvixl)
486b8021494Sopenharmony_cienv.Alias('libvixl', libvixl)
487b8021494Sopenharmony_citop_level_targets.Add('', 'Build the VIXL library.')
488b8021494Sopenharmony_ci
489b8021494Sopenharmony_ci
490b8021494Sopenharmony_ci# Common test code.
491b8021494Sopenharmony_citest_build_dir = PrepareVariantDir('test', TargetBuildDir(env))
492b8021494Sopenharmony_citest_objects = [env.Object(Glob(join(test_build_dir, '*.cc'), exclude=join(test_build_dir, 'test-donkey.cc')))]
493b8021494Sopenharmony_ci
494b8021494Sopenharmony_ci# AArch32 support
495b8021494Sopenharmony_ciif CanTargetAArch32(env):
496b8021494Sopenharmony_ci  # The examples.
497b8021494Sopenharmony_ci  aarch32_example_names = util.ListCCFilesWithoutExt(config.dir_aarch32_examples)
498b8021494Sopenharmony_ci  aarch32_examples_build_dir = PrepareVariantDir('examples/aarch32', TargetBuildDir(env))
499b8021494Sopenharmony_ci  aarch32_example_targets = []
500b8021494Sopenharmony_ci  for example in aarch32_example_names:
501b8021494Sopenharmony_ci    prog = env.Program(join(aarch32_examples_build_dir, example),
502b8021494Sopenharmony_ci                       join(aarch32_examples_build_dir, example + '.cc'),
503b8021494Sopenharmony_ci                       LIBS=[libvixl])
504b8021494Sopenharmony_ci    aarch32_example_targets.append(prog)
505b8021494Sopenharmony_ci  env.Alias('aarch32_examples', aarch32_example_targets)
506b8021494Sopenharmony_ci  top_level_targets.Add('aarch32_examples', 'Build the examples for AArch32.')
507b8021494Sopenharmony_ci
508b8021494Sopenharmony_ci  # The benchmarks
509b8021494Sopenharmony_ci  aarch32_benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch32_benchmarks)
510b8021494Sopenharmony_ci  aarch32_benchmarks_build_dir = PrepareVariantDir('benchmarks/aarch32', TargetBuildDir(env))
511b8021494Sopenharmony_ci  aarch32_benchmark_targets = []
512b8021494Sopenharmony_ci  for bench in aarch32_benchmark_names:
513b8021494Sopenharmony_ci    prog = env.Program(join(aarch32_benchmarks_build_dir, bench),
514b8021494Sopenharmony_ci                       join(aarch32_benchmarks_build_dir, bench + '.cc'),
515b8021494Sopenharmony_ci                       LIBS=[libvixl])
516b8021494Sopenharmony_ci    aarch32_benchmark_targets.append(prog)
517b8021494Sopenharmony_ci  env.Alias('aarch32_benchmarks', aarch32_benchmark_targets)
518b8021494Sopenharmony_ci  top_level_targets.Add('aarch32_benchmarks', 'Build the benchmarks for AArch32.')
519b8021494Sopenharmony_ci
520b8021494Sopenharmony_ci  # The tests.
521b8021494Sopenharmony_ci  test_aarch32_build_dir = PrepareVariantDir(join('test', 'aarch32'), TargetBuildDir(env))
522b8021494Sopenharmony_ci  test_objects.append(env.Object(
523b8021494Sopenharmony_ci      Glob(join(test_aarch32_build_dir, '*.cc')),
524b8021494Sopenharmony_ci      CPPPATH = env['CPPPATH'] + [config.dir_tests],
525b8021494Sopenharmony_ci      CCFLAGS = [flag for flag in env['CCFLAGS'] if flag != '-O3']))
526b8021494Sopenharmony_ci
527b8021494Sopenharmony_ci# AArch64 support
528b8021494Sopenharmony_ciif CanTargetAArch64(env):
529b8021494Sopenharmony_ci  # The benchmarks.
530b8021494Sopenharmony_ci  aarch64_benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch64_benchmarks)
531b8021494Sopenharmony_ci  aarch64_benchmarks_build_dir = PrepareVariantDir('benchmarks/aarch64', TargetBuildDir(env))
532b8021494Sopenharmony_ci  aarch64_benchmark_targets = []
533b8021494Sopenharmony_ci  bench_utils = env.Object(join(aarch64_benchmarks_build_dir, 'bench-utils.o'),
534b8021494Sopenharmony_ci                           join(aarch64_benchmarks_build_dir, 'bench-utils.cc'))
535b8021494Sopenharmony_ci  for bench in aarch64_benchmark_names:
536b8021494Sopenharmony_ci    if bench != 'bench-utils':
537b8021494Sopenharmony_ci      prog = env.Program(join(aarch64_benchmarks_build_dir, bench),
538b8021494Sopenharmony_ci                         [join(aarch64_benchmarks_build_dir, bench + '.cc'), bench_utils],
539b8021494Sopenharmony_ci                         LIBS=[libvixl])
540b8021494Sopenharmony_ci      aarch64_benchmark_targets.append(prog)
541b8021494Sopenharmony_ci  env.Alias('aarch64_benchmarks', aarch64_benchmark_targets)
542b8021494Sopenharmony_ci  top_level_targets.Add('aarch64_benchmarks', 'Build the benchmarks for AArch64.')
543b8021494Sopenharmony_ci
544b8021494Sopenharmony_ci  # The examples.
545b8021494Sopenharmony_ci  aarch64_example_names = util.ListCCFilesWithoutExt(config.dir_aarch64_examples)
546b8021494Sopenharmony_ci  aarch64_examples_build_dir = PrepareVariantDir('examples/aarch64', TargetBuildDir(env))
547b8021494Sopenharmony_ci  aarch64_example_targets = []
548b8021494Sopenharmony_ci  for example in aarch64_example_names:
549b8021494Sopenharmony_ci    prog = env.Program(join(aarch64_examples_build_dir, example),
550b8021494Sopenharmony_ci                       join(aarch64_examples_build_dir, example + '.cc'),
551b8021494Sopenharmony_ci                       LIBS=[libvixl])
552b8021494Sopenharmony_ci    aarch64_example_targets.append(prog)
553b8021494Sopenharmony_ci  env.Alias('aarch64_examples', aarch64_example_targets)
554b8021494Sopenharmony_ci  top_level_targets.Add('aarch64_examples', 'Build the examples for AArch64.')
555b8021494Sopenharmony_ci
556b8021494Sopenharmony_ci  # The tests.
557b8021494Sopenharmony_ci  test_aarch64_build_dir = PrepareVariantDir(join('test', 'aarch64'), TargetBuildDir(env))
558b8021494Sopenharmony_ci  test_objects.append(env.Object(
559b8021494Sopenharmony_ci      Glob(join(test_aarch64_build_dir, '*.cc')),
560b8021494Sopenharmony_ci      CPPPATH = env['CPPPATH'] + [config.dir_tests],
561b8021494Sopenharmony_ci      CCFLAGS = [flag for flag in env['CCFLAGS'] if flag != '-O3']))
562b8021494Sopenharmony_ci
563b8021494Sopenharmony_ci  # The test requires building the example files with specific options, so we
564b8021494Sopenharmony_ci  # create a separate variant dir for the example objects built this way.
565b8021494Sopenharmony_ci  test_aarch64_examples_vdir = join(TargetBuildDir(env), 'test', 'aarch64', 'test_examples')
566b8021494Sopenharmony_ci  VariantDir(test_aarch64_examples_vdir, '.')
567b8021494Sopenharmony_ci  test_aarch64_examples_obj = env.Object(
568b8021494Sopenharmony_ci      [Glob(join(test_aarch64_examples_vdir, join('test', 'aarch64', 'examples', '*.cc'))),
569b8021494Sopenharmony_ci       Glob(join(test_aarch64_examples_vdir, join('examples/aarch64', '*.cc')))],
570b8021494Sopenharmony_ci      CCFLAGS = env['CCFLAGS'] + ['-DTEST_EXAMPLES'],
571b8021494Sopenharmony_ci      CPPPATH = env['CPPPATH'] + [config.dir_aarch64_examples] + [config.dir_tests])
572b8021494Sopenharmony_ci  test_objects.append(test_aarch64_examples_obj)
573b8021494Sopenharmony_ci
574b8021494Sopenharmony_ci  # The simulator test generator.
575b8021494Sopenharmony_ci  donkey_objects = []
576b8021494Sopenharmony_ci  donkey_objects.append(env.Object(
577b8021494Sopenharmony_ci      [join(test_build_dir, 'test-donkey.cc'), join(test_aarch64_build_dir, 'test-utils-aarch64.cc')],
578b8021494Sopenharmony_ci      CPPPATH = env['CPPPATH'] + [config.dir_tests],
579b8021494Sopenharmony_ci      CCFLAGS = [flag for flag in env['CCFLAGS'] if flag != '-O3']))
580b8021494Sopenharmony_ci  donkey = env.Program(join(test_build_dir, 'test-donkey'), donkey_objects, LIBS=[libvixl])
581b8021494Sopenharmony_ci  env.Alias('tests', donkey)
582b8021494Sopenharmony_ci
583b8021494Sopenharmony_citest = env.Program(join(test_build_dir, 'test-runner'), test_objects,
584b8021494Sopenharmony_ci                   LIBS=[libvixl])
585b8021494Sopenharmony_cienv.Alias('tests', test)
586b8021494Sopenharmony_citop_level_targets.Add('tests', 'Build the tests.')
587b8021494Sopenharmony_ci
588b8021494Sopenharmony_ci
589b8021494Sopenharmony_cienv.Alias('all', top_level_targets.targets)
590b8021494Sopenharmony_citop_level_targets.Add('all', 'Build all the targets above.')
591b8021494Sopenharmony_ci
592b8021494Sopenharmony_ciHelp('\n\nAvailable top level targets:\n' + top_level_targets.Help())
593b8021494Sopenharmony_ci
594b8021494Sopenharmony_ciextra_targets = VIXLTargets()
595b8021494Sopenharmony_ci
596b8021494Sopenharmony_ci# Build documentation
597b8021494Sopenharmony_cidoc = [
598b8021494Sopenharmony_ci    env.Markdown('README.md'),
599b8021494Sopenharmony_ci    env.Markdown('doc/changelog.md'),
600b8021494Sopenharmony_ci    env.Markdown('doc/aarch32/getting-started-aarch32.md'),
601b8021494Sopenharmony_ci    env.Markdown('doc/aarch32/design/code-generation-aarch32.md'),
602b8021494Sopenharmony_ci    env.Markdown('doc/aarch32/design/literal-pool-aarch32.md'),
603b8021494Sopenharmony_ci    env.Markdown('doc/aarch64/supported-instructions-aarch64.md'),
604b8021494Sopenharmony_ci    env.Markdown('doc/aarch64/getting-started-aarch64.md'),
605b8021494Sopenharmony_ci    env.Markdown('doc/aarch64/topics/ycm.md'),
606b8021494Sopenharmony_ci    env.Markdown('doc/aarch64/topics/extending-the-disassembler.md'),
607b8021494Sopenharmony_ci    env.Markdown('doc/aarch64/topics/index.md'),
608b8021494Sopenharmony_ci]
609b8021494Sopenharmony_cienv.Alias('doc', doc)
610b8021494Sopenharmony_ciextra_targets.Add('doc', 'Convert documentation to HTML (requires the '
611b8021494Sopenharmony_ci                         '`markdown` program).')
612b8021494Sopenharmony_ci
613b8021494Sopenharmony_ciHelp('\nAvailable extra targets:\n' + extra_targets.Help())
614