summaryrefslogtreecommitdiff
path: root/src/python/generate.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/python/generate.py')
-rw-r--r--src/python/generate.py324
1 files changed, 324 insertions, 0 deletions
diff --git a/src/python/generate.py b/src/python/generate.py
new file mode 100644
index 000000000..6a09b8106
--- /dev/null
+++ b/src/python/generate.py
@@ -0,0 +1,324 @@
+# Copyright (c) 2004-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 imp
+import py_compile
+import sys
+import zipfile
+
+from os.path import basename
+from os.path import exists
+
+class DictImporter(object):
+ '''This importer takes a dictionary of arbitrary module names that
+ map to arbitrary filenames.'''
+ def __init__(self, modules, build_env):
+ self.modules = modules
+ self.installed = set()
+ self.build_env = build_env
+
+ def __del__(self):
+ self.unload()
+
+ def unload(self):
+ for module in self.installed:
+ del sys.modules[module]
+
+ def find_module(self, fullname, path):
+ if fullname == '__scons':
+ return self
+
+ if fullname == 'm5.objects':
+ return self
+
+ if fullname.startswith('m5.internal'):
+ return None
+
+ if fullname in self.modules and exists(self.modules[fullname]):
+ 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 == '__scons':
+ mod.__dict__['m5_build_env'] = self.build_env
+ return mod
+
+ srcfile = self.modules[fullname]
+ if basename(srcfile) == '__init__.py':
+ mod.__path__ = fullname.split('.')
+ mod.__file__ = srcfile
+
+ exec file(srcfile, 'r') in mod.__dict__
+
+ return mod
+
+class ordered_dict(dict):
+ def keys(self):
+ keys = super(ordered_dict, self).keys()
+ keys.sort()
+ return keys
+
+ def values(self):
+ return [ self[key] for key in self.keys() ]
+
+ def items(self):
+ return [ (key,self[key]) for key in self.keys() ]
+
+ def iterkeys(self):
+ for key in self.keys():
+ yield key
+
+ def itervalues(self):
+ for value in self.values():
+ yield value
+
+ def iteritems(self):
+ for key,value in self.items():
+ yield key, value
+
+class Generate(object):
+ def __init__(self, py_sources, sim_objects, build_env):
+ self.py_sources = py_sources
+ self.py_modules = {}
+ for source in py_sources:
+ self.py_modules[source.modpath] = source.srcpath
+
+ importer = DictImporter(self.py_modules, build_env)
+
+ # install the python importer so we can grab stuff from the source
+ # tree itself.
+ sys.meta_path[0:0] = [ importer ]
+
+ import m5
+ self.m5 = 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
+ sim_objects = list(sim_objects)
+ sim_objects.sort()
+ for simobj in sim_objects:
+ exec('from m5.objects import %s' % simobj)
+
+ # 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)
+
+ self.sim_objects = m5.SimObject.allClasses
+ self.enums = m5.params.allEnums
+
+ self.params = {}
+ for name,obj in self.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 self.params:
+ self.params[pname] = param
+
+ def createSimObjectParam(self, 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 = self.sim_objects[name]
+
+ print >>hh_file, obj.cxx_decl()
+
+ # Generate Python file containing a dict specifying the current
+ # build_env flags.
+ def makeDefinesPyFile(self, target, source, env):
+ f = file(str(target[0]), 'w')
+ print >>f, "m5_build_env = ", source[0]
+ f.close()
+
+ # Generate python file containing info about the M5 source code
+ def makeInfoPyFile(self, 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 the __init__.py file for m5.objects
+ def makeObjectsInitFile(self, 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()
+
+ def createSwigParam(self, 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 = self.params[name]
+
+ for line in param.swig_decl():
+ print >>i_file, line
+
+ def createEnumStrings(self, 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 = self.enums[name]
+
+ print >>cc_file, obj.cxx_def()
+ cc_file.close()
+
+ def createEnumParam(self, 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 = self.enums[name]
+
+ print >>hh_file, obj.cxx_decl()
+
+ def buildParams(self, target, source, env):
+ names = [ s.get_contents() for s in source ]
+ objs = [ self.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, self.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, '%%import "enums/%s.hh"' % enum.__name__
+ print >>out
+
+ for obj in ordered_objs:
+ code = 'class %s ' % obj.cxx_class
+ if str(obj) != 'SimObject':
+ code += ': public %s ' % obj.__bases__[0]
+ code += '{};'
+
+ klass = obj.cxx_class;
+ if hasattr(obj, 'cxx_namespace'):
+ code = 'namespace %s { %s }' % (obj.cxx_namespace, code)
+ klass = '%s::%s' % (obj.cxx_namespace, klass)
+
+ print >>out, '%%ignore %s;' % klass
+ print >>out, code
+
+ for obj in ordered_objs:
+ print >>out, '%%include "params/%s.hh"' % obj
+
+ def makeSwigInit(self, 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 init_swig() {'
+ for module in source:
+ print >>f, ' init_%s();' % module.get_contents()
+ print >>f, '}'
+ f.close()
+
+ def compilePyFile(self, target, source, env):
+ '''Action function to compile a .py into a .pyc'''
+ py_compile.compile(str(source[0]), str(target[0]))
+
+ def buildPyZip(self, target, source, env):
+ '''Action function to build the zip archive. Uses the
+ PyZipFile module included in the standard Python library.'''
+
+ py_compiled = {}
+ for s in self.py_sources:
+ compname = str(s.compiled)
+ assert compname not in py_compiled
+ py_compiled[compname] = s
+
+ zf = zipfile.ZipFile(str(target[0]), 'w')
+ for s in source:
+ zipname = str(s)
+ arcname = py_compiled[zipname].arcname
+ zf.write(zipname, arcname)
+ zf.close()