1#!/usr/bin/env python2.7 2# Copyright (c) 2006 The Regents of The University of Michigan 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer; 9# redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution; 12# neither the name of the copyright holders nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27# 28# Authors: Nathan Binkert 29 30import os, re, sys 31from os.path import isdir, isfile, join as joinpath 32 33homedir = os.environ['HOME'] 34 35def do_compile(): 36 # 37 # Find SCons 38 # 39 search_dirs = [ joinpath(homedir, 'local/lib'), '/opt/local/lib', 40 '/usr/local/lib', '/usr/lib' ] 41 42 if os.environ.has_key("SCONS_LIB_DIR"): 43 search_dirs.append(os.environ["SCONS_LIB_DIR"]) 44 45 local = re.compile(r'^scons-local-([0-9]*)\.([0-9]*)\.([0-9]*)$') 46 standard = re.compile(r'^scons-([0-9]*)\.([0-9]*)\.([0-9]*)$') 47 48 scons_dirs = [] 49 for dir in search_dirs: 50 if not isdir(dir): 51 continue 52 53 entries = os.listdir(dir) 54 for entry in entries: 55 if not entry.startswith('scons'): 56 continue 57 58 version = (0,0,0) 59 path = joinpath(dir, entry) 60 61 match = local.search(entry) 62 if not match: 63 match = standard.search(entry) 64 65 if match: 66 version = match.group(1), match.group(2), match.group(3) 67 68 scons_dirs.append((version, path)) 69 70 scons_dirs.sort() 71 scons_dirs.reverse() 72 73 if not scons_dirs: 74 print >>sys.stderr, \ 75 "could not find scons in the following dirs: %s" % search_dirs 76 sys.exit(1) 77 78 sys.path = [ scons_dirs[0][1] ] + sys.path 79 80 # invoke SCons 81 import SCons.Script 82 SCons.Script.main() 83 84# 85# do argument parsing 86# 87progname = sys.argv[0] 88 89import optparse 90 91usage = '''%prog [compile options] <version> [SCons options] 92 93%prog assumes that the user has a directory called ~/m5/<version> where 94the source tree resides, and a directory called ~/build, where %prog 95will create ~/build/<version> if it does not exist and build the resulting 96simulators there. 97 98If ~/build is set up in such a way that it points to a local disk on 99each host, compiles will be very efficient. For example: 100~/build -> /z/<username>/.build (Assuming that /z is a local disk and 101not NFS mounted, whereas your home directory is NFS mounted). 102''' 103version = '%prog 0.1' 104parser = optparse.OptionParser(usage=usage, version=version, 105 formatter=optparse.TitledHelpFormatter()) 106parser.disable_interspersed_args() 107 108# current option group 109group = None 110 111def set_group(*args, **kwargs): 112 '''set the current option group''' 113 global group 114 if not args and not kwargs: 115 group = None 116 else: 117 group = parser.add_option_group(*args, **kwargs) 118 119def add_option(*args, **kwargs): 120 if group: 121 return group.add_option(*args, **kwargs) 122 else: 123 return parser.add_option(*args, **kwargs) 124 125def bool_option(name, default, help): 126 '''add a boolean option called --name and --no-name. 127 Display help depending on which is the default''' 128 129 tname = '--%s' % name 130 fname = '--no-%s' % name 131 dest = name.replace('-', '_') 132 if default: 133 thelp = optparse.SUPPRESS_HELP 134 fhelp = help 135 else: 136 thelp = help 137 fhelp = optparse.SUPPRESS_HELP 138 139 add_option(tname, action="store_true", default=default, help=thelp) 140 add_option(fname, action="store_false", dest=dest, help=fhelp) 141 142add_option('-n', '--no-compile', default=False, action='store_true', 143 help="don't actually compile, just echo SCons command line") 144add_option('--everything', default=False, action='store_true', 145 help="compile everything that can be compiled") 146add_option('-E', "--experimental", action='store_true', default=False, 147 help="enable experimental builds") 148add_option('-v', "--verbose", default=False, action='store_true', 149 help="be verbose") 150 151set_group("Output binary types") 152bool_option("debug", default=False, help="compile debug binaries") 153bool_option("opt", default=False, help="compile opt binaries") 154bool_option("fast", default=False, help="compile fast binaries") 155bool_option("prof", default=False, help="compile profile binaries") 156add_option('-a', "--all-bin", default=False, action='store_true', 157 help="compile debug, opt, and fast binaries") 158 159set_group("ISA options") 160bool_option("alpha", default=False, help="compile Alpha") 161bool_option("mips", default=False, help="compile MIPS") 162bool_option("sparc", default=False, help="compile SPARC") 163add_option('-i', "--all-isa", default=False, action='store_true', 164 help="compile all ISAs") 165 166set_group("Emulation options") 167bool_option("syscall", default=True, 168 help="Do not compile System Call Emulation mode") 169bool_option("fullsys", default=True, 170 help="Do not compile Full System mode") 171 172def usage(exitcode=None): 173 parser.print_help() 174 if exitcode is not None: 175 sys.exit(exitcode) 176 177(options, args) = parser.parse_args() 178 179if options.everything: 180 options.all_bin = True 181 options.prof = True 182 options.all_isa = True 183 184if options.all_bin: 185 options.debug = True 186 options.opt = True 187 options.fast = True 188 189binaries = [] 190if options.debug: 191 binaries.append('m5.debug') 192if options.opt: 193 binaries.append('m5.opt') 194if options.fast: 195 binaries.append('m5.fast') 196if options.prof: 197 binaries.append('m5.prof') 198 199if not binaries: 200 binaries.append('m5.debug') 201 202if options.all_isa: 203 options.alpha = True 204 options.mips = True 205 options.sparc = True 206 207isas = [] 208if options.alpha: 209 isas.append('alpha') 210if options.mips: 211 isas.append('mips') 212if options.sparc: 213 isas.append('sparc') 214 215if not isas: 216 isas.append('alpha') 217 218modes = [] 219if options.syscall: 220 modes.append('syscall') 221if options.fullsys: 222 modes.append('fullsys') 223 224if not modes: 225 sys.exit("must specify at least one mode") 226 227# 228# Convert options into SCons command line arguments 229# 230 231# valid combinations of ISA and emulation mode 232valid = { ('alpha', 'syscall') : 'ALPHA_SE', 233 ('alpha', 'fullsys') : 'ALPHA_FS', 234 ('mips', 'syscall') : 'MIPS_SE', 235 ('sparc', 'syscall') : 'SPARC_SE' } 236 237# experimental combinations of ISA and emulation mode 238experiment = { ('mips', 'fullsys') : 'MIPS_FS', 239 ('sparc', 'fullsys') : 'SPARC_FS' } 240 241if options.experimental: 242 valid.update(experiment) 243 244builds = [] 245for isa in isas: 246 for mode in modes: 247 try: 248 build = valid[(isa, mode)] 249 builds.append(build) 250 except KeyError: 251 pass 252 253if not builds: 254 sys.exit("must specify at least one valid combination of ISA and mode") 255 256if not args: 257 usage(2) 258 259version = args[0] 260del args[0] 261 262for bin in binaries: 263 for build in builds: 264 args.append('%s/%s' % (build, bin)) 265 266# 267# set up compile 268# 269build_base = joinpath(homedir, 'build') 270m5_base = joinpath(homedir, 'm5') 271 272if not isdir(build_base): 273 sys.exit('build directory %s not found' % build_base) 274 275if not isdir(m5_base): 276 sys.exit('m5 base directory %s not found' % m5_base) 277 278m5_dir = joinpath(m5_base, version) 279if not isdir(m5_dir): 280 sys.exit('source directory %s not found' % m5_dir) 281 282# support M5 1.x 283oldstyle = isfile(joinpath(m5_dir, 'SConscript')) 284if oldstyle: 285 ext_dir = joinpath(m5_base, 'ext') 286 test_dir = joinpath(m5_base, 'test.' + version) 287 288 if not isdir(ext_dir): 289 sys.exit('ext directory not found at %s' % ext_dir) 290 291 if not isdir(test_dir): 292 sys.exit('test directory not found at %s' % test_dir) 293 294build_dir = joinpath(build_base, version) 295if not isdir(build_dir): 296 os.mkdir(build_dir) 297 # need some symlinks for m5 1.x 298 if oldstyle: 299 os.symlink(m5_dir, joinpath(build_dir, 'm5')) 300 os.symlink(ext_dir, joinpath(build_dir, 'ext')) 301 os.symlink(test_dir, joinpath(build_dir, 'test')) 302 os.symlink(joinpath(m5_dir, 'build', 'SConstruct'), 303 joinpath(build_dir, 'SConstruct')) 304 os.symlink(joinpath(m5_dir, 'build', 'default_options'), 305 joinpath(build_dir, 'default_options')) 306 307sys.argv = [ progname ] 308if oldstyle: 309 os.chdir(build_dir) 310 sys.argv.extend(args) 311else: 312 os.chdir(m5_dir) 313 for arg in args: 314 if not arg.startswith('-') and '=' not in arg: 315 arg = joinpath(build_dir, 'build', arg) 316 sys.argv.append(arg) 317 318if options.no_compile or options.verbose: 319 for arg in sys.argv[1:]: 320 print arg 321 322if not options.no_compile: 323 do_compile() 324