| #!/usr/bin/env python2.7 | |
| # Copyright (c) 2006 The Regents of The University of Michigan | |
| # 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 the copyright holders 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 AND 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. | |
| # | |
| # Authors: Nathan Binkert | |
| import os, re, sys | |
| from os.path import isdir, isfile, join as joinpath | |
| homedir = os.environ['HOME'] | |
| def do_compile(): | |
| # | |
| # Find SCons | |
| # | |
| search_dirs = [ joinpath(homedir, 'local/lib'), '/opt/local/lib', | |
| '/usr/local/lib', '/usr/lib' ] | |
| if os.environ.has_key("SCONS_LIB_DIR"): | |
| search_dirs.append(os.environ["SCONS_LIB_DIR"]) | |
| local = re.compile(r'^scons-local-([0-9]*)\.([0-9]*)\.([0-9]*)$') | |
| standard = re.compile(r'^scons-([0-9]*)\.([0-9]*)\.([0-9]*)$') | |
| scons_dirs = [] | |
| for dir in search_dirs: | |
| if not isdir(dir): | |
| continue | |
| entries = os.listdir(dir) | |
| for entry in entries: | |
| if not entry.startswith('scons'): | |
| continue | |
| version = (0,0,0) | |
| path = joinpath(dir, entry) | |
| match = local.search(entry) | |
| if not match: | |
| match = standard.search(entry) | |
| if match: | |
| version = match.group(1), match.group(2), match.group(3) | |
| scons_dirs.append((version, path)) | |
| scons_dirs.sort() | |
| scons_dirs.reverse() | |
| if not scons_dirs: | |
| print >>sys.stderr, \ | |
| "could not find scons in the following dirs: %s" % search_dirs | |
| sys.exit(1) | |
| sys.path = [ scons_dirs[0][1] ] + sys.path | |
| # invoke SCons | |
| import SCons.Script | |
| SCons.Script.main() | |
| # | |
| # do argument parsing | |
| # | |
| progname = sys.argv[0] | |
| import optparse | |
| usage = '''%prog [compile options] <version> [SCons options] | |
| %prog assumes that the user has a directory called ~/m5/<version> where | |
| the source tree resides, and a directory called ~/build, where %prog | |
| will create ~/build/<version> if it does not exist and build the resulting | |
| simulators there. | |
| If ~/build is set up in such a way that it points to a local disk on | |
| each host, compiles will be very efficient. For example: | |
| ~/build -> /z/<username>/.build (Assuming that /z is a local disk and | |
| not NFS mounted, whereas your home directory is NFS mounted). | |
| ''' | |
| version = '%prog 0.1' | |
| parser = optparse.OptionParser(usage=usage, version=version, | |
| formatter=optparse.TitledHelpFormatter()) | |
| parser.disable_interspersed_args() | |
| # current option group | |
| group = None | |
| def set_group(*args, **kwargs): | |
| '''set the current option group''' | |
| global group | |
| if not args and not kwargs: | |
| group = None | |
| else: | |
| group = parser.add_option_group(*args, **kwargs) | |
| def add_option(*args, **kwargs): | |
| if group: | |
| return group.add_option(*args, **kwargs) | |
| else: | |
| return parser.add_option(*args, **kwargs) | |
| def bool_option(name, default, help): | |
| '''add a boolean option called --name and --no-name. | |
| Display help depending on which is the default''' | |
| tname = '--%s' % name | |
| fname = '--no-%s' % name | |
| dest = name.replace('-', '_') | |
| if default: | |
| thelp = optparse.SUPPRESS_HELP | |
| fhelp = help | |
| else: | |
| thelp = help | |
| fhelp = optparse.SUPPRESS_HELP | |
| add_option(tname, action="store_true", default=default, help=thelp) | |
| add_option(fname, action="store_false", dest=dest, help=fhelp) | |
| add_option('-n', '--no-compile', default=False, action='store_true', | |
| help="don't actually compile, just echo SCons command line") | |
| add_option('--everything', default=False, action='store_true', | |
| help="compile everything that can be compiled") | |
| add_option('-E', "--experimental", action='store_true', default=False, | |
| help="enable experimental builds") | |
| add_option('-v', "--verbose", default=False, action='store_true', | |
| help="be verbose") | |
| set_group("Output binary types") | |
| bool_option("debug", default=False, help="compile debug binaries") | |
| bool_option("opt", default=False, help="compile opt binaries") | |
| bool_option("fast", default=False, help="compile fast binaries") | |
| bool_option("prof", default=False, help="compile profile binaries") | |
| add_option('-a', "--all-bin", default=False, action='store_true', | |
| help="compile debug, opt, and fast binaries") | |
| set_group("ISA options") | |
| bool_option("alpha", default=False, help="compile Alpha") | |
| bool_option("mips", default=False, help="compile MIPS") | |
| bool_option("sparc", default=False, help="compile SPARC") | |
| add_option('-i', "--all-isa", default=False, action='store_true', | |
| help="compile all ISAs") | |
| set_group("Emulation options") | |
| bool_option("syscall", default=True, | |
| help="Do not compile System Call Emulation mode") | |
| bool_option("fullsys", default=True, | |
| help="Do not compile Full System mode") | |
| def usage(exitcode=None): | |
| parser.print_help() | |
| if exitcode is not None: | |
| sys.exit(exitcode) | |
| (options, args) = parser.parse_args() | |
| if options.everything: | |
| options.all_bin = True | |
| options.prof = True | |
| options.all_isa = True | |
| if options.all_bin: | |
| options.debug = True | |
| options.opt = True | |
| options.fast = True | |
| binaries = [] | |
| if options.debug: | |
| binaries.append('m5.debug') | |
| if options.opt: | |
| binaries.append('m5.opt') | |
| if options.fast: | |
| binaries.append('m5.fast') | |
| if options.prof: | |
| binaries.append('m5.prof') | |
| if not binaries: | |
| binaries.append('m5.debug') | |
| if options.all_isa: | |
| options.alpha = True | |
| options.mips = True | |
| options.sparc = True | |
| isas = [] | |
| if options.alpha: | |
| isas.append('alpha') | |
| if options.mips: | |
| isas.append('mips') | |
| if options.sparc: | |
| isas.append('sparc') | |
| if not isas: | |
| isas.append('alpha') | |
| modes = [] | |
| if options.syscall: | |
| modes.append('syscall') | |
| if options.fullsys: | |
| modes.append('fullsys') | |
| if not modes: | |
| sys.exit("must specify at least one mode") | |
| # | |
| # Convert options into SCons command line arguments | |
| # | |
| # valid combinations of ISA and emulation mode | |
| valid = { ('alpha', 'syscall') : 'ALPHA_SE', | |
| ('alpha', 'fullsys') : 'ALPHA_FS', | |
| ('mips', 'syscall') : 'MIPS_SE', | |
| ('sparc', 'syscall') : 'SPARC_SE' } | |
| # experimental combinations of ISA and emulation mode | |
| experiment = { ('mips', 'fullsys') : 'MIPS_FS', | |
| ('sparc', 'fullsys') : 'SPARC_FS' } | |
| if options.experimental: | |
| valid.update(experiment) | |
| builds = [] | |
| for isa in isas: | |
| for mode in modes: | |
| try: | |
| build = valid[(isa, mode)] | |
| builds.append(build) | |
| except KeyError: | |
| pass | |
| if not builds: | |
| sys.exit("must specify at least one valid combination of ISA and mode") | |
| if not args: | |
| usage(2) | |
| version = args[0] | |
| del args[0] | |
| for bin in binaries: | |
| for build in builds: | |
| args.append('%s/%s' % (build, bin)) | |
| # | |
| # set up compile | |
| # | |
| build_base = joinpath(homedir, 'build') | |
| m5_base = joinpath(homedir, 'm5') | |
| if not isdir(build_base): | |
| sys.exit('build directory %s not found' % build_base) | |
| if not isdir(m5_base): | |
| sys.exit('m5 base directory %s not found' % m5_base) | |
| m5_dir = joinpath(m5_base, version) | |
| if not isdir(m5_dir): | |
| sys.exit('source directory %s not found' % m5_dir) | |
| # support M5 1.x | |
| oldstyle = isfile(joinpath(m5_dir, 'SConscript')) | |
| if oldstyle: | |
| ext_dir = joinpath(m5_base, 'ext') | |
| test_dir = joinpath(m5_base, 'test.' + version) | |
| if not isdir(ext_dir): | |
| sys.exit('ext directory not found at %s' % ext_dir) | |
| if not isdir(test_dir): | |
| sys.exit('test directory not found at %s' % test_dir) | |
| build_dir = joinpath(build_base, version) | |
| if not isdir(build_dir): | |
| os.mkdir(build_dir) | |
| # need some symlinks for m5 1.x | |
| if oldstyle: | |
| os.symlink(m5_dir, joinpath(build_dir, 'm5')) | |
| os.symlink(ext_dir, joinpath(build_dir, 'ext')) | |
| os.symlink(test_dir, joinpath(build_dir, 'test')) | |
| os.symlink(joinpath(m5_dir, 'build', 'SConstruct'), | |
| joinpath(build_dir, 'SConstruct')) | |
| os.symlink(joinpath(m5_dir, 'build', 'default_options'), | |
| joinpath(build_dir, 'default_options')) | |
| sys.argv = [ progname ] | |
| if oldstyle: | |
| os.chdir(build_dir) | |
| sys.argv.extend(args) | |
| else: | |
| os.chdir(m5_dir) | |
| for arg in args: | |
| if not arg.startswith('-') and '=' not in arg: | |
| arg = joinpath(build_dir, 'build', arg) | |
| sys.argv.append(arg) | |
| if options.no_compile or options.verbose: | |
| for arg in sys.argv[1:]: | |
| print arg | |
| if not options.no_compile: | |
| do_compile() |