6b167552e5dc0e9f5f9c7e09b63f6ad39ea570da
[gem5.git] / src / python / generate.py
1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #
27 # Authors: Nathan Binkert
28
29 import imp
30 import py_compile
31 import sys
32 import zipfile
33
34 from os.path import basename
35 from os.path import exists
36
37 class DictImporter(object):
38 '''This importer takes a dictionary of arbitrary module names that
39 map to arbitrary filenames.'''
40 def __init__(self, modules, build_env):
41 self.modules = modules
42 self.installed = set()
43 self.build_env = build_env
44
45 def __del__(self):
46 self.unload()
47
48 def unload(self):
49 for module in self.installed:
50 del sys.modules[module]
51
52 def find_module(self, fullname, path):
53 if fullname == '__scons':
54 return self
55
56 if fullname == 'm5.objects':
57 return self
58
59 if fullname.startswith('m5.internal'):
60 return None
61
62 if fullname in self.modules and exists(self.modules[fullname]):
63 return self
64
65 return None
66
67 def load_module(self, fullname):
68 mod = imp.new_module(fullname)
69 sys.modules[fullname] = mod
70 self.installed.add(fullname)
71
72 mod.__loader__ = self
73 if fullname == 'm5.objects':
74 mod.__path__ = fullname.split('.')
75 return mod
76
77 if fullname == '__scons':
78 mod.__dict__['m5_build_env'] = self.build_env
79 return mod
80
81 srcfile = self.modules[fullname]
82 if basename(srcfile) == '__init__.py':
83 mod.__path__ = fullname.split('.')
84 mod.__file__ = srcfile
85
86 exec file(srcfile, 'r') in mod.__dict__
87
88 return mod
89
90 class ordered_dict(dict):
91 def keys(self):
92 keys = super(ordered_dict, self).keys()
93 keys.sort()
94 return keys
95
96 def values(self):
97 return [ self[key] for key in self.keys() ]
98
99 def items(self):
100 return [ (key,self[key]) for key in self.keys() ]
101
102 def iterkeys(self):
103 for key in self.keys():
104 yield key
105
106 def itervalues(self):
107 for value in self.values():
108 yield value
109
110 def iteritems(self):
111 for key,value in self.items():
112 yield key, value
113
114 class Generate(object):
115 def __init__(self, py_sources, sim_objects, build_env):
116 self.py_sources = py_sources
117 self.py_modules = {}
118 for source in py_sources:
119 self.py_modules[source.modpath] = source.srcpath
120
121 importer = DictImporter(self.py_modules, build_env)
122
123 # install the python importer so we can grab stuff from the source
124 # tree itself.
125 sys.meta_path[0:0] = [ importer ]
126
127 import m5
128 self.m5 = m5
129
130 # import all sim objects so we can populate the all_objects list
131 # make sure that we're working with a list, then let's sort it
132 sim_objects = list(sim_objects)
133 sim_objects.sort()
134 for simobj in sim_objects:
135 exec('from m5.objects import %s' % simobj)
136
137 # we need to unload all of the currently imported modules so that they
138 # will be re-imported the next time the sconscript is run
139 importer.unload()
140 sys.meta_path.remove(importer)
141
142 self.sim_objects = m5.SimObject.allClasses
143 self.enums = m5.params.allEnums
144
145 self.params = {}
146 for name,obj in self.sim_objects.iteritems():
147 for param in obj._params.local.values():
148 if not hasattr(param, 'swig_decl'):
149 continue
150 pname = param.ptype_str
151 if pname not in self.params:
152 self.params[pname] = param
153
154 def createSimObjectParam(self, target, source, env):
155 assert len(target) == 1 and len(source) == 1
156
157 hh_file = file(target[0].abspath, 'w')
158 name = str(source[0].get_contents())
159 obj = self.sim_objects[name]
160
161 print >>hh_file, obj.cxx_decl()
162
163 # Generate Python file containing a dict specifying the current
164 # build_env flags.
165 def makeDefinesPyFile(self, target, source, env):
166 f = file(str(target[0]), 'w')
167 print >>f, "m5_build_env = ", source[0]
168 f.close()
169
170 # Generate python file containing info about the M5 source code
171 def makeInfoPyFile(self, target, source, env):
172 f = file(str(target[0]), 'w')
173 for src in source:
174 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
175 print >>f, "%s = %s" % (src, repr(data))
176 f.close()
177
178 # Generate the __init__.py file for m5.objects
179 def makeObjectsInitFile(self, target, source, env):
180 f = file(str(target[0]), 'w')
181 print >>f, 'from params import *'
182 print >>f, 'from m5.SimObject import *'
183 for module in source:
184 print >>f, 'from %s import *' % module.get_contents()
185 f.close()
186
187 def createSwigParam(self, target, source, env):
188 assert len(target) == 1 and len(source) == 1
189
190 i_file = file(target[0].abspath, 'w')
191 name = str(source[0].get_contents())
192 param = self.params[name]
193
194 for line in param.swig_decl():
195 print >>i_file, line
196
197 def createEnumStrings(self, target, source, env):
198 assert len(target) == 1 and len(source) == 1
199
200 cc_file = file(target[0].abspath, 'w')
201 name = str(source[0].get_contents())
202 obj = self.enums[name]
203
204 print >>cc_file, obj.cxx_def()
205 cc_file.close()
206
207 def createEnumParam(self, target, source, env):
208 assert len(target) == 1 and len(source) == 1
209
210 hh_file = file(target[0].abspath, 'w')
211 name = str(source[0].get_contents())
212 obj = self.enums[name]
213
214 print >>hh_file, obj.cxx_decl()
215
216 def buildParams(self, target, source, env):
217 names = [ s.get_contents() for s in source ]
218 objs = [ self.sim_objects[name] for name in names ]
219 out = file(target[0].abspath, 'w')
220
221 ordered_objs = []
222 obj_seen = set()
223 def order_obj(obj):
224 name = str(obj)
225 if name in obj_seen:
226 return
227
228 obj_seen.add(name)
229 if str(obj) != 'SimObject':
230 order_obj(obj.__bases__[0])
231
232 ordered_objs.append(obj)
233
234 for obj in objs:
235 order_obj(obj)
236
237 enums = set()
238 predecls = []
239 pd_seen = set()
240
241 def add_pds(*pds):
242 for pd in pds:
243 if pd not in pd_seen:
244 predecls.append(pd)
245 pd_seen.add(pd)
246
247 for obj in ordered_objs:
248 params = obj._params.local.values()
249 for param in params:
250 ptype = param.ptype
251 if issubclass(ptype, self.m5.params.Enum):
252 if ptype not in enums:
253 enums.add(ptype)
254 pds = param.swig_predecls()
255 if isinstance(pds, (list, tuple)):
256 add_pds(*pds)
257 else:
258 add_pds(pds)
259
260 print >>out, '%module params'
261
262 print >>out, '%{'
263 for obj in ordered_objs:
264 print >>out, '#include "params/%s.hh"' % obj
265 print >>out, '%}'
266
267 for pd in predecls:
268 print >>out, pd
269
270 enums = list(enums)
271 enums.sort()
272 for enum in enums:
273 print >>out, '%%include "enums/%s.hh"' % enum.__name__
274 print >>out
275
276 for obj in ordered_objs:
277 if obj.swig_objdecls:
278 for decl in obj.swig_objdecls:
279 print >>out, decl
280 continue
281
282 code = ''
283 base = obj.get_base()
284
285 code += '// stop swig from creating/wrapping default ctor/dtor\n'
286 code += '%%nodefault %s;\n' % obj.cxx_class
287 code += 'class %s ' % obj.cxx_class
288 if base:
289 code += ': public %s' % base
290 code += ' {};\n'
291
292 klass = obj.cxx_class;
293 if hasattr(obj, 'cxx_namespace'):
294 new_code = 'namespace %s {\n' % obj.cxx_namespace
295 new_code += code
296 new_code += '}\n'
297 code = new_code
298 klass = '%s::%s' % (obj.cxx_namespace, klass)
299
300 print >>out, code
301
302 for obj in ordered_objs:
303 print >>out, '%%include "params/%s.hh"' % obj
304
305 def makeSwigInit(self, target, source, env):
306 f = file(str(target[0]), 'w')
307 print >>f, 'extern "C" {'
308 for module in source:
309 print >>f, ' void init_%s();' % module.get_contents()
310 print >>f, '}'
311 print >>f, 'void init_swig() {'
312 for module in source:
313 print >>f, ' init_%s();' % module.get_contents()
314 print >>f, '}'
315 f.close()
316
317 def compilePyFile(self, target, source, env):
318 '''Action function to compile a .py into a .pyc'''
319 py_compile.compile(str(source[0]), str(target[0]))
320
321 def buildPyZip(self, target, source, env):
322 '''Action function to build the zip archive. Uses the
323 PyZipFile module included in the standard Python library.'''
324
325 py_compiled = {}
326 for s in self.py_sources:
327 compname = str(s.compiled)
328 assert compname not in py_compiled
329 py_compiled[compname] = s
330
331 zf = zipfile.ZipFile(str(target[0]), 'w')
332 for s in source:
333 zipname = str(s)
334 arcname = py_compiled[zipname].arcname
335 zf.write(zipname, arcname)
336 zf.close()