| # -*- mode:python -*- |
| |
| # Copyright (c) 2004-2005 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 array |
| import bisect |
| import imp |
| import marshal |
| import os |
| import re |
| import sys |
| import zlib |
| |
| from os.path import basename, dirname, exists, isdir, isfile, join as joinpath |
| |
| import SCons |
| |
| # This file defines how to build a particular configuration of M5 |
| # based on variable settings in the 'env' build environment. |
| |
| Import('*') |
| |
| # Children need to see the environment |
| Export('env') |
| |
| build_env = [(opt, env[opt]) for opt in export_vars] |
| |
| from m5.util import code_formatter |
| |
| ######################################################################## |
| # Code for adding source files of various types |
| # |
| class SourceMeta(type): |
| def __init__(cls, name, bases, dict): |
| super(SourceMeta, cls).__init__(name, bases, dict) |
| cls.all = [] |
| |
| def get(cls, **kwargs): |
| for src in cls.all: |
| for attr,value in kwargs.iteritems(): |
| if getattr(src, attr) != value: |
| break |
| else: |
| yield src |
| |
| class SourceFile(object): |
| __metaclass__ = SourceMeta |
| def __init__(self, source): |
| tnode = source |
| if not isinstance(source, SCons.Node.FS.File): |
| tnode = File(source) |
| |
| self.tnode = tnode |
| self.snode = tnode.srcnode() |
| self.filename = str(tnode) |
| self.dirname = dirname(self.filename) |
| self.basename = basename(self.filename) |
| index = self.basename.rfind('.') |
| if index <= 0: |
| # dot files aren't extensions |
| self.extname = self.basename, None |
| else: |
| self.extname = self.basename[:index], self.basename[index+1:] |
| |
| for base in type(self).__mro__: |
| if issubclass(base, SourceFile): |
| base.all.append(self) |
| |
| def __lt__(self, other): return self.filename < other.filename |
| def __le__(self, other): return self.filename <= other.filename |
| def __gt__(self, other): return self.filename > other.filename |
| def __ge__(self, other): return self.filename >= other.filename |
| def __eq__(self, other): return self.filename == other.filename |
| def __ne__(self, other): return self.filename != other.filename |
| |
| class Source(SourceFile): |
| '''Add a c/c++ source file to the build''' |
| def __init__(self, source, Werror=True, swig=False, bin_only=False, |
| skip_lib=False): |
| super(Source, self).__init__(source) |
| |
| self.Werror = Werror |
| self.swig = swig |
| self.bin_only = bin_only |
| self.skip_lib = bin_only or skip_lib |
| |
| class PySource(SourceFile): |
| '''Add a python source file to the named package''' |
| invalid_sym_char = re.compile('[^A-z0-9_]') |
| modules = {} |
| tnodes = {} |
| symnames = {} |
| |
| def __init__(self, package, source): |
| super(PySource, self).__init__(source) |
| |
| modname,ext = self.extname |
| assert ext == 'py' |
| |
| if package: |
| path = package.split('.') |
| else: |
| path = [] |
| |
| modpath = path[:] |
| if modname != '__init__': |
| modpath += [ modname ] |
| modpath = '.'.join(modpath) |
| |
| arcpath = path + [ self.basename ] |
| abspath = self.snode.abspath |
| if not exists(abspath): |
| abspath = self.tnode.abspath |
| |
| self.package = package |
| self.modname = modname |
| self.modpath = modpath |
| self.arcname = joinpath(*arcpath) |
| self.abspath = abspath |
| self.compiled = File(self.filename + 'c') |
| self.cpp = File(self.filename + '.cc') |
| self.symname = PySource.invalid_sym_char.sub('_', modpath) |
| |
| PySource.modules[modpath] = self |
| PySource.tnodes[self.tnode] = self |
| PySource.symnames[self.symname] = self |
| |
| class SimObject(PySource): |
| '''Add a SimObject python file as a python source object and add |
| it to a list of sim object modules''' |
| |
| fixed = False |
| modnames = [] |
| |
| def __init__(self, source): |
| super(SimObject, self).__init__('m5.objects', source) |
| if self.fixed: |
| raise AttributeError, "Too late to call SimObject now." |
| |
| bisect.insort_right(SimObject.modnames, self.modname) |
| |
| class SwigSource(SourceFile): |
| '''Add a swig file to build''' |
| |
| def __init__(self, package, source): |
| super(SwigSource, self).__init__(source) |
| |
| modname,ext = self.extname |
| assert ext == 'i' |
| |
| self.module = modname |
| cc_file = joinpath(self.dirname, modname + '_wrap.cc') |
| py_file = joinpath(self.dirname, modname + '.py') |
| |
| self.cc_source = Source(cc_file, swig=True) |
| self.py_source = PySource(package, py_file) |
| |
| unit_tests = [] |
| def UnitTest(target, sources): |
| if not isinstance(sources, (list, tuple)): |
| sources = [ sources ] |
| |
| sources = [ Source(src, skip_lib=True) for src in sources ] |
| unit_tests.append((target, sources)) |
| |
| # Children should have access |
| Export('Source') |
| Export('PySource') |
| Export('SimObject') |
| Export('SwigSource') |
| Export('UnitTest') |
| |
| ######################################################################## |
| # |
| # Trace Flags |
| # |
| trace_flags = {} |
| def TraceFlag(name, desc=None): |
| if name in trace_flags: |
| raise AttributeError, "Flag %s already specified" % name |
| trace_flags[name] = (name, (), desc) |
| |
| def CompoundFlag(name, flags, desc=None): |
| if name in trace_flags: |
| raise AttributeError, "Flag %s already specified" % name |
| |
| compound = tuple(flags) |
| trace_flags[name] = (name, compound, desc) |
| |
| Export('TraceFlag') |
| Export('CompoundFlag') |
| |
| ######################################################################## |
| # |
| # Set some compiler variables |
| # |
| |
| # Include file paths are rooted in this directory. SCons will |
| # automatically expand '.' to refer to both the source directory and |
| # the corresponding build directory to pick up generated include |
| # files. |
| env.Append(CPPPATH=Dir('.')) |
| |
| for extra_dir in extras_dir_list: |
| env.Append(CPPPATH=Dir(extra_dir)) |
| |
| # Workaround for bug in SCons version > 0.97d20071212 |
| # Scons bug id: 2006 M5 Bug id: 308 |
| for root, dirs, files in os.walk(base_dir, topdown=True): |
| Dir(root[len(base_dir) + 1:]) |
| |
| ######################################################################## |
| # |
| # Walk the tree and execute all SConscripts in subdirectories |
| # |
| |
| here = Dir('.').srcnode().abspath |
| for root, dirs, files in os.walk(base_dir, topdown=True): |
| if root == here: |
| # we don't want to recurse back into this SConscript |
| continue |
| |
| if 'SConscript' in files: |
| build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) |
| SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) |
| |
| for extra_dir in extras_dir_list: |
| prefix_len = len(dirname(extra_dir)) + 1 |
| for root, dirs, files in os.walk(extra_dir, topdown=True): |
| if 'SConscript' in files: |
| build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) |
| SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) |
| |
| for opt in export_vars: |
| env.ConfigFile(opt) |
| |
| def makeTheISA(source, target, env): |
| isas = [ src.get_contents() for src in source ] |
| target_isa = env['TARGET_ISA'] |
| def define(isa): |
| return isa.upper() + '_ISA' |
| |
| def namespace(isa): |
| return isa[0].upper() + isa[1:].lower() + 'ISA' |
| |
| |
| code = code_formatter() |
| code('''\ |
| #ifndef __CONFIG_THE_ISA_HH__ |
| #define __CONFIG_THE_ISA_HH__ |
| |
| ''') |
| |
| for i,isa in enumerate(isas): |
| code('#define $0 $1', define(isa), i + 1) |
| |
| code(''' |
| |
| #define THE_ISA ${{define(target_isa)}} |
| #define TheISA ${{namespace(target_isa)}} |
| |
| #endif // __CONFIG_THE_ISA_HH__''') |
| |
| code.write(str(target[0])) |
| |
| env.Command('config/the_isa.hh', map(Value, all_isa_list), |
| MakeAction(makeTheISA, " [ CFG ISA] $STRIP_TARGET")) |
| |
| ######################################################################## |
| # |
| # Prevent any SimObjects from being added after this point, they |
| # should all have been added in the SConscripts above |
| # |
| SimObject.fixed = True |
| |
| class DictImporter(object): |
| '''This importer takes a dictionary of arbitrary module names that |
| map to arbitrary filenames.''' |
| def __init__(self, modules): |
| self.modules = modules |
| self.installed = set() |
| |
| def __del__(self): |
| self.unload() |
| |
| def unload(self): |
| import sys |
| for module in self.installed: |
| del sys.modules[module] |
| self.installed = set() |
| |
| def find_module(self, fullname, path): |
| if fullname == 'm5.defines': |
| return self |
| |
| if fullname == 'm5.objects': |
| return self |
| |
| if fullname.startswith('m5.internal'): |
| return None |
| |
| source = self.modules.get(fullname, None) |
| if source is not None and fullname.startswith('m5.objects'): |
| return self |
| |
| return None |
| |
| def load_module(self, fullname): |
| mod = imp.new_module(fullname) |
| sys.modules[fullname] = mod |
| self.installed.add(fullname) |
| |
| mod.__loader__ = self |
| if fullname == 'm5.objects': |
| mod.__path__ = fullname.split('.') |
| return mod |
| |
| if fullname == 'm5.defines': |
| mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) |
| return mod |
| |
| source = self.modules[fullname] |
| if source.modname == '__init__': |
| mod.__path__ = source.modpath |
| mod.__file__ = source.abspath |
| |
| exec file(source.abspath, 'r') in mod.__dict__ |
| |
| return mod |
| |
| import m5.SimObject |
| import m5.params |
| from m5.util import code_formatter |
| |
| m5.SimObject.clear() |
| m5.params.clear() |
| |
| # install the python importer so we can grab stuff from the source |
| # tree itself. We can't have SimObjects added after this point or |
| # else we won't know about them for the rest of the stuff. |
| importer = DictImporter(PySource.modules) |
| sys.meta_path[0:0] = [ importer ] |
| |
| # import all sim objects so we can populate the all_objects list |
| # make sure that we're working with a list, then let's sort it |
| for modname in SimObject.modnames: |
| exec('from m5.objects import %s' % modname) |
| |
| # we need to unload all of the currently imported modules so that they |
| # will be re-imported the next time the sconscript is run |
| importer.unload() |
| sys.meta_path.remove(importer) |
| |
| sim_objects = m5.SimObject.allClasses |
| all_enums = m5.params.allEnums |
| |
| all_params = {} |
| for name,obj in sorted(sim_objects.iteritems()): |
| for param in obj._params.local.values(): |
| # load the ptype attribute now because it depends on the |
| # current version of SimObject.allClasses, but when scons |
| # actually uses the value, all versions of |
| # SimObject.allClasses will have been loaded |
| param.ptype |
| |
| if not hasattr(param, 'swig_decl'): |
| continue |
| pname = param.ptype_str |
| if pname not in all_params: |
| all_params[pname] = param |
| |
| ######################################################################## |
| # |
| # calculate extra dependencies |
| # |
| module_depends = ["m5", "m5.SimObject", "m5.params"] |
| depends = [ PySource.modules[dep].snode for dep in module_depends ] |
| |
| ######################################################################## |
| # |
| # Commands for the basic automatically generated python files |
| # |
| |
| # Generate Python file containing a dict specifying the current |
| # buildEnv flags. |
| def makeDefinesPyFile(target, source, env): |
| build_env, hg_info = [ x.get_contents() for x in source ] |
| |
| code = code_formatter() |
| code(""" |
| import m5.internal |
| import m5.util |
| |
| buildEnv = m5.util.SmartDict($build_env) |
| hgRev = '$hg_info' |
| |
| compileDate = m5.internal.core.compileDate |
| _globals = globals() |
| for key,val in m5.internal.core.__dict__.iteritems(): |
| if key.startswith('flag_'): |
| flag = key[5:] |
| _globals[flag] = val |
| del _globals |
| """) |
| code.write(target[0].abspath) |
| |
| defines_info = [ Value(build_env), Value(env['HG_INFO']) ] |
| # Generate a file with all of the compile options in it |
| env.Command('python/m5/defines.py', defines_info, |
| MakeAction(makeDefinesPyFile, " [ DEFINES] $STRIP_TARGET")) |
| PySource('m5', 'python/m5/defines.py') |
| |
| # Generate python file containing info about the M5 source code |
| def makeInfoPyFile(target, source, env): |
| code = code_formatter() |
| for src in source: |
| data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) |
| code('$src = ${{repr(data)}}') |
| code.write(str(target[0])) |
| |
| # Generate a file that wraps the basic top level files |
| env.Command('python/m5/info.py', |
| [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], |
| MakeAction(makeInfoPyFile, " [ INFO] $STRIP_TARGET")) |
| PySource('m5', 'python/m5/info.py') |
| |
| ######################################################################## |
| # |
| # Create all of the SimObject param headers and enum headers |
| # |
| |
| def createSimObjectParam(target, source, env): |
| assert len(target) == 1 and len(source) == 1 |
| |
| name = str(source[0].get_contents()) |
| obj = sim_objects[name] |
| |
| code = code_formatter() |
| obj.cxx_decl(code) |
| code.write(target[0].abspath) |
| |
| def createSwigParam(target, source, env): |
| assert len(target) == 1 and len(source) == 1 |
| |
| name = str(source[0].get_contents()) |
| param = all_params[name] |
| |
| code = code_formatter() |
| code('%module(package="m5.internal") $0_${name}', param.file_ext) |
| param.swig_decl(code) |
| code.write(target[0].abspath) |
| |
| def createEnumStrings(target, source, env): |
| assert len(target) == 1 and len(source) == 1 |
| |
| name = str(source[0].get_contents()) |
| obj = all_enums[name] |
| |
| code = code_formatter() |
| obj.cxx_def(code) |
| code.write(target[0].abspath) |
| |
| def createEnumParam(target, source, env): |
| assert len(target) == 1 and len(source) == 1 |
| |
| name = str(source[0].get_contents()) |
| obj = all_enums[name] |
| |
| code = code_formatter() |
| obj.cxx_decl(code) |
| code.write(target[0].abspath) |
| |
| def createEnumSwig(target, source, env): |
| assert len(target) == 1 and len(source) == 1 |
| |
| name = str(source[0].get_contents()) |
| obj = all_enums[name] |
| |
| code = code_formatter() |
| code('''\ |
| %module(package="m5.internal") enum_$name |
| |
| %{ |
| #include "enums/$name.hh" |
| %} |
| |
| %include "enums/$name.hh" |
| ''') |
| code.write(target[0].abspath) |
| |
| # Generate all of the SimObject param struct header files |
| params_hh_files = [] |
| for name,simobj in sorted(sim_objects.iteritems()): |
| py_source = PySource.modules[simobj.__module__] |
| extra_deps = [ py_source.tnode ] |
| |
| hh_file = File('params/%s.hh' % name) |
| params_hh_files.append(hh_file) |
| env.Command(hh_file, Value(name), |
| MakeAction(createSimObjectParam, " [SO PARAM] $STRIP_TARGET")) |
| env.Depends(hh_file, depends + extra_deps) |
| |
| # Generate any parameter header files needed |
| params_i_files = [] |
| for name,param in all_params.iteritems(): |
| i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name)) |
| params_i_files.append(i_file) |
| env.Command(i_file, Value(name), |
| MakeAction(createSwigParam, " [SW PARAM] $STRIP_TARGET")) |
| env.Depends(i_file, depends) |
| SwigSource('m5.internal', i_file) |
| |
| # Generate all enum header files |
| for name,enum in sorted(all_enums.iteritems()): |
| py_source = PySource.modules[enum.__module__] |
| extra_deps = [ py_source.tnode ] |
| |
| cc_file = File('enums/%s.cc' % name) |
| env.Command(cc_file, Value(name), |
| MakeAction(createEnumStrings, " [ENUM STR] $STRIP_TARGET")) |
| env.Depends(cc_file, depends + extra_deps) |
| Source(cc_file) |
| |
| hh_file = File('enums/%s.hh' % name) |
| env.Command(hh_file, Value(name), |
| MakeAction(createEnumParam, " [EN PARAM] $STRIP_TARGET")) |
| env.Depends(hh_file, depends + extra_deps) |
| |
| i_file = File('python/m5/internal/enum_%s.i' % name) |
| env.Command(i_file, Value(name), |
| MakeAction(createEnumSwig, " [ENUMSWIG] $STRIP_TARGET")) |
| env.Depends(i_file, depends + extra_deps) |
| SwigSource('m5.internal', i_file) |
| |
| def buildParam(target, source, env): |
| name = source[0].get_contents() |
| obj = sim_objects[name] |
| class_path = obj.cxx_class.split('::') |
| classname = class_path[-1] |
| namespaces = class_path[:-1] |
| params = obj._params.local.values() |
| |
| code = code_formatter() |
| |
| code('%module(package="m5.internal") param_$name') |
| code() |
| code('%{') |
| code('#include "params/$obj.hh"') |
| for param in params: |
| param.cxx_predecls(code) |
| code('%}') |
| code() |
| |
| for param in params: |
| param.swig_predecls(code) |
| |
| code() |
| if obj._base: |
| code('%import "python/m5/internal/param_${{obj._base}}.i"') |
| code() |
| obj.swig_objdecls(code) |
| code() |
| |
| code('%include "params/$obj.hh"') |
| |
| code.write(target[0].abspath) |
| |
| for name in sim_objects.iterkeys(): |
| params_file = File('python/m5/internal/param_%s.i' % name) |
| env.Command(params_file, Value(name), |
| MakeAction(buildParam, " [BLDPARAM] $STRIP_TARGET")) |
| env.Depends(params_file, depends) |
| SwigSource('m5.internal', params_file) |
| |
| # Generate the main swig init file |
| def makeEmbeddedSwigInit(target, source, env): |
| code = code_formatter() |
| module = source[0].get_contents() |
| code('''\ |
| #include "sim/init.hh" |
| |
| extern "C" { |
| void init_${module}(); |
| } |
| |
| EmbeddedSwig embed_swig_${module}(init_${module}); |
| ''') |
| code.write(str(target[0])) |
| |
| # Build all swig modules |
| for swig in SwigSource.all: |
| env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, |
| MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' |
| '-o ${TARGETS[0]} $SOURCES', " [ SWIG] $STRIP_TARGET")) |
| init_file = 'python/swig/init_%s.cc' % swig.module |
| env.Command(init_file, Value(swig.module), |
| MakeAction(makeEmbeddedSwigInit, " [EMBED SW] $STRIP_TARGET")) |
| Source(init_file) |
| |
| def getFlags(source_flags): |
| flagsMap = {} |
| flagsList = [] |
| for s in source_flags: |
| val = eval(s.get_contents()) |
| name, compound, desc = val |
| flagsList.append(val) |
| flagsMap[name] = bool(compound) |
| |
| for name, compound, desc in flagsList: |
| for flag in compound: |
| if flag not in flagsMap: |
| raise AttributeError, "Trace flag %s not found" % flag |
| if flagsMap[flag]: |
| raise AttributeError, \ |
| "Compound flag can't point to another compound flag" |
| |
| flagsList.sort() |
| return flagsList |
| |
| |
| # Generate traceflags.py |
| def traceFlagsPy(target, source, env): |
| assert(len(target) == 1) |
| code = code_formatter() |
| |
| allFlags = getFlags(source) |
| |
| code('basic = [') |
| code.indent() |
| for flag, compound, desc in allFlags: |
| if not compound: |
| code("'$flag',") |
| code(']') |
| code.dedent() |
| code() |
| |
| code('compound = [') |
| code.indent() |
| code("'All',") |
| for flag, compound, desc in allFlags: |
| if compound: |
| code("'$flag',") |
| code("]") |
| code.dedent() |
| code() |
| |
| code("all = frozenset(basic + compound)") |
| code() |
| |
| code('compoundMap = {') |
| code.indent() |
| all = tuple([flag for flag,compound,desc in allFlags if not compound]) |
| code("'All' : $all,") |
| for flag, compound, desc in allFlags: |
| if compound: |
| code("'$flag' : $compound,") |
| code('}') |
| code.dedent() |
| code() |
| |
| code('descriptions = {') |
| code.indent() |
| code("'All' : 'All flags',") |
| for flag, compound, desc in allFlags: |
| code("'$flag' : '$desc',") |
| code("}") |
| code.dedent() |
| |
| code.write(str(target[0])) |
| |
| def traceFlagsCC(target, source, env): |
| assert(len(target) == 1) |
| |
| allFlags = getFlags(source) |
| code = code_formatter() |
| |
| # file header |
| code(''' |
| /* |
| * DO NOT EDIT THIS FILE! Automatically generated |
| */ |
| |
| #include "base/traceflags.hh" |
| |
| using namespace Trace; |
| |
| const char *Trace::flagStrings[] = |
| {''') |
| |
| code.indent() |
| # The string array is used by SimpleEnumParam to map the strings |
| # provided by the user to enum values. |
| for flag, compound, desc in allFlags: |
| if not compound: |
| code('"$flag",') |
| |
| code('"All",') |
| for flag, compound, desc in allFlags: |
| if compound: |
| code('"$flag",') |
| code.dedent() |
| |
| code('''\ |
| }; |
| |
| const int Trace::numFlagStrings = ${{len(allFlags) + 1}}; |
| |
| ''') |
| |
| # Now define the individual compound flag arrays. There is an array |
| # for each compound flag listing the component base flags. |
| all = tuple([flag for flag,compound,desc in allFlags if not compound]) |
| code('static const Flags AllMap[] = {') |
| code.indent() |
| for flag, compound, desc in allFlags: |
| if not compound: |
| code('$flag,') |
| code.dedent() |
| code('};') |
| code() |
| |
| for flag, compound, desc in allFlags: |
| if not compound: |
| continue |
| code('static const Flags ${flag}Map[] = {') |
| code.indent() |
| for flag in compound: |
| code('$flag,') |
| code('(Flags)-1') |
| code.dedent() |
| code('};') |
| code() |
| |
| # Finally the compoundFlags[] array maps the compound flags |
| # to their individual arrays/ |
| code('const Flags *Trace::compoundFlags[] = {') |
| code.indent() |
| code('AllMap,') |
| for flag, compound, desc in allFlags: |
| if compound: |
| code('${flag}Map,') |
| # file trailer |
| code.dedent() |
| code('};') |
| |
| code.write(str(target[0])) |
| |
| def traceFlagsHH(target, source, env): |
| assert(len(target) == 1) |
| |
| allFlags = getFlags(source) |
| code = code_formatter() |
| |
| # file header boilerplate |
| code('''\ |
| /* |
| * DO NOT EDIT THIS FILE! |
| * |
| * Automatically generated from traceflags.py |
| */ |
| |
| #ifndef __BASE_TRACE_FLAGS_HH__ |
| #define __BASE_TRACE_FLAGS_HH__ |
| |
| namespace Trace { |
| |
| enum Flags {''') |
| |
| # Generate the enum. Base flags come first, then compound flags. |
| idx = 0 |
| code.indent() |
| for flag, compound, desc in allFlags: |
| if not compound: |
| code('$flag = $idx,') |
| idx += 1 |
| |
| numBaseFlags = idx |
| code('NumFlags = $idx,') |
| code.dedent() |
| code() |
| |
| # put a comment in here to separate base from compound flags |
| code(''' |
| // The remaining enum values are *not* valid indices for Trace::flags. |
| // They are "compound" flags, which correspond to sets of base |
| // flags, and are used by changeFlag.''') |
| |
| code.indent() |
| code('All = $idx,') |
| idx += 1 |
| for flag, compound, desc in allFlags: |
| if compound: |
| code('$flag = $idx,') |
| idx += 1 |
| |
| numCompoundFlags = idx - numBaseFlags |
| code('NumCompoundFlags = $numCompoundFlags') |
| code.dedent() |
| |
| # trailer boilerplate |
| code('''\ |
| }; // enum Flags |
| |
| // Array of strings for SimpleEnumParam |
| extern const char *flagStrings[]; |
| extern const int numFlagStrings; |
| |
| // Array of arraay pointers: for each compound flag, gives the list of |
| // base flags to set. Inidividual flag arrays are terminated by -1. |
| extern const Flags *compoundFlags[]; |
| |
| } // namespace Trace |
| |
| #endif // __BASE_TRACE_FLAGS_HH__ |
| ''') |
| |
| code.write(str(target[0])) |
| |
| flags = map(Value, trace_flags.values()) |
| env.Command('base/traceflags.py', flags, |
| MakeAction(traceFlagsPy, " [ TRACING] $STRIP_TARGET")) |
| PySource('m5', 'base/traceflags.py') |
| |
| env.Command('base/traceflags.hh', flags, |
| MakeAction(traceFlagsHH, " [ TRACING] $STRIP_TARGET")) |
| env.Command('base/traceflags.cc', flags, |
| MakeAction(traceFlagsCC, " [ TRACING] $STRIP_TARGET")) |
| Source('base/traceflags.cc') |
| |
| # Embed python files. All .py files that have been indicated by a |
| # PySource() call in a SConscript need to be embedded into the M5 |
| # library. To do that, we compile the file to byte code, marshal the |
| # byte code, compress it, and then generate a c++ file that |
| # inserts the result into an array. |
| def embedPyFile(target, source, env): |
| def c_str(string): |
| if string is None: |
| return "0" |
| return '"%s"' % string |
| |
| '''Action function to compile a .py into a code object, marshal |
| it, compress it, and stick it into an asm file so the code appears |
| as just bytes with a label in the data section''' |
| |
| src = file(str(source[0]), 'r').read() |
| |
| pysource = PySource.tnodes[source[0]] |
| compiled = compile(src, pysource.abspath, 'exec') |
| marshalled = marshal.dumps(compiled) |
| compressed = zlib.compress(marshalled) |
| data = compressed |
| sym = pysource.symname |
| |
| code = code_formatter() |
| code('''\ |
| #include "sim/init.hh" |
| |
| namespace { |
| |
| const char data_${sym}[] = { |
| ''') |
| code.indent() |
| step = 16 |
| for i in xrange(0, len(data), step): |
| x = array.array('B', data[i:i+step]) |
| code(''.join('%d,' % d for d in x)) |
| code.dedent() |
| |
| code('''}; |
| |
| EmbeddedPython embedded_${sym}( |
| ${{c_str(pysource.arcname)}}, |
| ${{c_str(pysource.abspath)}}, |
| ${{c_str(pysource.modpath)}}, |
| data_${sym}, |
| ${{len(data)}}, |
| ${{len(marshalled)}}); |
| |
| } // anonymous namespace |
| ''') |
| code.write(str(target[0])) |
| |
| for source in PySource.all: |
| env.Command(source.cpp, source.tnode, |
| MakeAction(embedPyFile, " [EMBED PY] $STRIP_TARGET")) |
| Source(source.cpp) |
| |
| ######################################################################## |
| # |
| # Define binaries. Each different build type (debug, opt, etc.) gets |
| # a slightly different build environment. |
| # |
| |
| # List of constructed environments to pass back to SConstruct |
| envList = [] |
| |
| date_source = Source('base/date.cc', skip_lib=True) |
| |
| # Function to create a new build environment as clone of current |
| # environment 'env' with modified object suffix and optional stripped |
| # binary. Additional keyword arguments are appended to corresponding |
| # build environment vars. |
| def makeEnv(label, objsfx, strip = False, **kwargs): |
| # SCons doesn't know to append a library suffix when there is a '.' in the |
| # name. Use '_' instead. |
| libname = 'm5_' + label |
| exename = 'm5.' + label |
| |
| new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') |
| new_env.Label = label |
| new_env.Append(**kwargs) |
| |
| swig_env = new_env.Clone() |
| swig_env.Append(CCFLAGS='-Werror') |
| if env['GCC']: |
| swig_env.Append(CCFLAGS='-Wno-uninitialized') |
| swig_env.Append(CCFLAGS='-Wno-sign-compare') |
| swig_env.Append(CCFLAGS='-Wno-parentheses') |
| |
| werror_env = new_env.Clone() |
| werror_env.Append(CCFLAGS='-Werror') |
| |
| def make_obj(source, static, extra_deps = None): |
| '''This function adds the specified source to the correct |
| build environment, and returns the corresponding SCons Object |
| nodes''' |
| |
| if source.swig: |
| env = swig_env |
| elif source.Werror: |
| env = werror_env |
| else: |
| env = new_env |
| |
| if static: |
| obj = env.StaticObject(source.tnode) |
| else: |
| obj = env.SharedObject(source.tnode) |
| |
| if extra_deps: |
| env.Depends(obj, extra_deps) |
| |
| return obj |
| |
| static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)] |
| shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)] |
| |
| static_date = make_obj(date_source, static=True, extra_deps=static_objs) |
| static_objs.append(static_date) |
| |
| shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) |
| shared_objs.append(shared_date) |
| |
| # First make a library of everything but main() so other programs can |
| # link against m5. |
| static_lib = new_env.StaticLibrary(libname, static_objs) |
| shared_lib = new_env.SharedLibrary(libname, shared_objs) |
| |
| for target, sources in unit_tests: |
| objs = [ make_obj(s, static=True) for s in sources ] |
| new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs) |
| |
| # Now link a stub with main() and the static library. |
| bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ] |
| progname = exename |
| if strip: |
| progname += '.unstripped' |
| |
| targets = new_env.Program(progname, bin_objs + static_objs) |
| |
| if strip: |
| if sys.platform == 'sunos5': |
| cmd = 'cp $SOURCE $TARGET; strip $TARGET' |
| else: |
| cmd = 'strip $SOURCE -o $TARGET' |
| targets = new_env.Command(exename, progname, |
| MakeAction(cmd, " [ STRIP] $STRIP_TARGET")) |
| |
| new_env.M5Binary = targets[0] |
| envList.append(new_env) |
| |
| # Debug binary |
| ccflags = {} |
| if env['GCC']: |
| if sys.platform == 'sunos5': |
| ccflags['debug'] = '-gstabs+' |
| else: |
| ccflags['debug'] = '-ggdb3' |
| ccflags['opt'] = '-g -O3' |
| ccflags['fast'] = '-O3' |
| ccflags['prof'] = '-O3 -g -pg' |
| elif env['SUNCC']: |
| ccflags['debug'] = '-g0' |
| ccflags['opt'] = '-g -O' |
| ccflags['fast'] = '-fast' |
| ccflags['prof'] = '-fast -g -pg' |
| elif env['ICC']: |
| ccflags['debug'] = '-g -O0' |
| ccflags['opt'] = '-g -O' |
| ccflags['fast'] = '-fast' |
| ccflags['prof'] = '-fast -g -pg' |
| else: |
| print 'Unknown compiler, please fix compiler options' |
| Exit(1) |
| |
| makeEnv('debug', '.do', |
| CCFLAGS = Split(ccflags['debug']), |
| CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) |
| |
| # Optimized binary |
| makeEnv('opt', '.o', |
| CCFLAGS = Split(ccflags['opt']), |
| CPPDEFINES = ['TRACING_ON=1']) |
| |
| # "Fast" binary |
| makeEnv('fast', '.fo', strip = True, |
| CCFLAGS = Split(ccflags['fast']), |
| CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) |
| |
| # Profiled binary |
| makeEnv('prof', '.po', |
| CCFLAGS = Split(ccflags['prof']), |
| CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], |
| LINKFLAGS = '-pg') |
| |
| Return('envList') |