blob: bca8766c5fb5f97f63b6f7c485380f2f3a1e9ecd [file] [log] [blame]
Alexandre Ramesb78f1392016-07-01 14:22:22 +01001# Copyright 2015, VIXL authors
armvixlad96eda2013-06-14 11:42:37 +01002# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6#
7# * Redistributions of source code must retain the above copyright notice,
8# this list of conditions and the following disclaimer.
9# * Redistributions in binary form must reproduce the above copyright notice,
10# this list of conditions and the following disclaimer in the documentation
11# and/or other materials provided with the distribution.
12# * Neither the name of ARM Limited nor the names of its contributors may be
13# used to endorse or promote products derived from this software without
14# specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
armvixldb644342015-07-21 11:37:10 +010027import glob
armvixlad96eda2013-06-14 11:42:37 +010028import os
armvixldb644342015-07-21 11:37:10 +010029from os.path import join
armvixlc68cb642014-09-25 18:49:30 +010030import platform
armvixl4a102ba2014-07-14 09:02:40 +010031import subprocess
armvixlad96eda2013-06-14 11:42:37 +010032import sys
Pierre Langloisa3b21462016-08-04 16:01:51 +010033from collections import OrderedDict
armvixlad96eda2013-06-14 11:42:37 +010034
armvixl4a102ba2014-07-14 09:02:40 +010035root_dir = os.path.dirname(File('SConstruct').rfile().abspath)
armvixldb644342015-07-21 11:37:10 +010036sys.path.insert(0, join(root_dir, 'tools'))
37import config
armvixl4a102ba2014-07-14 09:02:40 +010038import util
39
armvixlc68cb642014-09-25 18:49:30 +010040
41Help('''
42Build system for the VIXL project.
43See README.md for documentation and details about the build system.
armvixlc68cb642014-09-25 18:49:30 +010044''')
45
46
armvixldb644342015-07-21 11:37:10 +010047# We track top-level targets to automatically generate help and alias them.
48class TopLevelTargets:
49 def __init__(self):
50 self.targets = []
51 self.help_messages = []
52 def Add(self, target, help_message):
53 self.targets.append(target)
54 self.help_messages.append(help_message)
55 def Help(self):
armvixl684cd2a2015-10-23 13:38:33 +010056 res = ""
armvixldb644342015-07-21 11:37:10 +010057 for i in range(len(self.targets)):
58 res += '\t{0:<{1}}{2:<{3}}\n'.format(
59 'scons ' + self.targets[i],
60 len('scons ') + max(map(len, self.targets)),
61 ' : ' + self.help_messages[i],
62 len(' : ') + max(map(len, self.help_messages)))
63 return res
armvixlad96eda2013-06-14 11:42:37 +010064
armvixldb644342015-07-21 11:37:10 +010065top_level_targets = TopLevelTargets()
armvixlad96eda2013-06-14 11:42:37 +010066
67
armvixldb644342015-07-21 11:37:10 +010068
69# Build options ----------------------------------------------------------------
70
71# Store all the options in a dictionary.
72# The SConstruct will check the build variables and construct the build
73# environment as appropriate.
74options = {
75 'all' : { # Unconditionally processed.
76 'CCFLAGS' : ['-Wall',
77 '-Werror',
78 '-fdiagnostics-show-option',
79 '-Wextra',
80 '-Wredundant-decls',
81 '-pedantic',
armvixl684cd2a2015-10-23 13:38:33 +010082 '-Wmissing-noreturn',
Alexandre Ramesfd098172016-08-09 10:29:53 +010083 '-Wwrite-strings',
84 '-Wunused'],
armvixldb644342015-07-21 11:37:10 +010085 'CPPPATH' : [config.dir_src_vixl]
86 },
87# 'build_option:value' : {
88# 'environment_key' : 'values to append'
89# },
90 'mode:debug' : {
91 'CCFLAGS' : ['-DVIXL_DEBUG', '-O0']
92 },
93 'mode:release' : {
Alexandre Ramesfa4a4bd2016-07-25 14:14:22 +010094 'CCFLAGS' : ['-O3'],
armvixldb644342015-07-21 11:37:10 +010095 },
Pierre Langloisa3b21462016-08-04 16:01:51 +010096 'simulator:aarch64' : {
Pierre Langlois1e85b7f2016-08-05 14:20:36 +010097 'CCFLAGS' : ['-DVIXL_INCLUDE_SIMULATOR_AARCH64'],
armvixldb644342015-07-21 11:37:10 +010098 },
99 'symbols:on' : {
100 'CCFLAGS' : ['-g'],
101 'LINKFLAGS' : ['-g']
102 },
103 }
armvixlad96eda2013-06-14 11:42:37 +0100104
105
armvixldb644342015-07-21 11:37:10 +0100106# A `DefaultVariable` has a default value that depends on elements not known
107# when variables are first evaluated.
108# Each `DefaultVariable` has a handler that will compute the default value for
109# the given environment.
110def modifiable_flags_handler(env):
111 env['modifiable_flags'] = \
112 'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
armvixl6e2c8272015-03-31 11:04:14 +0100113
114
armvixldb644342015-07-21 11:37:10 +0100115def symbols_handler(env):
116 env['symbols'] = 'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
armvixlad96eda2013-06-14 11:42:37 +0100117
118
Pierre Langloisa3b21462016-08-04 16:01:51 +0100119# The architecture targeted by default will depend on the compiler being
120# used. 'host_arch' is extracted from the compiler while 'target_arch' can be
121# set by the user.
122# By default, we target both AArch32 and AArch64 unless the compiler
123# targets AArch32. At the moment, we cannot build VIXL's AArch64 support on a 32
124# bit platform.
125# TODO: Port VIXL to build on a 32 bit platform.
126def target_arch_handler(env):
127 if env['host_arch'] == 'aarch32':
128 env['target_arch'] = 'aarch32'
129 else:
130 env['target_arch'] = 'both'
131
132
133# By default, include the simulator only if AArch64 is targeted and we are not
134# building VIXL natively for AArch64.
135def simulator_handler(env):
136 if env['host_arch'] != 'aarch64' and \
137 env['target_arch'] in ['aarch64', 'both']:
138 env['simulator'] = 'aarch64'
139 else:
140 env['simulator'] = 'none'
141
142
143# Default variables may depend on each other, therefore we need this dictionnary
144# to be ordered.
145vars_default_handlers = OrderedDict({
armvixldb644342015-07-21 11:37:10 +0100146 # variable_name : [ 'default val', 'handler' ]
147 'symbols' : [ 'mode==debug', symbols_handler ],
Pierre Langloisa3b21462016-08-04 16:01:51 +0100148 'modifiable_flags' : [ 'mode==debug', modifiable_flags_handler ],
149 'target_arch' : [ 'same as host architecture if running on AArch32 - '
150 'otherwise both',
151 target_arch_handler ],
152 'simulator' : ['on if the target architectures include AArch64 but '
153 'the host is not AArch64, else off',
154 simulator_handler ]
155 })
armvixldb644342015-07-21 11:37:10 +0100156
157
Pierre Langloisa3b21462016-08-04 16:01:51 +0100158def DefaultVariable(name, help, allowed_values):
159 help = '%s (%s)' % (help, '|'.join(allowed_values))
armvixldb644342015-07-21 11:37:10 +0100160 default_value = vars_default_handlers[name][0]
Pierre Langloisa3b21462016-08-04 16:01:51 +0100161 def validator(name, value, env):
162 if value != default_value and value not in allowed_values:
163 raise SCons.Errors.UserError(
164 'Invalid value for option {name}: {value}. '
165 'Valid values are: {allowed_values}'.format(name,
166 value,
167 allowed_values))
168 return (name, help, default_value, validator)
armvixldb644342015-07-21 11:37:10 +0100169
170
171vars = Variables()
172# Define command line build options.
armvixldb644342015-07-21 11:37:10 +0100173vars.AddVariables(
174 EnumVariable('mode', 'Build mode',
175 'release', allowed_values=config.build_options_modes),
176 DefaultVariable('symbols', 'Include debugging symbols in the binaries',
177 ['on', 'off']),
Pierre Langloisa3b21462016-08-04 16:01:51 +0100178 DefaultVariable('target_arch', 'Target architecture',
179 ['aarch32', 'aarch64', 'both']),
180 DefaultVariable('simulator', 'Simulators to include', ['aarch64', 'none']),
armvixldb644342015-07-21 11:37:10 +0100181 ('std', 'C++ standard. The standards tested are: %s.' % \
182 ', '.join(config.tested_cpp_standards))
183 )
armvixlad96eda2013-06-14 11:42:37 +0100184
armvixldb644342015-07-21 11:37:10 +0100185# Abort the build if any command line option is unknown or invalid.
186unknown_build_options = vars.UnknownVariables()
187if unknown_build_options:
188 print 'Unknown build options:', unknown_build_options.keys()
189 Exit(1)
armvixlad96eda2013-06-14 11:42:37 +0100190
armvixldb644342015-07-21 11:37:10 +0100191# We use 'variant directories' to avoid recompiling multiple times when build
192# options are changed, different build paths are used depending on the options
193# set. These are the options that should be reflected in the build directory
194# path.
Pierre Langloisa3b21462016-08-04 16:01:51 +0100195options_influencing_build_path = [
196 'target_arch', 'mode', 'symbols', 'CXX', 'std', 'simulator'
197]
armvixlad96eda2013-06-14 11:42:37 +0100198
armvixlad96eda2013-06-14 11:42:37 +0100199
armvixldb644342015-07-21 11:37:10 +0100200
201# Build helpers ----------------------------------------------------------------
202
203def RetrieveEnvironmentVariables(env):
Pierre Langlois88c46b82016-06-02 18:15:32 +0100204 for key in ['CC', 'CXX', 'AR', 'RANLIB', 'LD']:
armvixldb644342015-07-21 11:37:10 +0100205 if os.getenv(key): env[key] = os.getenv(key)
206 if os.getenv('LD_LIBRARY_PATH'): env['LIBPATH'] = os.getenv('LD_LIBRARY_PATH')
Pierre Langlois88c46b82016-06-02 18:15:32 +0100207 if os.getenv('CCFLAGS'):
208 env.Append(CCFLAGS = os.getenv('CCFLAGS').split())
armvixldb644342015-07-21 11:37:10 +0100209 if os.getenv('CXXFLAGS'):
210 env.Append(CXXFLAGS = os.getenv('CXXFLAGS').split())
211 if os.getenv('LINKFLAGS'):
212 env.Append(LINKFLAGS = os.getenv('LINKFLAGS').split())
213 # This allows colors to be displayed when using with clang.
214 env['ENV']['TERM'] = os.getenv('TERM')
armvixl4a102ba2014-07-14 09:02:40 +0100215
216
armvixldb644342015-07-21 11:37:10 +0100217def ProcessBuildOptions(env):
218 # 'all' is unconditionally processed.
219 if 'all' in options:
220 for var in options['all']:
221 if var in env and env[var]:
222 env[var] += options['all'][var]
223 else:
224 env[var] = options['all'][var]
Pierre Langloisa3b21462016-08-04 16:01:51 +0100225
armvixldb644342015-07-21 11:37:10 +0100226 # Other build options must match 'option:value'
227 env_dict = env.Dictionary()
Pierre Langloisa3b21462016-08-04 16:01:51 +0100228
229 # First apply the default variables handlers in order.
230 for key, value in vars_default_handlers.items():
231 default = value[0]
232 handler = value[1]
233 if env_dict.get(key) == default:
234 handler(env_dict)
235
armvixldb644342015-07-21 11:37:10 +0100236 for key in env_dict.keys():
armvixldb644342015-07-21 11:37:10 +0100237 # Then update the environment according to the value of the variable.
238 key_val_couple = key + ':%s' % env_dict[key]
239 if key_val_couple in options:
240 for var in options[key_val_couple]:
241 env[var] += options[key_val_couple][var]
242
243
244def ConfigureEnvironmentForCompiler(env):
245 def is_compiler(compiler):
246 return env['CXX'].find(compiler) == 0
247 if is_compiler('clang++'):
248 # These warnings only work for Clang.
249 # -Wimplicit-fallthrough only works when compiling the code base as C++11 or
250 # newer. The compiler does not complain if the option is passed when
251 # compiling earlier C++ standards.
252 env.Append(CPPFLAGS = ['-Wimplicit-fallthrough', '-Wshorten-64-to-32'])
253
254 # The '-Wunreachable-code' flag breaks builds for clang 3.4.
255 process = subprocess.Popen(env['CXX'] + ' --version | grep "clang.*3\.4"',
256 shell = True,
257 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
258 stdout, stderr = process.communicate()
259 using_clang3_4 = stdout != ''
260 if not using_clang3_4:
261 env.Append(CPPFLAGS = ['-Wunreachable-code'])
262
Pierre Langlois88c46b82016-06-02 18:15:32 +0100263 env.Append(CPPFLAGS = ['-Wno-shorten-64-to-32'])
Pierre Langlois88c46b82016-06-02 18:15:32 +0100264
armvixldb644342015-07-21 11:37:10 +0100265 # GCC 4.8 has a bug which produces a warning saying that an anonymous Operand
266 # object might be used uninitialized:
267 # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57045
268 # The bug does not seem to appear in GCC 4.7, or in debug builds with GCC 4.8.
269 if env['mode'] == 'release':
armvixl0f35e362016-05-10 13:57:58 +0100270 process = subprocess.Popen(env['CXX'] + ' --version 2>&1 | grep "g++.*4\.8"',
armvixldb644342015-07-21 11:37:10 +0100271 shell = True,
272 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
armvixl0f35e362016-05-10 13:57:58 +0100273 stdout, unused = process.communicate()
armvixldb644342015-07-21 11:37:10 +0100274 using_gcc48 = stdout != ''
275 if using_gcc48:
276 env.Append(CPPFLAGS = ['-Wno-maybe-uninitialized'])
armvixl0f35e362016-05-10 13:57:58 +0100277 # On OSX, compilers complain about `long long` being a C++11 extension when no
278 # standard is passed.
279 if 'std' not in env or env['std'] == 'c++98':
280 env.Append(CPPFLAGS = ['-Wno-c++11-long-long'])
armvixldb644342015-07-21 11:37:10 +0100281
282
283def ConfigureEnvironment(env):
284 RetrieveEnvironmentVariables(env)
Pierre Langloisa3b21462016-08-04 16:01:51 +0100285 env['host_arch'] = util.GetHostArch(env['CXX'])
armvixldb644342015-07-21 11:37:10 +0100286 ProcessBuildOptions(env)
287 if 'std' in env:
288 env.Append(CPPFLAGS = ['-std=' + env['std']])
289 std_path = env['std']
290 ConfigureEnvironmentForCompiler(env)
291
292
293def TargetBuildDir(env):
294 # Build-time option values are embedded in the build path to avoid requiring a
295 # full build when an option changes.
296 build_dir = config.dir_build
297 for option in options_influencing_build_path:
298 option_value = env[option] if option in env else ''
299 build_dir = join(build_dir, option + '_'+ option_value)
300 return build_dir
301
302
303def PrepareVariantDir(location, build_dir):
304 location_build_dir = join(build_dir, location)
305 VariantDir(location_build_dir, location)
306 return location_build_dir
307
308
309def VIXLLibraryTarget(env):
310 build_dir = TargetBuildDir(env)
311 # Create a link to the latest build directory.
Alexandre Rames4e241932016-06-08 21:32:03 +0100312 # Use `-r` to avoid failure when `latest` exists and is a directory.
313 subprocess.check_call(["rm", "-rf", config.dir_build_latest])
armvixldb644342015-07-21 11:37:10 +0100314 util.ensure_dir(build_dir)
315 subprocess.check_call(["ln", "-s", build_dir, config.dir_build_latest])
Alexandre Ramesd3832962016-07-04 15:03:43 +0100316 # Source files are in `src` and in `src/aarch64/`.
Alexandre Rames39c32a62016-05-23 15:47:22 +0100317 variant_dir_vixl = PrepareVariantDir(join('src'), build_dir)
Pierre Langloisa3b21462016-08-04 16:01:51 +0100318 sources = [Glob(join(variant_dir_vixl, '*.cc'))]
319 if env['target_arch'] in ['aarch32', 'both']:
320 variant_dir_aarch32 = PrepareVariantDir(join('src', 'aarch32'), build_dir)
321 sources.append(Glob(join(variant_dir_aarch32, '*.cc')))
322 if env['target_arch'] in ['aarch64', 'both']:
323 variant_dir_aarch64 = PrepareVariantDir(join('src', 'aarch64'), build_dir)
324 sources.append(Glob(join(variant_dir_aarch64, '*.cc')))
armvixldb644342015-07-21 11:37:10 +0100325 return env.Library(join(build_dir, 'vixl'), sources)
326
327
328
329# Build ------------------------------------------------------------------------
330
331# The VIXL library, built by default.
332env = Environment(variables = vars)
333ConfigureEnvironment(env)
armvixldb644342015-07-21 11:37:10 +0100334Help(vars.GenerateHelpText(env))
335libvixl = VIXLLibraryTarget(env)
336Default(libvixl)
337env.Alias('libvixl', libvixl)
338top_level_targets.Add('', 'Build the VIXL library.')
339
armvixl4a102ba2014-07-14 09:02:40 +0100340
Pierre Langloisa3b21462016-08-04 16:01:51 +0100341# Common test code.
armvixldb644342015-07-21 11:37:10 +0100342test_build_dir = PrepareVariantDir('test', TargetBuildDir(env))
Pierre Langlois88c46b82016-06-02 18:15:32 +0100343test_objects = [env.Object(Glob(join(test_build_dir, '*.cc')))]
344
Pierre Langloisa3b21462016-08-04 16:01:51 +0100345# AArch32 support
346if env['target_arch'] in ['aarch32', 'both']:
347 # The examples.
348 aarch32_example_names = util.ListCCFilesWithoutExt(config.dir_aarch32_examples)
349 aarch32_examples_build_dir = PrepareVariantDir('examples/aarch32', TargetBuildDir(env))
350 aarch32_example_targets = []
351 for example in aarch32_example_names:
352 prog = env.Program(join(aarch32_examples_build_dir, example),
353 join(aarch32_examples_build_dir, example + '.cc'),
354 LIBS=[libvixl])
355 aarch32_example_targets.append(prog)
356 env.Alias('aarch32_examples', aarch32_example_targets)
357 top_level_targets.Add('aarch32_examples', 'Build the examples for AArch32.')
Pierre Langlois88c46b82016-06-02 18:15:32 +0100358
Pierre Langloisa3b21462016-08-04 16:01:51 +0100359 # The tests.
360 test_aarch32_build_dir = PrepareVariantDir(join('test', 'aarch32'), TargetBuildDir(env))
361 test_objects.append(env.Object(
362 Glob(join(test_aarch32_build_dir, '*.cc')),
363 CPPPATH = env['CPPPATH'] + [config.dir_tests]))
Pierre Langlois88c46b82016-06-02 18:15:32 +0100364
Pierre Langloisa3b21462016-08-04 16:01:51 +0100365# AArch64 support
366if env['target_arch'] in ['aarch64', 'both']:
367 # The benchmarks.
368 aarch64_benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch64_benchmarks)
369 aarch64_benchmarks_build_dir = PrepareVariantDir('benchmarks/aarch64', TargetBuildDir(env))
370 aarch64_benchmark_targets = []
371 for bench in aarch64_benchmark_names:
372 prog = env.Program(join(aarch64_benchmarks_build_dir, bench),
373 join(aarch64_benchmarks_build_dir, bench + '.cc'),
374 LIBS=[libvixl])
375 aarch64_benchmark_targets.append(prog)
376 env.Alias('aarch64_benchmarks', aarch64_benchmark_targets)
377 top_level_targets.Add('aarch64_benchmarks', 'Build the benchmarks for AArch64.')
378
379 # The examples.
380 aarch64_example_names = util.ListCCFilesWithoutExt(config.dir_aarch64_examples)
381 aarch64_examples_build_dir = PrepareVariantDir('examples/aarch64', TargetBuildDir(env))
382 aarch64_example_targets = []
383 for example in aarch64_example_names:
384 prog = env.Program(join(aarch64_examples_build_dir, example),
385 join(aarch64_examples_build_dir, example + '.cc'),
386 LIBS=[libvixl])
387 aarch64_example_targets.append(prog)
388 env.Alias('aarch64_examples', aarch64_example_targets)
389 top_level_targets.Add('aarch64_examples', 'Build the examples for AArch64.')
390
391 # The tests.
392 test_aarch64_build_dir = PrepareVariantDir(join('test', 'aarch64'), TargetBuildDir(env))
393 test_objects.append(env.Object(
394 Glob(join(test_aarch64_build_dir, '*.cc')),
395 CPPPATH = env['CPPPATH'] + [config.dir_tests]))
396
397 # The test requires building the example files with specific options, so we
398 # create a separate variant dir for the example objects built this way.
399 test_aarch64_examples_vdir = join(TargetBuildDir(env), 'test', 'aarch64', 'test_examples')
400 VariantDir(test_aarch64_examples_vdir, '.')
401 test_aarch64_examples_obj = env.Object(
402 [Glob(join(test_aarch64_examples_vdir, join('test', 'aarch64', 'examples/aarch64', '*.cc'))),
403 Glob(join(test_aarch64_examples_vdir, join('examples/aarch64', '*.cc')))],
404 CCFLAGS = env['CCFLAGS'] + ['-DTEST_EXAMPLES'],
405 CPPPATH = env['CPPPATH'] + [config.dir_aarch64_examples] + [config.dir_tests])
406 test_objects.append(test_aarch64_examples_obj)
Pierre Langlois88c46b82016-06-02 18:15:32 +0100407
408test = env.Program(join(test_build_dir, 'test-runner'), test_objects,
armvixldb644342015-07-21 11:37:10 +0100409 LIBS=[libvixl])
410env.Alias('tests', test)
411top_level_targets.Add('tests', 'Build the tests.')
armvixl4a102ba2014-07-14 09:02:40 +0100412
armvixl4a102ba2014-07-14 09:02:40 +0100413
armvixldb644342015-07-21 11:37:10 +0100414env.Alias('all', top_level_targets.targets)
415top_level_targets.Add('all', 'Build all the targets above.')
416
417Help('\n\nAvailable top level targets:\n' + top_level_targets.Help())