| # -*- 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 = dict([(opt, env[opt]) for opt in export_vars]) |
| |
| ######################################################################## |
| # 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): |
| bisect.insort_right(base.all, 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 ] |
| debugname = self.snode.abspath |
| if not exists(debugname): |
| debugname = self.tnode.abspath |
| |
| self.package = package |
| self.modname = modname |
| self.modpath = modpath |
| self.arcname = joinpath(*arcpath) |
| self.debugname = debugname |
| self.compiled = File(self.filename + 'c') |
| self.assembly = File(self.filename + '.s') |
| self.symname = "PyEMB_" + 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)) |
| |
| # Add a flag defining what THE_ISA should be for all compilation |
| env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) |
| |
| # 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'), build_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'), build_dir=build_dir) |
| |
| for opt in export_vars: |
| env.ConfigFile(opt) |
| |
| ######################################################################## |
| # |
| # Prevent any SimObjects from being added after this point, they |
| # should all have been added in the SConscripts above |
| # |
| 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 == '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 exists(source.snode.abspath): |
| 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 == 'defines': |
| mod.__dict__['buildEnv'] = build_env |
| return mod |
| |
| source = self.modules[fullname] |
| if source.modname == '__init__': |
| mod.__path__ = source.modpath |
| mod.__file__ = source.snode.abspath |
| |
| exec file(source.snode.abspath, 'r') in mod.__dict__ |
| |
| return mod |
| |
| # 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. |
| SimObject.fixed = True |
| importer = DictImporter(PySource.modules) |
| sys.meta_path[0:0] = [ importer ] |
| |
| import m5 |
| |
| # 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(): |
| 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].tnode for dep in module_depends ] |
| |
| ######################################################################## |
| # |
| # Commands for the basic automatically generated python files |
| # |
| |
| # Generate Python file containing a dict specifying the current |
| # build_env flags. |
| def makeDefinesPyFile(target, source, env): |
| f = file(str(target[0]), 'w') |
| build_env, hg_info = [ x.get_contents() for x in source ] |
| print >>f, "buildEnv = %s" % build_env |
| print >>f, "hgRev = '%s'" % hg_info |
| f.close() |
| |
| 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, makeDefinesPyFile) |
| PySource('m5', 'python/m5/defines.py') |
| |
| # Generate python file containing info about the M5 source code |
| def makeInfoPyFile(target, source, env): |
| f = file(str(target[0]), 'w') |
| for src in source: |
| data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) |
| print >>f, "%s = %s" % (src, repr(data)) |
| f.close() |
| |
| # Generate a file that wraps the basic top level files |
| env.Command('python/m5/info.py', |
| [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], |
| makeInfoPyFile) |
| PySource('m5', 'python/m5/info.py') |
| |
| # Generate the __init__.py file for m5.objects |
| def makeObjectsInitFile(target, source, env): |
| f = file(str(target[0]), 'w') |
| print >>f, 'from params import *' |
| print >>f, 'from m5.SimObject import *' |
| for module in source: |
| print >>f, 'from %s import *' % module.get_contents() |
| f.close() |
| |
| # Generate an __init__.py file for the objects package |
| env.Command('python/m5/objects/__init__.py', |
| map(Value, SimObject.modnames), |
| makeObjectsInitFile) |
| PySource('m5.objects', 'python/m5/objects/__init__.py') |
| |
| ######################################################################## |
| # |
| # Create all of the SimObject param headers and enum headers |
| # |
| |
| def createSimObjectParam(target, source, env): |
| assert len(target) == 1 and len(source) == 1 |
| |
| hh_file = file(target[0].abspath, 'w') |
| name = str(source[0].get_contents()) |
| obj = sim_objects[name] |
| |
| print >>hh_file, obj.cxx_decl() |
| hh_file.close() |
| |
| def createSwigParam(target, source, env): |
| assert len(target) == 1 and len(source) == 1 |
| |
| i_file = file(target[0].abspath, 'w') |
| name = str(source[0].get_contents()) |
| param = all_params[name] |
| |
| for line in param.swig_decl(): |
| print >>i_file, line |
| i_file.close() |
| |
| def createEnumStrings(target, source, env): |
| assert len(target) == 1 and len(source) == 1 |
| |
| cc_file = file(target[0].abspath, 'w') |
| name = str(source[0].get_contents()) |
| obj = all_enums[name] |
| |
| print >>cc_file, obj.cxx_def() |
| cc_file.close() |
| |
| def createEnumParam(target, source, env): |
| assert len(target) == 1 and len(source) == 1 |
| |
| hh_file = file(target[0].abspath, 'w') |
| name = str(source[0].get_contents()) |
| obj = all_enums[name] |
| |
| print >>hh_file, obj.cxx_decl() |
| hh_file.close() |
| |
| # 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), createSimObjectParam) |
| env.Depends(hh_file, depends + extra_deps) |
| |
| # Generate any parameter header files needed |
| params_i_files = [] |
| for name,param in all_params.iteritems(): |
| if isinstance(param, m5.params.VectorParamDesc): |
| ext = 'vptype' |
| else: |
| ext = 'ptype' |
| |
| i_file = File('params/%s_%s.i' % (name, ext)) |
| params_i_files.append(i_file) |
| env.Command(i_file, Value(name), createSwigParam) |
| env.Depends(i_file, depends) |
| |
| # 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), createEnumStrings) |
| env.Depends(cc_file, depends + extra_deps) |
| Source(cc_file) |
| |
| hh_file = File('enums/%s.hh' % name) |
| env.Command(hh_file, Value(name), createEnumParam) |
| env.Depends(hh_file, depends + extra_deps) |
| |
| # Build the big monolithic swigged params module (wraps all SimObject |
| # param structs and enum structs) |
| def buildParams(target, source, env): |
| names = [ s.get_contents() for s in source ] |
| objs = [ sim_objects[name] for name in names ] |
| out = file(target[0].abspath, 'w') |
| |
| ordered_objs = [] |
| obj_seen = set() |
| def order_obj(obj): |
| name = str(obj) |
| if name in obj_seen: |
| return |
| |
| obj_seen.add(name) |
| if str(obj) != 'SimObject': |
| order_obj(obj.__bases__[0]) |
| |
| ordered_objs.append(obj) |
| |
| for obj in objs: |
| order_obj(obj) |
| |
| enums = set() |
| predecls = [] |
| pd_seen = set() |
| |
| def add_pds(*pds): |
| for pd in pds: |
| if pd not in pd_seen: |
| predecls.append(pd) |
| pd_seen.add(pd) |
| |
| for obj in ordered_objs: |
| params = obj._params.local.values() |
| for param in params: |
| ptype = param.ptype |
| if issubclass(ptype, m5.params.Enum): |
| if ptype not in enums: |
| enums.add(ptype) |
| pds = param.swig_predecls() |
| if isinstance(pds, (list, tuple)): |
| add_pds(*pds) |
| else: |
| add_pds(pds) |
| |
| print >>out, '%module params' |
| |
| print >>out, '%{' |
| for obj in ordered_objs: |
| print >>out, '#include "params/%s.hh"' % obj |
| print >>out, '%}' |
| |
| for pd in predecls: |
| print >>out, pd |
| |
| enums = list(enums) |
| enums.sort() |
| for enum in enums: |
| print >>out, '%%include "enums/%s.hh"' % enum.__name__ |
| print >>out |
| |
| for obj in ordered_objs: |
| if obj.swig_objdecls: |
| for decl in obj.swig_objdecls: |
| print >>out, decl |
| continue |
| |
| class_path = obj.cxx_class.split('::') |
| classname = class_path[-1] |
| namespaces = class_path[:-1] |
| namespaces.reverse() |
| |
| code = '' |
| |
| if namespaces: |
| code += '// avoid name conflicts\n' |
| sep_string = '_COLONS_' |
| flat_name = sep_string.join(class_path) |
| code += '%%rename(%s) %s;\n' % (flat_name, classname) |
| |
| code += '// stop swig from creating/wrapping default ctor/dtor\n' |
| code += '%%nodefault %s;\n' % classname |
| code += 'class %s ' % classname |
| if obj._base: |
| code += ': public %s' % obj._base.cxx_class |
| code += ' {};\n' |
| |
| for ns in namespaces: |
| new_code = 'namespace %s {\n' % ns |
| new_code += code |
| new_code += '}\n' |
| code = new_code |
| |
| print >>out, code |
| |
| print >>out, '%%include "src/sim/sim_object_params.hh"' % obj |
| for obj in ordered_objs: |
| print >>out, '%%include "params/%s.hh"' % obj |
| |
| params_file = File('params/params.i') |
| names = sorted(sim_objects.keys()) |
| env.Command(params_file, map(Value, names), buildParams) |
| env.Depends(params_file, params_hh_files + params_i_files + depends) |
| SwigSource('m5.objects', params_file) |
| |
| # Build all swig modules |
| for swig in SwigSource.all: |
| env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, |
| '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' |
| '-o ${TARGETS[0]} $SOURCES') |
| env.Depends(swig.py_source.tnode, swig.tnode) |
| env.Depends(swig.cc_source.tnode, swig.tnode) |
| |
| # Generate the main swig init file |
| def makeSwigInit(target, source, env): |
| f = file(str(target[0]), 'w') |
| print >>f, 'extern "C" {' |
| for module in source: |
| print >>f, ' void init_%s();' % module.get_contents() |
| print >>f, '}' |
| print >>f, 'void initSwig() {' |
| for module in source: |
| print >>f, ' init_%s();' % module.get_contents() |
| print >>f, '}' |
| f.close() |
| |
| env.Command('python/swig/init.cc', |
| map(Value, sorted(s.module for s in SwigSource.all)), |
| makeSwigInit) |
| Source('python/swig/init.cc') |
| |
| 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) |
| |
| f = file(str(target[0]), 'w') |
| |
| allFlags = getFlags(source) |
| |
| print >>f, 'basic = [' |
| for flag, compound, desc in allFlags: |
| if not compound: |
| print >>f, " '%s'," % flag |
| print >>f, " ]" |
| print >>f |
| |
| print >>f, 'compound = [' |
| print >>f, " 'All'," |
| for flag, compound, desc in allFlags: |
| if compound: |
| print >>f, " '%s'," % flag |
| print >>f, " ]" |
| print >>f |
| |
| print >>f, "all = frozenset(basic + compound)" |
| print >>f |
| |
| print >>f, 'compoundMap = {' |
| all = tuple([flag for flag,compound,desc in allFlags if not compound]) |
| print >>f, " 'All' : %s," % (all, ) |
| for flag, compound, desc in allFlags: |
| if compound: |
| print >>f, " '%s' : %s," % (flag, compound) |
| print >>f, " }" |
| print >>f |
| |
| print >>f, 'descriptions = {' |
| print >>f, " 'All' : 'All flags'," |
| for flag, compound, desc in allFlags: |
| print >>f, " '%s' : '%s'," % (flag, desc) |
| print >>f, " }" |
| |
| f.close() |
| |
| def traceFlagsCC(target, source, env): |
| assert(len(target) == 1) |
| |
| f = file(str(target[0]), 'w') |
| |
| allFlags = getFlags(source) |
| |
| # file header |
| print >>f, ''' |
| /* |
| * DO NOT EDIT THIS FILE! Automatically generated |
| */ |
| |
| #include "base/traceflags.hh" |
| |
| using namespace Trace; |
| |
| const char *Trace::flagStrings[] = |
| {''' |
| |
| # 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: |
| print >>f, ' "%s",' % flag |
| |
| print >>f, ' "All",' |
| for flag, compound, desc in allFlags: |
| if compound: |
| print >>f, ' "%s",' % flag |
| |
| print >>f, '};' |
| print >>f |
| print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1) |
| print >>f |
| |
| # |
| # 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]) |
| print >>f, 'static const Flags AllMap[] = {' |
| for flag, compound, desc in allFlags: |
| if not compound: |
| print >>f, " %s," % flag |
| print >>f, '};' |
| print >>f |
| |
| for flag, compound, desc in allFlags: |
| if not compound: |
| continue |
| print >>f, 'static const Flags %sMap[] = {' % flag |
| for flag in compound: |
| print >>f, " %s," % flag |
| print >>f, " (Flags)-1" |
| print >>f, '};' |
| print >>f |
| |
| # |
| # Finally the compoundFlags[] array maps the compound flags |
| # to their individual arrays/ |
| # |
| print >>f, 'const Flags *Trace::compoundFlags[] =' |
| print >>f, '{' |
| print >>f, ' AllMap,' |
| for flag, compound, desc in allFlags: |
| if compound: |
| print >>f, ' %sMap,' % flag |
| # file trailer |
| print >>f, '};' |
| |
| f.close() |
| |
| def traceFlagsHH(target, source, env): |
| assert(len(target) == 1) |
| |
| f = file(str(target[0]), 'w') |
| |
| allFlags = getFlags(source) |
| |
| # file header boilerplate |
| print >>f, ''' |
| /* |
| * 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 |
| for flag, compound, desc in allFlags: |
| if not compound: |
| print >>f, ' %s = %d,' % (flag, idx) |
| idx += 1 |
| |
| numBaseFlags = idx |
| print >>f, ' NumFlags = %d,' % idx |
| |
| # put a comment in here to separate base from compound flags |
| print >>f, ''' |
| // 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.''' |
| |
| print >>f, ' All = %d,' % idx |
| idx += 1 |
| for flag, compound, desc in allFlags: |
| if compound: |
| print >>f, ' %s = %d,' % (flag, idx) |
| idx += 1 |
| |
| numCompoundFlags = idx - numBaseFlags |
| print >>f, ' NumCompoundFlags = %d' % numCompoundFlags |
| |
| # trailer boilerplate |
| print >>f, '''\ |
| }; // 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__ |
| ''' |
| |
| f.close() |
| |
| flags = map(Value, trace_flags.values()) |
| env.Command('base/traceflags.py', flags, traceFlagsPy) |
| PySource('m5', 'base/traceflags.py') |
| |
| env.Command('base/traceflags.hh', flags, traceFlagsHH) |
| env.Command('base/traceflags.cc', flags, traceFlagsCC) |
| 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 an assembly file that |
| # inserts the result into the data section with symbols indicating the |
| # beginning, and end (and with the size at the end) |
| def objectifyPyFile(target, source, env): |
| '''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() |
| dst = file(str(target[0]), 'w') |
| |
| pysource = PySource.tnodes[source[0]] |
| compiled = compile(src, pysource.debugname, 'exec') |
| marshalled = marshal.dumps(compiled) |
| compressed = zlib.compress(marshalled) |
| data = compressed |
| |
| # Some C/C++ compilers prepend an underscore to global symbol |
| # names, so if they're going to do that, we need to prepend that |
| # leading underscore to globals in the assembly file. |
| if env['LEADING_UNDERSCORE']: |
| sym = '_' + pysource.symname |
| else: |
| sym = pysource.symname |
| |
| step = 16 |
| print >>dst, ".data" |
| print >>dst, ".globl %s_beg" % sym |
| print >>dst, ".globl %s_end" % sym |
| print >>dst, "%s_beg:" % sym |
| for i in xrange(0, len(data), step): |
| x = array.array('B', data[i:i+step]) |
| print >>dst, ".byte", ','.join([str(d) for d in x]) |
| print >>dst, "%s_end:" % sym |
| print >>dst, ".long %d" % len(marshalled) |
| |
| for source in PySource.all: |
| env.Command(source.assembly, source.tnode, objectifyPyFile) |
| Source(source.assembly) |
| |
| # Generate init_python.cc which creates a bunch of EmbeddedPyModule |
| # structs that describe the embedded python code. One such struct |
| # contains information about the importer that python uses to get at |
| # the embedded files, and then there's a list of all of the rest that |
| # the importer uses to load the rest on demand. |
| def pythonInit(target, source, env): |
| dst = file(str(target[0]), 'w') |
| |
| def dump_mod(sym, endchar=','): |
| pysource = PySource.symnames[sym] |
| print >>dst, ' { "%s",' % pysource.arcname |
| print >>dst, ' "%s",' % pysource.modpath |
| print >>dst, ' %s_beg, %s_end,' % (sym, sym) |
| print >>dst, ' %s_end - %s_beg,' % (sym, sym) |
| print >>dst, ' *(int *)%s_end }%s' % (sym, endchar) |
| |
| print >>dst, '#include "sim/init.hh"' |
| |
| for sym in source: |
| sym = sym.get_contents() |
| print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym) |
| |
| print >>dst, "const EmbeddedPyModule embeddedPyImporter = " |
| dump_mod("PyEMB_importer", endchar=';'); |
| print >>dst |
| |
| print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {" |
| for i,sym in enumerate(source): |
| sym = sym.get_contents() |
| if sym == "PyEMB_importer": |
| # Skip the importer since we've already exported it |
| continue |
| dump_mod(sym) |
| print >>dst, " { 0, 0, 0, 0, 0, 0 }" |
| print >>dst, "};" |
| |
| |
| env.Command('sim/init_python.cc', |
| map(Value, (s.symname for s in PySource.all)), |
| pythonInit) |
| Source('sim/init_python.cc') |
| |
| ######################################################################## |
| # |
| # 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, cmd) |
| |
| 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') |