mirror of
https://github.com/openharmony/third_party_vixl.git
synced 2026-07-01 20:54:04 -04:00
b78f13911b
Change-Id: Ifb505e5664996c1af41e38376e58ba49864213a3
373 lines
14 KiB
Python
373 lines
14 KiB
Python
# Copyright 2015, VIXL authors
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright notice,
|
|
# this list of conditions and the following disclaimer.
|
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
# this list of conditions and the following disclaimer in the documentation
|
|
# and/or other materials provided with the distribution.
|
|
# * Neither the name of ARM Limited nor the names of its contributors may be
|
|
# used to endorse or promote products derived from this software without
|
|
# specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import glob
|
|
import os
|
|
from os.path import join
|
|
import platform
|
|
import subprocess
|
|
import sys
|
|
|
|
root_dir = os.path.dirname(File('SConstruct').rfile().abspath)
|
|
sys.path.insert(0, join(root_dir, 'tools'))
|
|
import config
|
|
import util
|
|
|
|
|
|
Help('''
|
|
Build system for the VIXL project.
|
|
See README.md for documentation and details about the build system.
|
|
''')
|
|
|
|
|
|
# We track top-level targets to automatically generate help and alias them.
|
|
class TopLevelTargets:
|
|
def __init__(self):
|
|
self.targets = []
|
|
self.help_messages = []
|
|
def Add(self, target, help_message):
|
|
self.targets.append(target)
|
|
self.help_messages.append(help_message)
|
|
def Help(self):
|
|
res = ""
|
|
for i in range(len(self.targets)):
|
|
res += '\t{0:<{1}}{2:<{3}}\n'.format(
|
|
'scons ' + self.targets[i],
|
|
len('scons ') + max(map(len, self.targets)),
|
|
' : ' + self.help_messages[i],
|
|
len(' : ') + max(map(len, self.help_messages)))
|
|
return res
|
|
|
|
top_level_targets = TopLevelTargets()
|
|
|
|
|
|
|
|
# Build options ----------------------------------------------------------------
|
|
|
|
# Store all the options in a dictionary.
|
|
# The SConstruct will check the build variables and construct the build
|
|
# environment as appropriate.
|
|
options = {
|
|
'all' : { # Unconditionally processed.
|
|
'CCFLAGS' : ['-Wall',
|
|
'-Werror',
|
|
'-fdiagnostics-show-option',
|
|
'-Wextra',
|
|
'-Wredundant-decls',
|
|
'-pedantic',
|
|
'-Wmissing-noreturn',
|
|
'-Wwrite-strings'],
|
|
'CPPPATH' : [config.dir_src_vixl]
|
|
},
|
|
# 'build_option:value' : {
|
|
# 'environment_key' : 'values to append'
|
|
# },
|
|
'mode:debug' : {
|
|
'CCFLAGS' : ['-DVIXL_DEBUG', '-O0']
|
|
},
|
|
'mode:release' : {
|
|
'CCFLAGS' : ['-O3', '-fdata-sections', '-ffunction-sections'],
|
|
'LINKFLAGS' : ['-Wl,--gc-sections']
|
|
},
|
|
'simulator:on' : {
|
|
'CCFLAGS' : ['-DVIXL_INCLUDE_SIMULATOR'],
|
|
},
|
|
'symbols:on' : {
|
|
'CCFLAGS' : ['-g'],
|
|
'LINKFLAGS' : ['-g']
|
|
},
|
|
}
|
|
|
|
|
|
# A `DefaultVariable` has a default value that depends on elements not known
|
|
# when variables are first evaluated.
|
|
# Each `DefaultVariable` has a handler that will compute the default value for
|
|
# the given environment.
|
|
def modifiable_flags_handler(env):
|
|
env['modifiable_flags'] = \
|
|
'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
|
|
|
|
|
|
def symbols_handler(env):
|
|
env['symbols'] = 'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
|
|
|
|
|
|
vars_default_handlers = {
|
|
# variable_name : [ 'default val', 'handler' ]
|
|
'symbols' : [ 'mode==debug', symbols_handler ],
|
|
'modifiable_flags' : [ 'mode==debug', modifiable_flags_handler ]
|
|
}
|
|
|
|
|
|
def DefaultVariable(name, help, allowed):
|
|
default_value = vars_default_handlers[name][0]
|
|
allowed.append(default_value)
|
|
return EnumVariable(name, help, default_value, allowed)
|
|
|
|
|
|
vars = Variables()
|
|
# Define command line build options.
|
|
sim_default = 'off' if platform.machine() == 'aarch64' else 'on'
|
|
vars.AddVariables(
|
|
EnumVariable('mode', 'Build mode',
|
|
'release', allowed_values=config.build_options_modes),
|
|
DefaultVariable('symbols', 'Include debugging symbols in the binaries',
|
|
['on', 'off']),
|
|
EnumVariable('simulator', 'Build for the simulator',
|
|
sim_default, allowed_values=['on', 'off']),
|
|
('std', 'C++ standard. The standards tested are: %s.' % \
|
|
', '.join(config.tested_cpp_standards))
|
|
)
|
|
|
|
# Abort the build if any command line option is unknown or invalid.
|
|
unknown_build_options = vars.UnknownVariables()
|
|
if unknown_build_options:
|
|
print 'Unknown build options:', unknown_build_options.keys()
|
|
Exit(1)
|
|
|
|
# We use 'variant directories' to avoid recompiling multiple times when build
|
|
# options are changed, different build paths are used depending on the options
|
|
# set. These are the options that should be reflected in the build directory
|
|
# path.
|
|
options_influencing_build_path = ['mode', 'symbols', 'CXX', 'std', 'simulator']
|
|
|
|
|
|
|
|
# Build helpers ----------------------------------------------------------------
|
|
|
|
def RetrieveEnvironmentVariables(env):
|
|
for key in ['CC', 'CXX', 'AR', 'RANLIB', 'LD']:
|
|
if os.getenv(key): env[key] = os.getenv(key)
|
|
if os.getenv('LD_LIBRARY_PATH'): env['LIBPATH'] = os.getenv('LD_LIBRARY_PATH')
|
|
if os.getenv('CCFLAGS'):
|
|
env.Append(CCFLAGS = os.getenv('CCFLAGS').split())
|
|
if os.getenv('CXXFLAGS'):
|
|
env.Append(CXXFLAGS = os.getenv('CXXFLAGS').split())
|
|
if os.getenv('LINKFLAGS'):
|
|
env.Append(LINKFLAGS = os.getenv('LINKFLAGS').split())
|
|
# This allows colors to be displayed when using with clang.
|
|
env['ENV']['TERM'] = os.getenv('TERM')
|
|
|
|
|
|
def ProcessBuildOptions(env):
|
|
# 'all' is unconditionally processed.
|
|
if 'all' in options:
|
|
for var in options['all']:
|
|
if var in env and env[var]:
|
|
env[var] += options['all'][var]
|
|
else:
|
|
env[var] = options['all'][var]
|
|
# Other build options must match 'option:value'
|
|
env_dict = env.Dictionary()
|
|
for key in env_dict.keys():
|
|
# First apply the default variables handlers.
|
|
if key in vars_default_handlers and \
|
|
env_dict[key] == vars_default_handlers[key][0]:
|
|
vars_default_handlers[key][1](env_dict)
|
|
# Then update the environment according to the value of the variable.
|
|
key_val_couple = key + ':%s' % env_dict[key]
|
|
if key_val_couple in options:
|
|
for var in options[key_val_couple]:
|
|
env[var] += options[key_val_couple][var]
|
|
|
|
|
|
def ConfigureEnvironmentForCompiler(env):
|
|
def is_compiler(compiler):
|
|
return env['CXX'].find(compiler) == 0
|
|
if is_compiler('clang++'):
|
|
# These warnings only work for Clang.
|
|
# -Wimplicit-fallthrough only works when compiling the code base as C++11 or
|
|
# newer. The compiler does not complain if the option is passed when
|
|
# compiling earlier C++ standards.
|
|
env.Append(CPPFLAGS = ['-Wimplicit-fallthrough', '-Wshorten-64-to-32'])
|
|
|
|
# The '-Wunreachable-code' flag breaks builds for clang 3.4.
|
|
process = subprocess.Popen(env['CXX'] + ' --version | grep "clang.*3\.4"',
|
|
shell = True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
stdout, stderr = process.communicate()
|
|
using_clang3_4 = stdout != ''
|
|
if not using_clang3_4:
|
|
env.Append(CPPFLAGS = ['-Wunreachable-code'])
|
|
|
|
env.Append(CPPFLAGS = ['-Wno-unreachable-code'])
|
|
env.Append(CPPFLAGS = ['-Wno-shorten-64-to-32'])
|
|
env.Append(CPPFLAGS = ['-Wno-missing-noreturn'])
|
|
env.Append(CPPFLAGS = ['-Wno-unused-private-field'])
|
|
env.Append(CPPFLAGS = ['-Wno-implicit-fallthrough'])
|
|
env.Append(CPPFLAGS = ['-Wno-sometimes-uninitialized'])
|
|
|
|
# GCC 4.8 has a bug which produces a warning saying that an anonymous Operand
|
|
# object might be used uninitialized:
|
|
# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57045
|
|
# The bug does not seem to appear in GCC 4.7, or in debug builds with GCC 4.8.
|
|
if env['mode'] == 'release':
|
|
process = subprocess.Popen(env['CXX'] + ' --version 2>&1 | grep "g++.*4\.8"',
|
|
shell = True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
stdout, unused = process.communicate()
|
|
using_gcc48 = stdout != ''
|
|
if using_gcc48:
|
|
env.Append(CPPFLAGS = ['-Wno-maybe-uninitialized'])
|
|
# On OSX, compilers complain about `long long` being a C++11 extension when no
|
|
# standard is passed.
|
|
if 'std' not in env or env['std'] == 'c++98':
|
|
env.Append(CPPFLAGS = ['-Wno-c++11-long-long'])
|
|
|
|
# The generated macro assembler contains uninitialized variables and
|
|
# GCC cannot prove that they are always initialised, even though it
|
|
# should.
|
|
if env['mode'] == 'release' and is_compiler('g++'):
|
|
env.Append(CPPFLAGS = ['-Wno-maybe-uninitialized'])
|
|
|
|
|
|
def ConfigureEnvironment(env):
|
|
RetrieveEnvironmentVariables(env)
|
|
ProcessBuildOptions(env)
|
|
if 'std' in env:
|
|
env.Append(CPPFLAGS = ['-std=' + env['std']])
|
|
std_path = env['std']
|
|
ConfigureEnvironmentForCompiler(env)
|
|
|
|
|
|
def TargetBuildDir(env):
|
|
# Build-time option values are embedded in the build path to avoid requiring a
|
|
# full build when an option changes.
|
|
build_dir = config.dir_build
|
|
for option in options_influencing_build_path:
|
|
option_value = env[option] if option in env else ''
|
|
build_dir = join(build_dir, option + '_'+ option_value)
|
|
return build_dir
|
|
|
|
|
|
def PrepareVariantDir(location, build_dir):
|
|
location_build_dir = join(build_dir, location)
|
|
VariantDir(location_build_dir, location)
|
|
return location_build_dir
|
|
|
|
|
|
def VIXLLibraryTarget(env):
|
|
build_dir = TargetBuildDir(env)
|
|
# Create a link to the latest build directory.
|
|
# Use `-r` to avoid failure when `latest` exists and is a directory.
|
|
subprocess.check_call(["rm", "-rf", config.dir_build_latest])
|
|
util.ensure_dir(build_dir)
|
|
subprocess.check_call(["ln", "-s", build_dir, config.dir_build_latest])
|
|
# Source files are in `src` and in `src/a64/`.
|
|
variant_dir_vixl = PrepareVariantDir(join('src'), build_dir)
|
|
variant_dir_a32 = PrepareVariantDir(join('src', 'a32'), build_dir)
|
|
variant_dir_a64 = PrepareVariantDir(join('src', 'a64'), build_dir)
|
|
sources = [Glob(join(variant_dir_vixl, '*.cc')),
|
|
Glob(join(variant_dir_a32, '*.cc')),
|
|
Glob(join(variant_dir_a64, '*.cc'))]
|
|
return env.Library(join(build_dir, 'vixl'), sources)
|
|
|
|
|
|
|
|
# Build ------------------------------------------------------------------------
|
|
|
|
# The VIXL library, built by default.
|
|
env = Environment(variables = vars)
|
|
ConfigureEnvironment(env)
|
|
Help(vars.GenerateHelpText(env))
|
|
libvixl = VIXLLibraryTarget(env)
|
|
Default(libvixl)
|
|
env.Alias('libvixl', libvixl)
|
|
top_level_targets.Add('', 'Build the VIXL library.')
|
|
|
|
|
|
# The benchmarks.
|
|
a64_benchmark_names = util.ListCCFilesWithoutExt(config.dir_a64_benchmarks)
|
|
a64_benchmarks_build_dir = PrepareVariantDir('benchmarks/a64', TargetBuildDir(env))
|
|
a64_benchmark_targets = []
|
|
for bench in a64_benchmark_names:
|
|
prog = env.Program(join(a64_benchmarks_build_dir, bench),
|
|
join(a64_benchmarks_build_dir, bench + '.cc'),
|
|
LIBS=[libvixl])
|
|
a64_benchmark_targets.append(prog)
|
|
env.Alias('a64_benchmarks', a64_benchmark_targets)
|
|
top_level_targets.Add('a64_benchmarks', 'Build the benchmarks for AArch64.')
|
|
|
|
|
|
# The examples.
|
|
a64_example_names = util.ListCCFilesWithoutExt(config.dir_a64_examples)
|
|
a64_examples_build_dir = PrepareVariantDir('examples/a64', TargetBuildDir(env))
|
|
a64_example_targets = []
|
|
for example in a64_example_names:
|
|
prog = env.Program(join(a64_examples_build_dir, example),
|
|
join(a64_examples_build_dir, example + '.cc'),
|
|
LIBS=[libvixl])
|
|
a64_example_targets.append(prog)
|
|
env.Alias('a64_examples', a64_example_targets)
|
|
top_level_targets.Add('a64_examples', 'Build the examples for AArch64.')
|
|
a32_example_names = util.ListCCFilesWithoutExt(config.dir_a32_examples)
|
|
a32_examples_build_dir = PrepareVariantDir('examples/a32', TargetBuildDir(env))
|
|
a32_example_targets = []
|
|
for example in a32_example_names:
|
|
prog = env.Program(join(a32_examples_build_dir, example),
|
|
join(a32_examples_build_dir, example + '.cc'),
|
|
LIBS=[libvixl])
|
|
a32_example_targets.append(prog)
|
|
env.Alias('a32_examples', a32_example_targets)
|
|
top_level_targets.Add('a32_examples', 'Build the examples for AArch32.')
|
|
|
|
|
|
# The tests.
|
|
test_build_dir = PrepareVariantDir('test', TargetBuildDir(env))
|
|
test_objects = [env.Object(Glob(join(test_build_dir, '*.cc')))]
|
|
|
|
test_a32_build_dir = PrepareVariantDir(join('test', 'a32'), TargetBuildDir(env))
|
|
test_objects.append(env.Object(
|
|
Glob(join(test_a32_build_dir, '*.cc')),
|
|
CPPPATH = env['CPPPATH'] + [config.dir_tests]))
|
|
|
|
test_a64_build_dir = PrepareVariantDir(join('test', 'a64'), TargetBuildDir(env))
|
|
test_objects.append(env.Object(
|
|
Glob(join(test_a64_build_dir, '*.cc')),
|
|
CPPPATH = env['CPPPATH'] + [config.dir_tests]))
|
|
|
|
# The test requires building the example files with specific options, so we
|
|
# create a separate variant dir for the example objects built this way.
|
|
test_a64_examples_vdir = join(TargetBuildDir(env), 'test', 'a64', 'test_examples')
|
|
VariantDir(test_a64_examples_vdir, '.')
|
|
test_a64_examples_obj = env.Object(
|
|
[Glob(join(test_a64_examples_vdir, join('test', 'a64', 'examples/a64', '*.cc'))),
|
|
Glob(join(test_a64_examples_vdir, join('examples/a64', '*.cc')))],
|
|
CCFLAGS = env['CCFLAGS'] + ['-DTEST_EXAMPLES'],
|
|
CPPPATH = env['CPPPATH'] + [config.dir_a64_examples] + [config.dir_tests])
|
|
test_objects.append(test_a64_examples_obj)
|
|
|
|
test = env.Program(join(test_build_dir, 'test-runner'), test_objects,
|
|
LIBS=[libvixl])
|
|
env.Alias('tests', test)
|
|
top_level_targets.Add('tests', 'Build the tests.')
|
|
|
|
|
|
env.Alias('all', top_level_targets.targets)
|
|
top_level_targets.Add('all', 'Build all the targets above.')
|
|
|
|
Help('\n\nAvailable top level targets:\n' + top_level_targets.Help())
|