Home | History | Annotate | Download | only in vixl
      1 # Copyright 2015, ARM Limited
      2 # 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 
     27 import os
     28 import os.path
     29 import platform
     30 import subprocess
     31 import sys
     32 
     33 root_dir = os.path.dirname(File('SConstruct').rfile().abspath)
     34 sys.path.insert(0, os.path.join(root_dir, 'tools'))
     35 import util
     36 
     37 
     38 Help('''
     39 Build system for the VIXL project.
     40 See README.md for documentation and details about the build system.
     41 Some common build targets are:
     42     scons            # Build the VIXL library and test utility.
     43     scons examples   # Build all the examples.
     44     scons all        # Build everything.
     45 
     46 ''')
     47 
     48 
     49 # Global configuration.
     50 PROJ_SRC_DIR   = 'src'
     51 PROJ_SRC_FILES = '''
     52 src/vixl/a64/assembler-a64.cc
     53 src/vixl/a64/cpu-a64.cc
     54 src/vixl/a64/debugger-a64.cc
     55 src/vixl/a64/decoder-a64.cc
     56 src/vixl/a64/disasm-a64.cc
     57 src/vixl/a64/instructions-a64.cc
     58 src/vixl/a64/instrument-a64.cc
     59 src/vixl/a64/logic-a64.cc
     60 src/vixl/a64/macro-assembler-a64.cc
     61 src/vixl/a64/simulator-a64.cc
     62 src/vixl/code-buffer.cc
     63 src/vixl/compiler-intrinsics.cc
     64 src/vixl/utils.cc
     65 '''.split()
     66 PROJ_EXAMPLES_DIR = 'examples'
     67 PROJ_EXAMPLES_SRC_FILES = '''
     68 examples/abs.cc
     69 examples/add2-vectors.cc
     70 examples/add3-double.cc
     71 examples/add4-double.cc
     72 examples/check-bounds.cc
     73 examples/crc-checksums.cc
     74 examples/custom-disassembler.cc
     75 examples/debugger.cc
     76 examples/factorial-rec.cc
     77 examples/factorial.cc
     78 examples/neon-matrix-multiply.cc
     79 examples/getting-started.cc
     80 examples/non-const-visitor.cc
     81 examples/sum-array.cc
     82 examples/swap-int32.cc
     83 examples/swap4.cc
     84 '''.split()
     85 # List target specific files.
     86 # Target names are used as dictionary entries.
     87 TARGET_SRC_DIR = {
     88   'test': 'test',
     89   'bench-dataop': 'benchmarks',
     90   'bench-branch': 'benchmarks',
     91   'bench-branch-link': 'benchmarks',
     92   'bench-branch-masm': 'benchmarks',
     93   'bench-branch-link-masm': 'benchmarks',
     94   'examples': 'examples'
     95 }
     96 TARGET_SRC_FILES = {
     97   'test': '''
     98     test/test-runner.cc
     99     test/examples/test-examples.cc
    100     test/test-assembler-a64.cc
    101     test/test-disasm-a64.cc
    102     test/test-fuzz-a64.cc
    103     test/test-invalset.cc
    104     test/test-simulator-a64.cc
    105     test/test-utils-a64.cc
    106     '''.split(),
    107   'bench-dataop': '''
    108     benchmarks/bench-dataop.cc
    109     '''.split(),
    110   'bench-branch': '''
    111     benchmarks/bench-branch.cc
    112     '''.split(),
    113   'bench-branch-link': '''
    114     benchmarks/bench-branch-link.cc
    115     '''.split(),
    116   'bench-branch-masm': '''
    117     benchmarks/bench-branch-masm.cc
    118     '''.split(),
    119   'bench-branch-link-masm': '''
    120     benchmarks/bench-branch-link-masm.cc
    121     '''.split()
    122 }
    123 OBJ_DIR  = 'obj'
    124 
    125 # Helper functions.
    126 def abort(message):
    127   print('ABORTING: ' + message)
    128   sys.exit(1)
    129 
    130 
    131 def list_target(obj_dir, src_files):
    132   return map(lambda x: os.path.join(obj_dir, x), src_files)
    133 
    134 
    135 def is_compiler(compiler):
    136   return env['CXX'].find(compiler) == 0
    137 
    138 
    139 def create_variant(obj_dir, targets_dir):
    140   VariantDir(os.path.join(obj_dir, PROJ_SRC_DIR), PROJ_SRC_DIR)
    141   for directory in targets_dir.itervalues():
    142     VariantDir(os.path.join(obj_dir, directory), directory)
    143 
    144 
    145 # Build arguments.
    146 args = Variables()
    147 args.Add(EnumVariable('mode', 'Build mode', 'release',
    148                       allowed_values = ['release', 'debug']))
    149 sim_default = 'off' if platform.machine() == 'aarch64' else 'on'
    150 args.Add(EnumVariable('simulator', 'build for the simulator', sim_default,
    151                       allowed_values = ['on', 'off']))
    152 args.Add('std', 'c++ standard')
    153 
    154 # Configure the environment.
    155 env = Environment(variables=args)
    156 
    157 # Commandline help.
    158 Help(args.GenerateHelpText(env) + '\n')
    159 
    160 # Abort if any invalid argument was passed.
    161 # This check must happened after an environment is created.
    162 unknown_arg = args.UnknownVariables()
    163 if unknown_arg:
    164   abort('Unknown variable(s): ' + str(unknown_arg.keys()))
    165 
    166 # Setup tools.
    167 # This is necessary for cross-compilation.
    168 env['CXX'] = os.environ.get('CXX', env.get('CXX'))
    169 env['AR'] = os.environ.get('AR', env.get('AR'))
    170 env['RANLIB'] = os.environ.get('RANLIB', env.get('RANLIB'))
    171 env['CC'] = os.environ.get('CC', env.get('CC'))
    172 env['LD'] = os.environ.get('LD', env.get('LD'))
    173 
    174 if os.environ.get('CPPFLAGS'):
    175   env.Append(CPPFLAGS = os.environ.get('CPPFLAGS').split())
    176 if os.environ.get('LINKFLAGS'):
    177   env.Append(LINKFLAGS = os.environ.get('LINKFLAGS').split())
    178 
    179 # Always look in 'src' for include files.
    180 # TODO: Restore the '-Wunreachable-code' flag. This flag breaks builds for clang
    181 # 3.4 with std=c++98. So we need to re-enable this conditionally when clang is at
    182 # version 3.5 or later.
    183 env.Append(CPPPATH = [PROJ_SRC_DIR])
    184 env.Append(CPPFLAGS = ['-Wall',
    185                        '-Werror',
    186                        '-fdiagnostics-show-option',
    187                        '-Wextra',
    188                        '-Wredundant-decls',
    189                        '-pedantic',
    190                        # Explicitly enable the write-strings warning. VIXL uses
    191                        # const correctly when handling string constants.
    192                        '-Wwrite-strings'])
    193 
    194 build_suffix = ''
    195 std_path = 'default-std'
    196 
    197 if 'std' in env:
    198   env.Append(CPPFLAGS = ['-std=' + env['std']])
    199   std_path = env['std']
    200 
    201 if is_compiler('clang++'):
    202   # This warning only works for Clang, when compiling the code base as C++11
    203   # or newer. The compiler does not complain if the option is passed when
    204   # compiling earlier C++ standards.
    205   env.Append(CPPFLAGS = ['-Wimplicit-fallthrough'])
    206 
    207 if env['simulator'] == 'on':
    208   env.Append(CPPFLAGS = ['-DUSE_SIMULATOR'])
    209   build_suffix += '_sim'
    210 
    211 if env['mode'] == 'debug':
    212   env.Append(CPPFLAGS = ['-g', '-DVIXL_DEBUG'])
    213   # Append the debug mode suffix to the executable name.
    214   build_suffix += '_g'
    215 else:
    216   # Release mode.
    217   env.Append(CPPFLAGS = ['-O3'])
    218   process = subprocess.Popen(env['CXX'] + ' --version | grep "gnu.*4\.8"',
    219                              shell = True,
    220                              stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    221   stdout, stderr = process.communicate()
    222   using_gcc48 = stdout != ''
    223   if using_gcc48:
    224     # GCC 4.8 has a bug which produces a warning saying that an anonymous
    225     # Operand object might be used uninitialized:
    226     #   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57045
    227     # The bug does not seem to appear in GCC 4.7, or in debug builds with
    228     # GCC 4.8.
    229     env.Append(CPPFLAGS = ['-Wno-maybe-uninitialized'])
    230 
    231 # Configure build directory
    232 build_dir = os.path.join(OBJ_DIR, env['mode'], env['CXX'], std_path, '')
    233 create_variant(build_dir, TARGET_SRC_DIR)
    234 
    235 # The lists of available targets and target names.
    236 targets = []
    237 target_alias_names = []
    238 # Helper to create aliases.
    239 def create_alias(name, target):
    240   env.Alias(name, target)
    241   targets.append(target)
    242   target_alias_names.append(name)
    243 
    244 
    245 # The vixl library.
    246 libvixl = env.Library(build_dir + 'vixl' + build_suffix,
    247                       list_target(build_dir, PROJ_SRC_FILES))
    248 create_alias('libvixl', libvixl)
    249 
    250 
    251 # The test executable.
    252 # The test requires building the example files with specific options, so we
    253 # create a separate variant dir for the example objects built this way.
    254 test_ex_vdir = os.path.join(build_dir, 'test_examples')
    255 VariantDir(test_ex_vdir, '.')
    256 test_ex_obj = env.Object(list_target(test_ex_vdir, PROJ_EXAMPLES_SRC_FILES),
    257                          CPPFLAGS = env['CPPFLAGS'] + ['-DTEST_EXAMPLES'])
    258 test = env.Program(build_dir + 'test-runner' + build_suffix,
    259                    list_target(build_dir, TARGET_SRC_FILES['test']) +
    260                    test_ex_obj + libvixl,
    261                    CPPPATH = env['CPPPATH'] + [PROJ_EXAMPLES_DIR])
    262 create_alias('test', test)
    263 
    264 # The benchmarks.
    265 benchmarks = ['bench-dataop', 'bench-branch', 'bench-branch-link',
    266               'bench-branch-masm', 'bench-branch-link-masm']
    267 for bench in benchmarks:
    268   prog = env.Program(build_dir + bench + build_suffix,
    269                      list_target(build_dir, TARGET_SRC_FILES[bench]) + libvixl)
    270   create_alias(bench, prog)
    271 # Alias to build all benchmarks.
    272 create_alias('benchmarks', benchmarks)
    273 
    274 # The examples.
    275 examples = []
    276 for example in PROJ_EXAMPLES_SRC_FILES:
    277   example_name = "example-" + os.path.splitext(os.path.basename(example))[0]
    278   prog = env.Program(build_dir + example_name,
    279                      [os.path.join(build_dir, example)] + libvixl,
    280                      CPPPATH = env['CPPPATH'] + [PROJ_EXAMPLES_DIR])
    281   create_alias(example_name, prog)
    282   examples.append(prog)
    283 # Alias to build all examples.
    284 create_alias('examples', examples)
    285 
    286 
    287 # Create a simple alias to build everything with the current options.
    288 create_alias('all', targets)
    289 
    290 Help('Available top level targets:\n' + '\t' + '\n\t'.join(target_alias_names) + '\n')
    291 
    292 # By default, only build the tests.
    293 Default(libvixl, test)
    294