blob: ccde2e564df2efbaab0389fbb6af66c79c75df69 [file] [log] [blame]
armvixl5289c592015-03-02 13:52:04 +00001# Copyright 2015, ARM Limited
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
33
armvixl4a102ba2014-07-14 09:02:40 +010034root_dir = os.path.dirname(File('SConstruct').rfile().abspath)
armvixldb644342015-07-21 11:37:10 +010035sys.path.insert(0, join(root_dir, 'tools'))
36import config
armvixl4a102ba2014-07-14 09:02:40 +010037import util
38
armvixlc68cb642014-09-25 18:49:30 +010039
40Help('''
41Build system for the VIXL project.
42See README.md for documentation and details about the build system.
armvixlc68cb642014-09-25 18:49:30 +010043''')
44
45
armvixldb644342015-07-21 11:37:10 +010046# We track top-level targets to automatically generate help and alias them.
47class TopLevelTargets:
48 def __init__(self):
49 self.targets = []
50 self.help_messages = []
51 def Add(self, target, help_message):
52 self.targets.append(target)
53 self.help_messages.append(help_message)
54 def Help(self):
armvixl684cd2a2015-10-23 13:38:33 +010055 res = ""
armvixldb644342015-07-21 11:37:10 +010056 for i in range(len(self.targets)):
57 res += '\t{0:<{1}}{2:<{3}}\n'.format(
58 'scons ' + self.targets[i],
59 len('scons ') + max(map(len, self.targets)),
60 ' : ' + self.help_messages[i],
61 len(' : ') + max(map(len, self.help_messages)))
62 return res
armvixlad96eda2013-06-14 11:42:37 +010063
armvixldb644342015-07-21 11:37:10 +010064top_level_targets = TopLevelTargets()
armvixlad96eda2013-06-14 11:42:37 +010065
66
armvixldb644342015-07-21 11:37:10 +010067
68# Build options ----------------------------------------------------------------
69
70# Store all the options in a dictionary.
71# The SConstruct will check the build variables and construct the build
72# environment as appropriate.
73options = {
74 'all' : { # Unconditionally processed.
75 'CCFLAGS' : ['-Wall',
76 '-Werror',
77 '-fdiagnostics-show-option',
78 '-Wextra',
79 '-Wredundant-decls',
80 '-pedantic',
armvixl684cd2a2015-10-23 13:38:33 +010081 '-Wmissing-noreturn',
armvixldb644342015-07-21 11:37:10 +010082 '-Wwrite-strings'],
83 'CPPPATH' : [config.dir_src_vixl]
84 },
85# 'build_option:value' : {
86# 'environment_key' : 'values to append'
87# },
88 'mode:debug' : {
89 'CCFLAGS' : ['-DVIXL_DEBUG', '-O0']
90 },
91 'mode:release' : {
Pierre Langlois88c46b82016-06-02 18:15:32 +010092 'CCFLAGS' : ['-O3', '-fdata-sections', '-ffunction-sections'],
93 'LINKFLAGS' : ['-Wl,--gc-sections']
armvixldb644342015-07-21 11:37:10 +010094 },
95 'simulator:on' : {
armvixl684cd2a2015-10-23 13:38:33 +010096 'CCFLAGS' : ['-DVIXL_INCLUDE_SIMULATOR'],
armvixldb644342015-07-21 11:37:10 +010097 },
98 'symbols:on' : {
99 'CCFLAGS' : ['-g'],
100 'LINKFLAGS' : ['-g']
101 },
102 }
armvixlad96eda2013-06-14 11:42:37 +0100103
104
armvixldb644342015-07-21 11:37:10 +0100105# A `DefaultVariable` has a default value that depends on elements not known
106# when variables are first evaluated.
107# Each `DefaultVariable` has a handler that will compute the default value for
108# the given environment.
109def modifiable_flags_handler(env):
110 env['modifiable_flags'] = \
111 'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
armvixl6e2c8272015-03-31 11:04:14 +0100112
113
armvixldb644342015-07-21 11:37:10 +0100114def symbols_handler(env):
115 env['symbols'] = 'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
armvixlad96eda2013-06-14 11:42:37 +0100116
117
armvixldb644342015-07-21 11:37:10 +0100118vars_default_handlers = {
119 # variable_name : [ 'default val', 'handler' ]
120 'symbols' : [ 'mode==debug', symbols_handler ],
121 'modifiable_flags' : [ 'mode==debug', modifiable_flags_handler ]
122 }
123
124
125def DefaultVariable(name, help, allowed):
126 default_value = vars_default_handlers[name][0]
127 allowed.append(default_value)
128 return EnumVariable(name, help, default_value, allowed)
129
130
131vars = Variables()
132# Define command line build options.
armvixlc68cb642014-09-25 18:49:30 +0100133sim_default = 'off' if platform.machine() == 'aarch64' else 'on'
armvixldb644342015-07-21 11:37:10 +0100134vars.AddVariables(
135 EnumVariable('mode', 'Build mode',
136 'release', allowed_values=config.build_options_modes),
137 DefaultVariable('symbols', 'Include debugging symbols in the binaries',
138 ['on', 'off']),
139 EnumVariable('simulator', 'Build for the simulator',
140 sim_default, allowed_values=['on', 'off']),
141 ('std', 'C++ standard. The standards tested are: %s.' % \
142 ', '.join(config.tested_cpp_standards))
143 )
armvixlad96eda2013-06-14 11:42:37 +0100144
armvixldb644342015-07-21 11:37:10 +0100145# Abort the build if any command line option is unknown or invalid.
146unknown_build_options = vars.UnknownVariables()
147if unknown_build_options:
148 print 'Unknown build options:', unknown_build_options.keys()
149 Exit(1)
armvixlad96eda2013-06-14 11:42:37 +0100150
armvixldb644342015-07-21 11:37:10 +0100151# We use 'variant directories' to avoid recompiling multiple times when build
152# options are changed, different build paths are used depending on the options
153# set. These are the options that should be reflected in the build directory
154# path.
155options_influencing_build_path = ['mode', 'symbols', 'CXX', 'std', 'simulator']
armvixlad96eda2013-06-14 11:42:37 +0100156
armvixlad96eda2013-06-14 11:42:37 +0100157
armvixldb644342015-07-21 11:37:10 +0100158
159# Build helpers ----------------------------------------------------------------
160
161def RetrieveEnvironmentVariables(env):
Pierre Langlois88c46b82016-06-02 18:15:32 +0100162 for key in ['CC', 'CXX', 'AR', 'RANLIB', 'LD']:
armvixldb644342015-07-21 11:37:10 +0100163 if os.getenv(key): env[key] = os.getenv(key)
164 if os.getenv('LD_LIBRARY_PATH'): env['LIBPATH'] = os.getenv('LD_LIBRARY_PATH')
Pierre Langlois88c46b82016-06-02 18:15:32 +0100165 if os.getenv('CCFLAGS'):
166 env.Append(CCFLAGS = os.getenv('CCFLAGS').split())
armvixldb644342015-07-21 11:37:10 +0100167 if os.getenv('CXXFLAGS'):
168 env.Append(CXXFLAGS = os.getenv('CXXFLAGS').split())
169 if os.getenv('LINKFLAGS'):
170 env.Append(LINKFLAGS = os.getenv('LINKFLAGS').split())
171 # This allows colors to be displayed when using with clang.
172 env['ENV']['TERM'] = os.getenv('TERM')
armvixl4a102ba2014-07-14 09:02:40 +0100173
174
armvixldb644342015-07-21 11:37:10 +0100175def ProcessBuildOptions(env):
176 # 'all' is unconditionally processed.
177 if 'all' in options:
178 for var in options['all']:
179 if var in env and env[var]:
180 env[var] += options['all'][var]
181 else:
182 env[var] = options['all'][var]
183 # Other build options must match 'option:value'
184 env_dict = env.Dictionary()
185 for key in env_dict.keys():
186 # First apply the default variables handlers.
187 if key in vars_default_handlers and \
188 env_dict[key] == vars_default_handlers[key][0]:
189 vars_default_handlers[key][1](env_dict)
190 # Then update the environment according to the value of the variable.
191 key_val_couple = key + ':%s' % env_dict[key]
192 if key_val_couple in options:
193 for var in options[key_val_couple]:
194 env[var] += options[key_val_couple][var]
195
196
197def ConfigureEnvironmentForCompiler(env):
198 def is_compiler(compiler):
199 return env['CXX'].find(compiler) == 0
200 if is_compiler('clang++'):
201 # These warnings only work for Clang.
202 # -Wimplicit-fallthrough only works when compiling the code base as C++11 or
203 # newer. The compiler does not complain if the option is passed when
204 # compiling earlier C++ standards.
205 env.Append(CPPFLAGS = ['-Wimplicit-fallthrough', '-Wshorten-64-to-32'])
206
207 # The '-Wunreachable-code' flag breaks builds for clang 3.4.
208 process = subprocess.Popen(env['CXX'] + ' --version | grep "clang.*3\.4"',
209 shell = True,
210 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
211 stdout, stderr = process.communicate()
212 using_clang3_4 = stdout != ''
213 if not using_clang3_4:
214 env.Append(CPPFLAGS = ['-Wunreachable-code'])
215
Pierre Langlois88c46b82016-06-02 18:15:32 +0100216 env.Append(CPPFLAGS = ['-Wno-unreachable-code'])
217 env.Append(CPPFLAGS = ['-Wno-shorten-64-to-32'])
218 env.Append(CPPFLAGS = ['-Wno-missing-noreturn'])
219 env.Append(CPPFLAGS = ['-Wno-unused-private-field'])
220 env.Append(CPPFLAGS = ['-Wno-implicit-fallthrough'])
221 env.Append(CPPFLAGS = ['-Wno-sometimes-uninitialized'])
222
armvixldb644342015-07-21 11:37:10 +0100223 # GCC 4.8 has a bug which produces a warning saying that an anonymous Operand
224 # object might be used uninitialized:
225 # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57045
226 # The bug does not seem to appear in GCC 4.7, or in debug builds with GCC 4.8.
227 if env['mode'] == 'release':
armvixl0f35e362016-05-10 13:57:58 +0100228 process = subprocess.Popen(env['CXX'] + ' --version 2>&1 | grep "g++.*4\.8"',
armvixldb644342015-07-21 11:37:10 +0100229 shell = True,
230 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
armvixl0f35e362016-05-10 13:57:58 +0100231 stdout, unused = process.communicate()
armvixldb644342015-07-21 11:37:10 +0100232 using_gcc48 = stdout != ''
233 if using_gcc48:
234 env.Append(CPPFLAGS = ['-Wno-maybe-uninitialized'])
armvixl0f35e362016-05-10 13:57:58 +0100235 # On OSX, compilers complain about `long long` being a C++11 extension when no
236 # standard is passed.
237 if 'std' not in env or env['std'] == 'c++98':
238 env.Append(CPPFLAGS = ['-Wno-c++11-long-long'])
armvixldb644342015-07-21 11:37:10 +0100239
Pierre Langlois88c46b82016-06-02 18:15:32 +0100240 # The generated macro assembler contains uninitialized variables and
241 # GCC cannot prove that they are always initialised, even though it
242 # should.
243 if env['mode'] == 'release' and is_compiler('g++'):
244 env.Append(CPPFLAGS = ['-Wno-maybe-uninitialized'])
245
armvixldb644342015-07-21 11:37:10 +0100246
247def ConfigureEnvironment(env):
248 RetrieveEnvironmentVariables(env)
249 ProcessBuildOptions(env)
250 if 'std' in env:
251 env.Append(CPPFLAGS = ['-std=' + env['std']])
252 std_path = env['std']
253 ConfigureEnvironmentForCompiler(env)
254
255
256def TargetBuildDir(env):
257 # Build-time option values are embedded in the build path to avoid requiring a
258 # full build when an option changes.
259 build_dir = config.dir_build
260 for option in options_influencing_build_path:
261 option_value = env[option] if option in env else ''
262 build_dir = join(build_dir, option + '_'+ option_value)
263 return build_dir
264
265
266def PrepareVariantDir(location, build_dir):
267 location_build_dir = join(build_dir, location)
268 VariantDir(location_build_dir, location)
269 return location_build_dir
270
271
272def VIXLLibraryTarget(env):
273 build_dir = TargetBuildDir(env)
274 # Create a link to the latest build directory.
Alexandre Rames4e241932016-06-08 21:32:03 +0100275 # Use `-r` to avoid failure when `latest` exists and is a directory.
276 subprocess.check_call(["rm", "-rf", config.dir_build_latest])
armvixldb644342015-07-21 11:37:10 +0100277 util.ensure_dir(build_dir)
278 subprocess.check_call(["ln", "-s", build_dir, config.dir_build_latest])
Alexandre Rames39c32a62016-05-23 15:47:22 +0100279 # Source files are in `src` and in `src/a64/`.
280 variant_dir_vixl = PrepareVariantDir(join('src'), build_dir)
Pierre Langlois88c46b82016-06-02 18:15:32 +0100281 variant_dir_a32 = PrepareVariantDir(join('src', 'a32'), build_dir)
Alexandre Rames39c32a62016-05-23 15:47:22 +0100282 variant_dir_a64 = PrepareVariantDir(join('src', 'a64'), build_dir)
armvixldb644342015-07-21 11:37:10 +0100283 sources = [Glob(join(variant_dir_vixl, '*.cc')),
Pierre Langlois88c46b82016-06-02 18:15:32 +0100284 Glob(join(variant_dir_a32, '*.cc')),
armvixldb644342015-07-21 11:37:10 +0100285 Glob(join(variant_dir_a64, '*.cc'))]
286 return env.Library(join(build_dir, 'vixl'), sources)
287
288
289
290# Build ------------------------------------------------------------------------
291
292# The VIXL library, built by default.
293env = Environment(variables = vars)
294ConfigureEnvironment(env)
armvixldb644342015-07-21 11:37:10 +0100295Help(vars.GenerateHelpText(env))
296libvixl = VIXLLibraryTarget(env)
297Default(libvixl)
298env.Alias('libvixl', libvixl)
299top_level_targets.Add('', 'Build the VIXL library.')
300
armvixl4a102ba2014-07-14 09:02:40 +0100301
302# The benchmarks.
Pierre Langlois88c46b82016-06-02 18:15:32 +0100303a64_benchmark_names = util.ListCCFilesWithoutExt(config.dir_a64_benchmarks)
304a64_benchmarks_build_dir = PrepareVariantDir('benchmarks/a64', TargetBuildDir(env))
305a64_benchmark_targets = []
306for bench in a64_benchmark_names:
307 prog = env.Program(join(a64_benchmarks_build_dir, bench),
308 join(a64_benchmarks_build_dir, bench + '.cc'),
armvixldb644342015-07-21 11:37:10 +0100309 LIBS=[libvixl])
Pierre Langlois88c46b82016-06-02 18:15:32 +0100310 a64_benchmark_targets.append(prog)
311env.Alias('a64_benchmarks', a64_benchmark_targets)
312top_level_targets.Add('a64_benchmarks', 'Build the benchmarks for AArch64.')
armvixldb644342015-07-21 11:37:10 +0100313
armvixl4a102ba2014-07-14 09:02:40 +0100314
315# The examples.
Pierre Langlois88c46b82016-06-02 18:15:32 +0100316a64_example_names = util.ListCCFilesWithoutExt(config.dir_a64_examples)
317a64_examples_build_dir = PrepareVariantDir('examples/a64', TargetBuildDir(env))
318a64_example_targets = []
319for example in a64_example_names:
320 prog = env.Program(join(a64_examples_build_dir, example),
321 join(a64_examples_build_dir, example + '.cc'),
armvixldb644342015-07-21 11:37:10 +0100322 LIBS=[libvixl])
Pierre Langlois88c46b82016-06-02 18:15:32 +0100323 a64_example_targets.append(prog)
324env.Alias('a64_examples', a64_example_targets)
325top_level_targets.Add('a64_examples', 'Build the examples for AArch64.')
326a32_example_names = util.ListCCFilesWithoutExt(config.dir_a32_examples)
327a32_examples_build_dir = PrepareVariantDir('examples/a32', TargetBuildDir(env))
328a32_example_targets = []
329for example in a32_example_names:
330 prog = env.Program(join(a32_examples_build_dir, example),
331 join(a32_examples_build_dir, example + '.cc'),
332 LIBS=[libvixl])
333 a32_example_targets.append(prog)
334env.Alias('a32_examples', a32_example_targets)
335top_level_targets.Add('a32_examples', 'Build the examples for AArch32.')
armvixl4a102ba2014-07-14 09:02:40 +0100336
337
armvixldb644342015-07-21 11:37:10 +0100338# The tests.
339test_build_dir = PrepareVariantDir('test', TargetBuildDir(env))
Pierre Langlois88c46b82016-06-02 18:15:32 +0100340test_objects = [env.Object(Glob(join(test_build_dir, '*.cc')))]
341
342test_a32_build_dir = PrepareVariantDir(join('test', 'a32'), TargetBuildDir(env))
343test_objects.append(env.Object(
344 Glob(join(test_a32_build_dir, '*.cc')),
345 CPPPATH = env['CPPPATH'] + [config.dir_tests]))
346
347test_a64_build_dir = PrepareVariantDir(join('test', 'a64'), TargetBuildDir(env))
348test_objects.append(env.Object(
349 Glob(join(test_a64_build_dir, '*.cc')),
350 CPPPATH = env['CPPPATH'] + [config.dir_tests]))
351
armvixldb644342015-07-21 11:37:10 +0100352# The test requires building the example files with specific options, so we
353# create a separate variant dir for the example objects built this way.
Pierre Langlois88c46b82016-06-02 18:15:32 +0100354test_a64_examples_vdir = join(TargetBuildDir(env), 'test', 'a64', 'test_examples')
355VariantDir(test_a64_examples_vdir, '.')
356test_a64_examples_obj = env.Object(
357 [Glob(join(test_a64_examples_vdir, join('test', 'a64', 'examples/a64', '*.cc'))),
358 Glob(join(test_a64_examples_vdir, join('examples/a64', '*.cc')))],
armvixldb644342015-07-21 11:37:10 +0100359 CCFLAGS = env['CCFLAGS'] + ['-DTEST_EXAMPLES'],
Pierre Langlois88c46b82016-06-02 18:15:32 +0100360 CPPPATH = env['CPPPATH'] + [config.dir_a64_examples] + [config.dir_tests])
361test_objects.append(test_a64_examples_obj)
362
363test = env.Program(join(test_build_dir, 'test-runner'), test_objects,
armvixldb644342015-07-21 11:37:10 +0100364 LIBS=[libvixl])
365env.Alias('tests', test)
366top_level_targets.Add('tests', 'Build the tests.')
armvixl4a102ba2014-07-14 09:02:40 +0100367
armvixl4a102ba2014-07-14 09:02:40 +0100368
armvixldb644342015-07-21 11:37:10 +0100369env.Alias('all', top_level_targets.targets)
370top_level_targets.Add('all', 'Build all the targets above.')
371
372Help('\n\nAvailable top level targets:\n' + top_level_targets.Help())