SConscript (5623:11a1079070b6) SConscript (5742:828a8296270e)
1# -*- mode:python -*-
2
3# Copyright (c) 2004-2005 The Regents of The University of Michigan
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met: redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer;
10# redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the
12# documentation and/or other materials provided with the distribution;
13# neither the name of the copyright holders nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29# Authors: Nathan Binkert
30
31import array
32import imp
33import marshal
34import os
35import re
36import sys
37import zlib
38
1# -*- mode:python -*-
2
3# Copyright (c) 2004-2005 The Regents of The University of Michigan
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met: redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer;
10# redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the
12# documentation and/or other materials provided with the distribution;
13# neither the name of the copyright holders nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29# Authors: Nathan Binkert
30
31import array
32import imp
33import marshal
34import os
35import re
36import sys
37import zlib
38
39from os.path import basename, exists, isdir, isfile, join as joinpath
39from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
40
41import SCons
42
43# This file defines how to build a particular configuration of M5
44# based on variable settings in the 'env' build environment.
45
46Import('*')
47
48# Children need to see the environment
49Export('env')
50
51build_env = dict([(opt, env[opt]) for opt in env.ExportOptions])
52
53def sort_list(_list):
54 """return a sorted copy of '_list'"""
55 if isinstance(_list, list):
56 _list = _list[:]
57 else:
58 _list = list(_list)
59 _list.sort()
60 return _list
61
62class PySourceFile(object):
63 invalid_sym_char = re.compile('[^A-z0-9_]')
64 def __init__(self, package, tnode):
65 snode = tnode.srcnode()
66 filename = str(tnode)
67 pyname = basename(filename)
68 assert pyname.endswith('.py')
69 name = pyname[:-3]
70 if package:
71 path = package.split('.')
72 else:
73 path = []
74
75 modpath = path[:]
76 if name != '__init__':
77 modpath += [name]
78 modpath = '.'.join(modpath)
79
80 arcpath = path + [ pyname ]
81 arcname = joinpath(*arcpath)
82
83 debugname = snode.abspath
84 if not exists(debugname):
85 debugname = tnode.abspath
86
87 self.tnode = tnode
88 self.snode = snode
89 self.pyname = pyname
90 self.package = package
91 self.modpath = modpath
92 self.arcname = arcname
93 self.debugname = debugname
94 self.compiled = File(filename + 'c')
95 self.assembly = File(filename + '.s')
96 self.symname = "PyEMB_" + self.invalid_sym_char.sub('_', modpath)
97
98
99########################################################################
100# Code for adding source files of various types
101#
102cc_lib_sources = []
103def Source(source):
104 '''Add a source file to the libm5 build'''
105 if not isinstance(source, SCons.Node.FS.File):
106 source = File(source)
107
108 cc_lib_sources.append(source)
109
110cc_bin_sources = []
111def BinSource(source):
112 '''Add a source file to the m5 binary build'''
113 if not isinstance(source, SCons.Node.FS.File):
114 source = File(source)
115
116 cc_bin_sources.append(source)
117
118py_sources = []
119def PySource(package, source):
120 '''Add a python source file to the named package'''
121 if not isinstance(source, SCons.Node.FS.File):
122 source = File(source)
123
124 source = PySourceFile(package, source)
125 py_sources.append(source)
126
127sim_objects_fixed = False
128sim_object_modfiles = set()
129def SimObject(source):
130 '''Add a SimObject python file as a python source object and add
131 it to a list of sim object modules'''
132
133 if sim_objects_fixed:
134 raise AttributeError, "Too late to call SimObject now."
135
136 if not isinstance(source, SCons.Node.FS.File):
137 source = File(source)
138
139 PySource('m5.objects', source)
140 modfile = basename(str(source))
141 assert modfile.endswith('.py')
142 modname = modfile[:-3]
143 sim_object_modfiles.add(modname)
144
145swig_sources = []
146def SwigSource(package, source):
147 '''Add a swig file to build'''
148 if not isinstance(source, SCons.Node.FS.File):
149 source = File(source)
150 val = source,package
151 swig_sources.append(val)
152
153unit_tests = []
154def UnitTest(target, sources):
155 if not isinstance(sources, (list, tuple)):
156 sources = [ sources ]
157
158 srcs = []
159 for source in sources:
160 if not isinstance(source, SCons.Node.FS.File):
161 source = File(source)
162 srcs.append(source)
163
164 unit_tests.append((target, srcs))
165
166# Children should have access
167Export('Source')
168Export('BinSource')
169Export('PySource')
170Export('SimObject')
171Export('SwigSource')
172Export('UnitTest')
173
174########################################################################
175#
176# Trace Flags
177#
178all_flags = {}
179trace_flags = []
180def TraceFlag(name, desc=''):
181 if name in all_flags:
182 raise AttributeError, "Flag %s already specified" % name
183 flag = (name, (), desc)
184 trace_flags.append(flag)
185 all_flags[name] = ()
186
187def CompoundFlag(name, flags, desc=''):
188 if name in all_flags:
189 raise AttributeError, "Flag %s already specified" % name
190
191 compound = tuple(flags)
192 for flag in compound:
193 if flag not in all_flags:
194 raise AttributeError, "Trace flag %s not found" % flag
195 if all_flags[flag]:
196 raise AttributeError, \
197 "Compound flag can't point to another compound flag"
198
199 flag = (name, compound, desc)
200 trace_flags.append(flag)
201 all_flags[name] = compound
202
203Export('TraceFlag')
204Export('CompoundFlag')
205
206########################################################################
207#
208# Set some compiler variables
209#
210
211# Include file paths are rooted in this directory. SCons will
212# automatically expand '.' to refer to both the source directory and
213# the corresponding build directory to pick up generated include
214# files.
215env.Append(CPPPATH=Dir('.'))
216
40
41import SCons
42
43# This file defines how to build a particular configuration of M5
44# based on variable settings in the 'env' build environment.
45
46Import('*')
47
48# Children need to see the environment
49Export('env')
50
51build_env = dict([(opt, env[opt]) for opt in env.ExportOptions])
52
53def sort_list(_list):
54 """return a sorted copy of '_list'"""
55 if isinstance(_list, list):
56 _list = _list[:]
57 else:
58 _list = list(_list)
59 _list.sort()
60 return _list
61
62class PySourceFile(object):
63 invalid_sym_char = re.compile('[^A-z0-9_]')
64 def __init__(self, package, tnode):
65 snode = tnode.srcnode()
66 filename = str(tnode)
67 pyname = basename(filename)
68 assert pyname.endswith('.py')
69 name = pyname[:-3]
70 if package:
71 path = package.split('.')
72 else:
73 path = []
74
75 modpath = path[:]
76 if name != '__init__':
77 modpath += [name]
78 modpath = '.'.join(modpath)
79
80 arcpath = path + [ pyname ]
81 arcname = joinpath(*arcpath)
82
83 debugname = snode.abspath
84 if not exists(debugname):
85 debugname = tnode.abspath
86
87 self.tnode = tnode
88 self.snode = snode
89 self.pyname = pyname
90 self.package = package
91 self.modpath = modpath
92 self.arcname = arcname
93 self.debugname = debugname
94 self.compiled = File(filename + 'c')
95 self.assembly = File(filename + '.s')
96 self.symname = "PyEMB_" + self.invalid_sym_char.sub('_', modpath)
97
98
99########################################################################
100# Code for adding source files of various types
101#
102cc_lib_sources = []
103def Source(source):
104 '''Add a source file to the libm5 build'''
105 if not isinstance(source, SCons.Node.FS.File):
106 source = File(source)
107
108 cc_lib_sources.append(source)
109
110cc_bin_sources = []
111def BinSource(source):
112 '''Add a source file to the m5 binary build'''
113 if not isinstance(source, SCons.Node.FS.File):
114 source = File(source)
115
116 cc_bin_sources.append(source)
117
118py_sources = []
119def PySource(package, source):
120 '''Add a python source file to the named package'''
121 if not isinstance(source, SCons.Node.FS.File):
122 source = File(source)
123
124 source = PySourceFile(package, source)
125 py_sources.append(source)
126
127sim_objects_fixed = False
128sim_object_modfiles = set()
129def SimObject(source):
130 '''Add a SimObject python file as a python source object and add
131 it to a list of sim object modules'''
132
133 if sim_objects_fixed:
134 raise AttributeError, "Too late to call SimObject now."
135
136 if not isinstance(source, SCons.Node.FS.File):
137 source = File(source)
138
139 PySource('m5.objects', source)
140 modfile = basename(str(source))
141 assert modfile.endswith('.py')
142 modname = modfile[:-3]
143 sim_object_modfiles.add(modname)
144
145swig_sources = []
146def SwigSource(package, source):
147 '''Add a swig file to build'''
148 if not isinstance(source, SCons.Node.FS.File):
149 source = File(source)
150 val = source,package
151 swig_sources.append(val)
152
153unit_tests = []
154def UnitTest(target, sources):
155 if not isinstance(sources, (list, tuple)):
156 sources = [ sources ]
157
158 srcs = []
159 for source in sources:
160 if not isinstance(source, SCons.Node.FS.File):
161 source = File(source)
162 srcs.append(source)
163
164 unit_tests.append((target, srcs))
165
166# Children should have access
167Export('Source')
168Export('BinSource')
169Export('PySource')
170Export('SimObject')
171Export('SwigSource')
172Export('UnitTest')
173
174########################################################################
175#
176# Trace Flags
177#
178all_flags = {}
179trace_flags = []
180def TraceFlag(name, desc=''):
181 if name in all_flags:
182 raise AttributeError, "Flag %s already specified" % name
183 flag = (name, (), desc)
184 trace_flags.append(flag)
185 all_flags[name] = ()
186
187def CompoundFlag(name, flags, desc=''):
188 if name in all_flags:
189 raise AttributeError, "Flag %s already specified" % name
190
191 compound = tuple(flags)
192 for flag in compound:
193 if flag not in all_flags:
194 raise AttributeError, "Trace flag %s not found" % flag
195 if all_flags[flag]:
196 raise AttributeError, \
197 "Compound flag can't point to another compound flag"
198
199 flag = (name, compound, desc)
200 trace_flags.append(flag)
201 all_flags[name] = compound
202
203Export('TraceFlag')
204Export('CompoundFlag')
205
206########################################################################
207#
208# Set some compiler variables
209#
210
211# Include file paths are rooted in this directory. SCons will
212# automatically expand '.' to refer to both the source directory and
213# the corresponding build directory to pick up generated include
214# files.
215env.Append(CPPPATH=Dir('.'))
216
217for extra_dir in extras_dir_list:
218 env.Append(CPPPATH=Dir(extra_dir))
219
217# Add a flag defining what THE_ISA should be for all compilation
218env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
219
220########################################################################
221#
222# Walk the tree and execute all SConscripts in subdirectories
223#
224
220# Add a flag defining what THE_ISA should be for all compilation
221env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
222
223########################################################################
224#
225# Walk the tree and execute all SConscripts in subdirectories
226#
227
225for base_dir in base_dir_list:
226 here = Dir('.').srcnode().abspath
227 for root, dirs, files in os.walk(base_dir, topdown=True):
228 if root == here:
229 # we don't want to recurse back into this SConscript
230 continue
228here = Dir('.').srcnode().abspath
229for root, dirs, files in os.walk(base_dir, topdown=True):
230 if root == here:
231 # we don't want to recurse back into this SConscript
232 continue
231
233
234 if 'SConscript' in files:
235 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
236 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
237
238for extra_dir in extras_dir_list:
239 prefix_len = len(dirname(extra_dir)) + 1
240 for root, dirs, files in os.walk(extra_dir, topdown=True):
232 if 'SConscript' in files:
241 if 'SConscript' in files:
233 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
242 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
234 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
235
236for opt in env.ExportOptions:
237 env.ConfigFile(opt)
238
239########################################################################
240#
241# Prevent any SimObjects from being added after this point, they
242# should all have been added in the SConscripts above
243#
244class DictImporter(object):
245 '''This importer takes a dictionary of arbitrary module names that
246 map to arbitrary filenames.'''
247 def __init__(self, modules):
248 self.modules = modules
249 self.installed = set()
250
251 def __del__(self):
252 self.unload()
253
254 def unload(self):
255 import sys
256 for module in self.installed:
257 del sys.modules[module]
258 self.installed = set()
259
260 def find_module(self, fullname, path):
261 if fullname == '__scons':
262 return self
263
264 if fullname == 'm5.objects':
265 return self
266
267 if fullname.startswith('m5.internal'):
268 return None
269
270 if fullname in self.modules and exists(self.modules[fullname]):
271 return self
272
273 return None
274
275 def load_module(self, fullname):
276 mod = imp.new_module(fullname)
277 sys.modules[fullname] = mod
278 self.installed.add(fullname)
279
280 mod.__loader__ = self
281 if fullname == 'm5.objects':
282 mod.__path__ = fullname.split('.')
283 return mod
284
285 if fullname == '__scons':
286 mod.__dict__['m5_build_env'] = build_env
287 return mod
288
289 srcfile = self.modules[fullname]
290 if basename(srcfile) == '__init__.py':
291 mod.__path__ = fullname.split('.')
292 mod.__file__ = srcfile
293
294 exec file(srcfile, 'r') in mod.__dict__
295
296 return mod
297
298py_modules = {}
299for source in py_sources:
300 py_modules[source.modpath] = source.snode.abspath
301
302# install the python importer so we can grab stuff from the source
303# tree itself. We can't have SimObjects added after this point or
304# else we won't know about them for the rest of the stuff.
305sim_objects_fixed = True
306importer = DictImporter(py_modules)
307sys.meta_path[0:0] = [ importer ]
308
309import m5
310
311# import all sim objects so we can populate the all_objects list
312# make sure that we're working with a list, then let's sort it
313sim_objects = list(sim_object_modfiles)
314sim_objects.sort()
315for simobj in sim_objects:
316 exec('from m5.objects import %s' % simobj)
317
318# we need to unload all of the currently imported modules so that they
319# will be re-imported the next time the sconscript is run
320importer.unload()
321sys.meta_path.remove(importer)
322
323sim_objects = m5.SimObject.allClasses
324all_enums = m5.params.allEnums
325
326all_params = {}
327for name,obj in sim_objects.iteritems():
328 for param in obj._params.local.values():
329 if not hasattr(param, 'swig_decl'):
330 continue
331 pname = param.ptype_str
332 if pname not in all_params:
333 all_params[pname] = param
334
335########################################################################
336#
337# calculate extra dependencies
338#
339module_depends = ["m5", "m5.SimObject", "m5.params"]
340depends = [ File(py_modules[dep]) for dep in module_depends ]
341
342########################################################################
343#
344# Commands for the basic automatically generated python files
345#
346
347# Generate Python file containing a dict specifying the current
348# build_env flags.
349def makeDefinesPyFile(target, source, env):
350 f = file(str(target[0]), 'w')
351 print >>f, "m5_build_env = ", source[0]
352 f.close()
353
354# Generate python file containing info about the M5 source code
355def makeInfoPyFile(target, source, env):
356 f = file(str(target[0]), 'w')
357 for src in source:
358 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
359 print >>f, "%s = %s" % (src, repr(data))
360 f.close()
361
362# Generate the __init__.py file for m5.objects
363def makeObjectsInitFile(target, source, env):
364 f = file(str(target[0]), 'w')
365 print >>f, 'from params import *'
366 print >>f, 'from m5.SimObject import *'
367 for module in source:
368 print >>f, 'from %s import *' % module.get_contents()
369 f.close()
370
371# Generate a file with all of the compile options in it
372env.Command('python/m5/defines.py', Value(build_env), makeDefinesPyFile)
373PySource('m5', 'python/m5/defines.py')
374
375# Generate a file that wraps the basic top level files
376env.Command('python/m5/info.py',
377 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
378 makeInfoPyFile)
379PySource('m5', 'python/m5/info.py')
380
381# Generate an __init__.py file for the objects package
382env.Command('python/m5/objects/__init__.py',
383 [ Value(o) for o in sort_list(sim_object_modfiles) ],
384 makeObjectsInitFile)
385PySource('m5.objects', 'python/m5/objects/__init__.py')
386
387########################################################################
388#
389# Create all of the SimObject param headers and enum headers
390#
391
392def createSimObjectParam(target, source, env):
393 assert len(target) == 1 and len(source) == 1
394
395 hh_file = file(target[0].abspath, 'w')
396 name = str(source[0].get_contents())
397 obj = sim_objects[name]
398
399 print >>hh_file, obj.cxx_decl()
400
401def createSwigParam(target, source, env):
402 assert len(target) == 1 and len(source) == 1
403
404 i_file = file(target[0].abspath, 'w')
405 name = str(source[0].get_contents())
406 param = all_params[name]
407
408 for line in param.swig_decl():
409 print >>i_file, line
410
411def createEnumStrings(target, source, env):
412 assert len(target) == 1 and len(source) == 1
413
414 cc_file = file(target[0].abspath, 'w')
415 name = str(source[0].get_contents())
416 obj = all_enums[name]
417
418 print >>cc_file, obj.cxx_def()
419 cc_file.close()
420
421def createEnumParam(target, source, env):
422 assert len(target) == 1 and len(source) == 1
423
424 hh_file = file(target[0].abspath, 'w')
425 name = str(source[0].get_contents())
426 obj = all_enums[name]
427
428 print >>hh_file, obj.cxx_decl()
429
430# Generate all of the SimObject param struct header files
431params_hh_files = []
432for name,simobj in sim_objects.iteritems():
433 extra_deps = [ File(py_modules[simobj.__module__]) ]
434
435 hh_file = File('params/%s.hh' % name)
436 params_hh_files.append(hh_file)
437 env.Command(hh_file, Value(name), createSimObjectParam)
438 env.Depends(hh_file, depends + extra_deps)
439
440# Generate any parameter header files needed
441params_i_files = []
442for name,param in all_params.iteritems():
443 if isinstance(param, m5.params.VectorParamDesc):
444 ext = 'vptype'
445 else:
446 ext = 'ptype'
447
448 i_file = File('params/%s_%s.i' % (name, ext))
449 params_i_files.append(i_file)
450 env.Command(i_file, Value(name), createSwigParam)
451 env.Depends(i_file, depends)
452
453# Generate all enum header files
454for name,enum in all_enums.iteritems():
455 extra_deps = [ File(py_modules[enum.__module__]) ]
456
457 cc_file = File('enums/%s.cc' % name)
458 env.Command(cc_file, Value(name), createEnumStrings)
459 env.Depends(cc_file, depends + extra_deps)
460 Source(cc_file)
461
462 hh_file = File('enums/%s.hh' % name)
463 env.Command(hh_file, Value(name), createEnumParam)
464 env.Depends(hh_file, depends + extra_deps)
465
466# Build the big monolithic swigged params module (wraps all SimObject
467# param structs and enum structs)
468def buildParams(target, source, env):
469 names = [ s.get_contents() for s in source ]
470 objs = [ sim_objects[name] for name in names ]
471 out = file(target[0].abspath, 'w')
472
473 ordered_objs = []
474 obj_seen = set()
475 def order_obj(obj):
476 name = str(obj)
477 if name in obj_seen:
478 return
479
480 obj_seen.add(name)
481 if str(obj) != 'SimObject':
482 order_obj(obj.__bases__[0])
483
484 ordered_objs.append(obj)
485
486 for obj in objs:
487 order_obj(obj)
488
489 enums = set()
490 predecls = []
491 pd_seen = set()
492
493 def add_pds(*pds):
494 for pd in pds:
495 if pd not in pd_seen:
496 predecls.append(pd)
497 pd_seen.add(pd)
498
499 for obj in ordered_objs:
500 params = obj._params.local.values()
501 for param in params:
502 ptype = param.ptype
503 if issubclass(ptype, m5.params.Enum):
504 if ptype not in enums:
505 enums.add(ptype)
506 pds = param.swig_predecls()
507 if isinstance(pds, (list, tuple)):
508 add_pds(*pds)
509 else:
510 add_pds(pds)
511
512 print >>out, '%module params'
513
514 print >>out, '%{'
515 for obj in ordered_objs:
516 print >>out, '#include "params/%s.hh"' % obj
517 print >>out, '%}'
518
519 for pd in predecls:
520 print >>out, pd
521
522 enums = list(enums)
523 enums.sort()
524 for enum in enums:
525 print >>out, '%%include "enums/%s.hh"' % enum.__name__
526 print >>out
527
528 for obj in ordered_objs:
529 if obj.swig_objdecls:
530 for decl in obj.swig_objdecls:
531 print >>out, decl
532 continue
533
534 class_path = obj.cxx_class.split('::')
535 classname = class_path[-1]
536 namespaces = class_path[:-1]
537 namespaces.reverse()
538
539 code = ''
540
541 if namespaces:
542 code += '// avoid name conflicts\n'
543 sep_string = '_COLONS_'
544 flat_name = sep_string.join(class_path)
545 code += '%%rename(%s) %s;\n' % (flat_name, classname)
546
547 code += '// stop swig from creating/wrapping default ctor/dtor\n'
548 code += '%%nodefault %s;\n' % classname
549 code += 'class %s ' % classname
550 if obj._base:
551 code += ': public %s' % obj._base.cxx_class
552 code += ' {};\n'
553
554 for ns in namespaces:
555 new_code = 'namespace %s {\n' % ns
556 new_code += code
557 new_code += '}\n'
558 code = new_code
559
560 print >>out, code
561
562 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj
563 for obj in ordered_objs:
564 print >>out, '%%include "params/%s.hh"' % obj
565
566params_file = File('params/params.i')
567names = sort_list(sim_objects.keys())
568env.Command(params_file, [ Value(v) for v in names ], buildParams)
569env.Depends(params_file, params_hh_files + params_i_files + depends)
570SwigSource('m5.objects', params_file)
571
572# Build all swig modules
573swig_modules = []
574cc_swig_sources = []
575for source,package in swig_sources:
576 filename = str(source)
577 assert filename.endswith('.i')
578
579 base = '.'.join(filename.split('.')[:-1])
580 module = basename(base)
581 cc_file = base + '_wrap.cc'
582 py_file = base + '.py'
583
584 env.Command([cc_file, py_file], source,
585 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
586 '-o ${TARGETS[0]} $SOURCES')
587 env.Depends(py_file, source)
588 env.Depends(cc_file, source)
589
590 swig_modules.append(Value(module))
591 cc_swig_sources.append(File(cc_file))
592 PySource(package, py_file)
593
594# Generate the main swig init file
595def makeSwigInit(target, source, env):
596 f = file(str(target[0]), 'w')
597 print >>f, 'extern "C" {'
598 for module in source:
599 print >>f, ' void init_%s();' % module.get_contents()
600 print >>f, '}'
601 print >>f, 'void initSwig() {'
602 for module in source:
603 print >>f, ' init_%s();' % module.get_contents()
604 print >>f, '}'
605 f.close()
606
607env.Command('python/swig/init.cc', swig_modules, makeSwigInit)
608Source('python/swig/init.cc')
609
610# Generate traceflags.py
611def traceFlagsPy(target, source, env):
612 assert(len(target) == 1)
613
614 f = file(str(target[0]), 'w')
615
616 allFlags = []
617 for s in source:
618 val = eval(s.get_contents())
619 allFlags.append(val)
620
621 print >>f, 'baseFlags = ['
622 for flag, compound, desc in allFlags:
623 if not compound:
624 print >>f, " '%s'," % flag
625 print >>f, " ]"
626 print >>f
627
628 print >>f, 'compoundFlags = ['
629 print >>f, " 'All',"
630 for flag, compound, desc in allFlags:
631 if compound:
632 print >>f, " '%s'," % flag
633 print >>f, " ]"
634 print >>f
635
636 print >>f, "allFlags = frozenset(baseFlags + compoundFlags)"
637 print >>f
638
639 print >>f, 'compoundFlagMap = {'
640 all = tuple([flag for flag,compound,desc in allFlags if not compound])
641 print >>f, " 'All' : %s," % (all, )
642 for flag, compound, desc in allFlags:
643 if compound:
644 print >>f, " '%s' : %s," % (flag, compound)
645 print >>f, " }"
646 print >>f
647
648 print >>f, 'flagDescriptions = {'
649 print >>f, " 'All' : 'All flags',"
650 for flag, compound, desc in allFlags:
651 print >>f, " '%s' : '%s'," % (flag, desc)
652 print >>f, " }"
653
654 f.close()
655
656def traceFlagsCC(target, source, env):
657 assert(len(target) == 1)
658
659 f = file(str(target[0]), 'w')
660
661 allFlags = []
662 for s in source:
663 val = eval(s.get_contents())
664 allFlags.append(val)
665
666 # file header
667 print >>f, '''
668/*
669 * DO NOT EDIT THIS FILE! Automatically generated
670 */
671
672#include "base/traceflags.hh"
673
674using namespace Trace;
675
676const char *Trace::flagStrings[] =
677{'''
678
679 # The string array is used by SimpleEnumParam to map the strings
680 # provided by the user to enum values.
681 for flag, compound, desc in allFlags:
682 if not compound:
683 print >>f, ' "%s",' % flag
684
685 print >>f, ' "All",'
686 for flag, compound, desc in allFlags:
687 if compound:
688 print >>f, ' "%s",' % flag
689
690 print >>f, '};'
691 print >>f
692 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
693 print >>f
694
695 #
696 # Now define the individual compound flag arrays. There is an array
697 # for each compound flag listing the component base flags.
698 #
699 all = tuple([flag for flag,compound,desc in allFlags if not compound])
700 print >>f, 'static const Flags AllMap[] = {'
701 for flag, compound, desc in allFlags:
702 if not compound:
703 print >>f, " %s," % flag
704 print >>f, '};'
705 print >>f
706
707 for flag, compound, desc in allFlags:
708 if not compound:
709 continue
710 print >>f, 'static const Flags %sMap[] = {' % flag
711 for flag in compound:
712 print >>f, " %s," % flag
713 print >>f, " (Flags)-1"
714 print >>f, '};'
715 print >>f
716
717 #
718 # Finally the compoundFlags[] array maps the compound flags
719 # to their individual arrays/
720 #
721 print >>f, 'const Flags *Trace::compoundFlags[] ='
722 print >>f, '{'
723 print >>f, ' AllMap,'
724 for flag, compound, desc in allFlags:
725 if compound:
726 print >>f, ' %sMap,' % flag
727 # file trailer
728 print >>f, '};'
729
730 f.close()
731
732def traceFlagsHH(target, source, env):
733 assert(len(target) == 1)
734
735 f = file(str(target[0]), 'w')
736
737 allFlags = []
738 for s in source:
739 val = eval(s.get_contents())
740 allFlags.append(val)
741
742 # file header boilerplate
743 print >>f, '''
744/*
745 * DO NOT EDIT THIS FILE!
746 *
747 * Automatically generated from traceflags.py
748 */
749
750#ifndef __BASE_TRACE_FLAGS_HH__
751#define __BASE_TRACE_FLAGS_HH__
752
753namespace Trace {
754
755enum Flags {'''
756
757 # Generate the enum. Base flags come first, then compound flags.
758 idx = 0
759 for flag, compound, desc in allFlags:
760 if not compound:
761 print >>f, ' %s = %d,' % (flag, idx)
762 idx += 1
763
764 numBaseFlags = idx
765 print >>f, ' NumFlags = %d,' % idx
766
767 # put a comment in here to separate base from compound flags
768 print >>f, '''
769// The remaining enum values are *not* valid indices for Trace::flags.
770// They are "compound" flags, which correspond to sets of base
771// flags, and are used by changeFlag.'''
772
773 print >>f, ' All = %d,' % idx
774 idx += 1
775 for flag, compound, desc in allFlags:
776 if compound:
777 print >>f, ' %s = %d,' % (flag, idx)
778 idx += 1
779
780 numCompoundFlags = idx - numBaseFlags
781 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags
782
783 # trailer boilerplate
784 print >>f, '''\
785}; // enum Flags
786
787// Array of strings for SimpleEnumParam
788extern const char *flagStrings[];
789extern const int numFlagStrings;
790
791// Array of arraay pointers: for each compound flag, gives the list of
792// base flags to set. Inidividual flag arrays are terminated by -1.
793extern const Flags *compoundFlags[];
794
795/* namespace Trace */ }
796
797#endif // __BASE_TRACE_FLAGS_HH__
798'''
799
800 f.close()
801
802flags = [ Value(f) for f in trace_flags ]
803env.Command('base/traceflags.py', flags, traceFlagsPy)
804PySource('m5', 'base/traceflags.py')
805
806env.Command('base/traceflags.hh', flags, traceFlagsHH)
807env.Command('base/traceflags.cc', flags, traceFlagsCC)
808Source('base/traceflags.cc')
809
810# Generate program_info.cc
811def programInfo(target, source, env):
812 def gen_file(target, rev, node, date):
813 pi_stats = file(target, 'w')
814 print >>pi_stats, 'const char *hgRev = "%s:%s";' % (rev, node)
815 print >>pi_stats, 'const char *hgDate = "%s";' % date
816 pi_stats.close()
817
818 target = str(target[0])
819 scons_dir = str(source[0].get_contents())
820 try:
821 import mercurial.demandimport, mercurial.hg, mercurial.ui
822 import mercurial.util, mercurial.node
823 if not exists(scons_dir) or not isdir(scons_dir) or \
824 not exists(joinpath(scons_dir, ".hg")):
825 raise ValueError
826 repo = mercurial.hg.repository(mercurial.ui.ui(), scons_dir)
827 rev = mercurial.node.nullrev + repo.changelog.count()
828 changenode = repo.changelog.node(rev)
829 changes = repo.changelog.read(changenode)
830 date = mercurial.util.datestr(changes[2])
831
832 gen_file(target, rev, mercurial.node.hex(changenode), date)
833
834 mercurial.demandimport.disable()
835 except ImportError:
836 gen_file(target, "Unknown", "Unknown", "Unknown")
837
838 except:
839 print "in except"
840 gen_file(target, "Unknown", "Unknown", "Unknown")
841 mercurial.demandimport.disable()
842
843env.Command('base/program_info.cc',
844 Value(str(SCons.Node.FS.default_fs.SConstruct_dir)),
845 programInfo)
846
847# embed python files. All .py files that have been indicated by a
848# PySource() call in a SConscript need to be embedded into the M5
849# library. To do that, we compile the file to byte code, marshal the
850# byte code, compress it, and then generate an assembly file that
851# inserts the result into the data section with symbols indicating the
852# beginning, and end (and with the size at the end)
853py_sources_tnodes = {}
854for pysource in py_sources:
855 py_sources_tnodes[pysource.tnode] = pysource
856
857def objectifyPyFile(target, source, env):
858 '''Action function to compile a .py into a code object, marshal
859 it, compress it, and stick it into an asm file so the code appears
860 as just bytes with a label in the data section'''
861
862 src = file(str(source[0]), 'r').read()
863 dst = file(str(target[0]), 'w')
864
865 pysource = py_sources_tnodes[source[0]]
866 compiled = compile(src, pysource.debugname, 'exec')
867 marshalled = marshal.dumps(compiled)
868 compressed = zlib.compress(marshalled)
869 data = compressed
870
871 # Some C/C++ compilers prepend an underscore to global symbol
872 # names, so if they're going to do that, we need to prepend that
873 # leading underscore to globals in the assembly file.
874 if env['LEADING_UNDERSCORE']:
875 sym = '_' + pysource.symname
876 else:
877 sym = pysource.symname
878
879 step = 16
880 print >>dst, ".data"
881 print >>dst, ".globl %s_beg" % sym
882 print >>dst, ".globl %s_end" % sym
883 print >>dst, "%s_beg:" % sym
884 for i in xrange(0, len(data), step):
885 x = array.array('B', data[i:i+step])
886 print >>dst, ".byte", ','.join([str(d) for d in x])
887 print >>dst, "%s_end:" % sym
888 print >>dst, ".long %d" % len(marshalled)
889
890for source in py_sources:
891 env.Command(source.assembly, source.tnode, objectifyPyFile)
892 Source(source.assembly)
893
894# Generate init_python.cc which creates a bunch of EmbeddedPyModule
895# structs that describe the embedded python code. One such struct
896# contains information about the importer that python uses to get at
897# the embedded files, and then there's a list of all of the rest that
898# the importer uses to load the rest on demand.
899py_sources_symbols = {}
900for pysource in py_sources:
901 py_sources_symbols[pysource.symname] = pysource
902def pythonInit(target, source, env):
903 dst = file(str(target[0]), 'w')
904
905 def dump_mod(sym, endchar=','):
906 pysource = py_sources_symbols[sym]
907 print >>dst, ' { "%s",' % pysource.arcname
908 print >>dst, ' "%s",' % pysource.modpath
909 print >>dst, ' %s_beg, %s_end,' % (sym, sym)
910 print >>dst, ' %s_end - %s_beg,' % (sym, sym)
911 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar)
912
913 print >>dst, '#include "sim/init.hh"'
914
915 for sym in source:
916 sym = sym.get_contents()
917 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym)
918
919 print >>dst, "const EmbeddedPyModule embeddedPyImporter = "
920 dump_mod("PyEMB_importer", endchar=';');
921 print >>dst
922
923 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {"
924 for i,sym in enumerate(source):
925 sym = sym.get_contents()
926 if sym == "PyEMB_importer":
927 # Skip the importer since we've already exported it
928 continue
929 dump_mod(sym)
930 print >>dst, " { 0, 0, 0, 0, 0, 0 }"
931 print >>dst, "};"
932
933symbols = [Value(s.symname) for s in py_sources]
934env.Command('sim/init_python.cc', symbols, pythonInit)
935Source('sim/init_python.cc')
936
937########################################################################
938#
939# Define binaries. Each different build type (debug, opt, etc.) gets
940# a slightly different build environment.
941#
942
943# List of constructed environments to pass back to SConstruct
944envList = []
945
946# This function adds the specified sources to the given build
947# environment, and returns a list of all the corresponding SCons
948# Object nodes (including an extra one for date.cc). We explicitly
949# add the Object nodes so we can set up special dependencies for
950# date.cc.
951def make_objs(sources, env, static):
952 if static:
953 XObject = env.StaticObject
954 else:
955 XObject = env.SharedObject
956
957 objs = [ XObject(s) for s in sources ]
958
959 # make date.cc depend on all other objects so it always gets
960 # recompiled whenever anything else does
961 date_obj = XObject('base/date.cc')
962
963 # Make the generation of program_info.cc dependend on all
964 # the other cc files and the compiling of program_info.cc
965 # dependent on all the objects but program_info.o
966 pinfo_obj = XObject('base/program_info.cc')
967 env.Depends('base/program_info.cc', sources)
968 env.Depends(date_obj, objs)
969 env.Depends(pinfo_obj, objs)
970 objs.extend([date_obj, pinfo_obj])
971 return objs
972
973# Function to create a new build environment as clone of current
974# environment 'env' with modified object suffix and optional stripped
975# binary. Additional keyword arguments are appended to corresponding
976# build environment vars.
977def makeEnv(label, objsfx, strip = False, **kwargs):
978 # SCons doesn't know to append a library suffix when there is a '.' in the
979 # name. Use '_' instead.
980 libname = 'm5_' + label
981 exename = 'm5.' + label
982
983 new_env = env.Copy(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
984 new_env.Label = label
985 new_env.Append(**kwargs)
986
987 swig_env = new_env.Copy()
988 if env['GCC']:
989 swig_env.Append(CCFLAGS='-Wno-uninitialized')
990 swig_env.Append(CCFLAGS='-Wno-sign-compare')
991 swig_env.Append(CCFLAGS='-Wno-parentheses')
992
993 static_objs = make_objs(cc_lib_sources, new_env, static=True)
994 shared_objs = make_objs(cc_lib_sources, new_env, static=False)
995 static_objs += [ swig_env.StaticObject(s) for s in cc_swig_sources ]
996 shared_objs += [ swig_env.SharedObject(s) for s in cc_swig_sources ]
997
998 # First make a library of everything but main() so other programs can
999 # link against m5.
1000 static_lib = new_env.StaticLibrary(libname, static_objs + static_objs)
1001 shared_lib = new_env.SharedLibrary(libname, shared_objs + shared_objs)
1002
1003 for target, sources in unit_tests:
1004 objs = [ new_env.StaticObject(s) for s in sources ]
1005 new_env.Program("unittest/%s.%s" % (target, label), objs + static_lib)
1006
1007 # Now link a stub with main() and the static library.
1008 objects = [new_env.Object(s) for s in cc_bin_sources] + static_lib
1009 if strip:
1010 unstripped_exe = exename + '.unstripped'
1011 new_env.Program(unstripped_exe, objects)
1012 if sys.platform == 'sunos5':
1013 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1014 else:
1015 cmd = 'strip $SOURCE -o $TARGET'
1016 targets = new_env.Command(exename, unstripped_exe, cmd)
1017 else:
1018 targets = new_env.Program(exename, objects)
1019
1020 new_env.M5Binary = targets[0]
1021 envList.append(new_env)
1022
1023# Debug binary
1024ccflags = {}
1025if env['GCC']:
1026 if sys.platform == 'sunos5':
1027 ccflags['debug'] = '-gstabs+'
1028 else:
1029 ccflags['debug'] = '-ggdb3'
1030 ccflags['opt'] = '-g -O3'
1031 ccflags['fast'] = '-O3'
1032 ccflags['prof'] = '-O3 -g -pg'
1033elif env['SUNCC']:
1034 ccflags['debug'] = '-g0'
1035 ccflags['opt'] = '-g -O'
1036 ccflags['fast'] = '-fast'
1037 ccflags['prof'] = '-fast -g -pg'
1038elif env['ICC']:
1039 ccflags['debug'] = '-g -O0'
1040 ccflags['opt'] = '-g -O'
1041 ccflags['fast'] = '-fast'
1042 ccflags['prof'] = '-fast -g -pg'
1043else:
1044 print 'Unknown compiler, please fix compiler options'
1045 Exit(1)
1046
1047makeEnv('debug', '.do',
1048 CCFLAGS = Split(ccflags['debug']),
1049 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1050
1051# Optimized binary
1052makeEnv('opt', '.o',
1053 CCFLAGS = Split(ccflags['opt']),
1054 CPPDEFINES = ['TRACING_ON=1'])
1055
1056# "Fast" binary
1057makeEnv('fast', '.fo', strip = True,
1058 CCFLAGS = Split(ccflags['fast']),
1059 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1060
1061# Profiled binary
1062makeEnv('prof', '.po',
1063 CCFLAGS = Split(ccflags['prof']),
1064 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1065 LINKFLAGS = '-pg')
1066
1067Return('envList')
243 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
244
245for opt in env.ExportOptions:
246 env.ConfigFile(opt)
247
248########################################################################
249#
250# Prevent any SimObjects from being added after this point, they
251# should all have been added in the SConscripts above
252#
253class DictImporter(object):
254 '''This importer takes a dictionary of arbitrary module names that
255 map to arbitrary filenames.'''
256 def __init__(self, modules):
257 self.modules = modules
258 self.installed = set()
259
260 def __del__(self):
261 self.unload()
262
263 def unload(self):
264 import sys
265 for module in self.installed:
266 del sys.modules[module]
267 self.installed = set()
268
269 def find_module(self, fullname, path):
270 if fullname == '__scons':
271 return self
272
273 if fullname == 'm5.objects':
274 return self
275
276 if fullname.startswith('m5.internal'):
277 return None
278
279 if fullname in self.modules and exists(self.modules[fullname]):
280 return self
281
282 return None
283
284 def load_module(self, fullname):
285 mod = imp.new_module(fullname)
286 sys.modules[fullname] = mod
287 self.installed.add(fullname)
288
289 mod.__loader__ = self
290 if fullname == 'm5.objects':
291 mod.__path__ = fullname.split('.')
292 return mod
293
294 if fullname == '__scons':
295 mod.__dict__['m5_build_env'] = build_env
296 return mod
297
298 srcfile = self.modules[fullname]
299 if basename(srcfile) == '__init__.py':
300 mod.__path__ = fullname.split('.')
301 mod.__file__ = srcfile
302
303 exec file(srcfile, 'r') in mod.__dict__
304
305 return mod
306
307py_modules = {}
308for source in py_sources:
309 py_modules[source.modpath] = source.snode.abspath
310
311# install the python importer so we can grab stuff from the source
312# tree itself. We can't have SimObjects added after this point or
313# else we won't know about them for the rest of the stuff.
314sim_objects_fixed = True
315importer = DictImporter(py_modules)
316sys.meta_path[0:0] = [ importer ]
317
318import m5
319
320# import all sim objects so we can populate the all_objects list
321# make sure that we're working with a list, then let's sort it
322sim_objects = list(sim_object_modfiles)
323sim_objects.sort()
324for simobj in sim_objects:
325 exec('from m5.objects import %s' % simobj)
326
327# we need to unload all of the currently imported modules so that they
328# will be re-imported the next time the sconscript is run
329importer.unload()
330sys.meta_path.remove(importer)
331
332sim_objects = m5.SimObject.allClasses
333all_enums = m5.params.allEnums
334
335all_params = {}
336for name,obj in sim_objects.iteritems():
337 for param in obj._params.local.values():
338 if not hasattr(param, 'swig_decl'):
339 continue
340 pname = param.ptype_str
341 if pname not in all_params:
342 all_params[pname] = param
343
344########################################################################
345#
346# calculate extra dependencies
347#
348module_depends = ["m5", "m5.SimObject", "m5.params"]
349depends = [ File(py_modules[dep]) for dep in module_depends ]
350
351########################################################################
352#
353# Commands for the basic automatically generated python files
354#
355
356# Generate Python file containing a dict specifying the current
357# build_env flags.
358def makeDefinesPyFile(target, source, env):
359 f = file(str(target[0]), 'w')
360 print >>f, "m5_build_env = ", source[0]
361 f.close()
362
363# Generate python file containing info about the M5 source code
364def makeInfoPyFile(target, source, env):
365 f = file(str(target[0]), 'w')
366 for src in source:
367 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
368 print >>f, "%s = %s" % (src, repr(data))
369 f.close()
370
371# Generate the __init__.py file for m5.objects
372def makeObjectsInitFile(target, source, env):
373 f = file(str(target[0]), 'w')
374 print >>f, 'from params import *'
375 print >>f, 'from m5.SimObject import *'
376 for module in source:
377 print >>f, 'from %s import *' % module.get_contents()
378 f.close()
379
380# Generate a file with all of the compile options in it
381env.Command('python/m5/defines.py', Value(build_env), makeDefinesPyFile)
382PySource('m5', 'python/m5/defines.py')
383
384# Generate a file that wraps the basic top level files
385env.Command('python/m5/info.py',
386 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
387 makeInfoPyFile)
388PySource('m5', 'python/m5/info.py')
389
390# Generate an __init__.py file for the objects package
391env.Command('python/m5/objects/__init__.py',
392 [ Value(o) for o in sort_list(sim_object_modfiles) ],
393 makeObjectsInitFile)
394PySource('m5.objects', 'python/m5/objects/__init__.py')
395
396########################################################################
397#
398# Create all of the SimObject param headers and enum headers
399#
400
401def createSimObjectParam(target, source, env):
402 assert len(target) == 1 and len(source) == 1
403
404 hh_file = file(target[0].abspath, 'w')
405 name = str(source[0].get_contents())
406 obj = sim_objects[name]
407
408 print >>hh_file, obj.cxx_decl()
409
410def createSwigParam(target, source, env):
411 assert len(target) == 1 and len(source) == 1
412
413 i_file = file(target[0].abspath, 'w')
414 name = str(source[0].get_contents())
415 param = all_params[name]
416
417 for line in param.swig_decl():
418 print >>i_file, line
419
420def createEnumStrings(target, source, env):
421 assert len(target) == 1 and len(source) == 1
422
423 cc_file = file(target[0].abspath, 'w')
424 name = str(source[0].get_contents())
425 obj = all_enums[name]
426
427 print >>cc_file, obj.cxx_def()
428 cc_file.close()
429
430def createEnumParam(target, source, env):
431 assert len(target) == 1 and len(source) == 1
432
433 hh_file = file(target[0].abspath, 'w')
434 name = str(source[0].get_contents())
435 obj = all_enums[name]
436
437 print >>hh_file, obj.cxx_decl()
438
439# Generate all of the SimObject param struct header files
440params_hh_files = []
441for name,simobj in sim_objects.iteritems():
442 extra_deps = [ File(py_modules[simobj.__module__]) ]
443
444 hh_file = File('params/%s.hh' % name)
445 params_hh_files.append(hh_file)
446 env.Command(hh_file, Value(name), createSimObjectParam)
447 env.Depends(hh_file, depends + extra_deps)
448
449# Generate any parameter header files needed
450params_i_files = []
451for name,param in all_params.iteritems():
452 if isinstance(param, m5.params.VectorParamDesc):
453 ext = 'vptype'
454 else:
455 ext = 'ptype'
456
457 i_file = File('params/%s_%s.i' % (name, ext))
458 params_i_files.append(i_file)
459 env.Command(i_file, Value(name), createSwigParam)
460 env.Depends(i_file, depends)
461
462# Generate all enum header files
463for name,enum in all_enums.iteritems():
464 extra_deps = [ File(py_modules[enum.__module__]) ]
465
466 cc_file = File('enums/%s.cc' % name)
467 env.Command(cc_file, Value(name), createEnumStrings)
468 env.Depends(cc_file, depends + extra_deps)
469 Source(cc_file)
470
471 hh_file = File('enums/%s.hh' % name)
472 env.Command(hh_file, Value(name), createEnumParam)
473 env.Depends(hh_file, depends + extra_deps)
474
475# Build the big monolithic swigged params module (wraps all SimObject
476# param structs and enum structs)
477def buildParams(target, source, env):
478 names = [ s.get_contents() for s in source ]
479 objs = [ sim_objects[name] for name in names ]
480 out = file(target[0].abspath, 'w')
481
482 ordered_objs = []
483 obj_seen = set()
484 def order_obj(obj):
485 name = str(obj)
486 if name in obj_seen:
487 return
488
489 obj_seen.add(name)
490 if str(obj) != 'SimObject':
491 order_obj(obj.__bases__[0])
492
493 ordered_objs.append(obj)
494
495 for obj in objs:
496 order_obj(obj)
497
498 enums = set()
499 predecls = []
500 pd_seen = set()
501
502 def add_pds(*pds):
503 for pd in pds:
504 if pd not in pd_seen:
505 predecls.append(pd)
506 pd_seen.add(pd)
507
508 for obj in ordered_objs:
509 params = obj._params.local.values()
510 for param in params:
511 ptype = param.ptype
512 if issubclass(ptype, m5.params.Enum):
513 if ptype not in enums:
514 enums.add(ptype)
515 pds = param.swig_predecls()
516 if isinstance(pds, (list, tuple)):
517 add_pds(*pds)
518 else:
519 add_pds(pds)
520
521 print >>out, '%module params'
522
523 print >>out, '%{'
524 for obj in ordered_objs:
525 print >>out, '#include "params/%s.hh"' % obj
526 print >>out, '%}'
527
528 for pd in predecls:
529 print >>out, pd
530
531 enums = list(enums)
532 enums.sort()
533 for enum in enums:
534 print >>out, '%%include "enums/%s.hh"' % enum.__name__
535 print >>out
536
537 for obj in ordered_objs:
538 if obj.swig_objdecls:
539 for decl in obj.swig_objdecls:
540 print >>out, decl
541 continue
542
543 class_path = obj.cxx_class.split('::')
544 classname = class_path[-1]
545 namespaces = class_path[:-1]
546 namespaces.reverse()
547
548 code = ''
549
550 if namespaces:
551 code += '// avoid name conflicts\n'
552 sep_string = '_COLONS_'
553 flat_name = sep_string.join(class_path)
554 code += '%%rename(%s) %s;\n' % (flat_name, classname)
555
556 code += '// stop swig from creating/wrapping default ctor/dtor\n'
557 code += '%%nodefault %s;\n' % classname
558 code += 'class %s ' % classname
559 if obj._base:
560 code += ': public %s' % obj._base.cxx_class
561 code += ' {};\n'
562
563 for ns in namespaces:
564 new_code = 'namespace %s {\n' % ns
565 new_code += code
566 new_code += '}\n'
567 code = new_code
568
569 print >>out, code
570
571 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj
572 for obj in ordered_objs:
573 print >>out, '%%include "params/%s.hh"' % obj
574
575params_file = File('params/params.i')
576names = sort_list(sim_objects.keys())
577env.Command(params_file, [ Value(v) for v in names ], buildParams)
578env.Depends(params_file, params_hh_files + params_i_files + depends)
579SwigSource('m5.objects', params_file)
580
581# Build all swig modules
582swig_modules = []
583cc_swig_sources = []
584for source,package in swig_sources:
585 filename = str(source)
586 assert filename.endswith('.i')
587
588 base = '.'.join(filename.split('.')[:-1])
589 module = basename(base)
590 cc_file = base + '_wrap.cc'
591 py_file = base + '.py'
592
593 env.Command([cc_file, py_file], source,
594 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
595 '-o ${TARGETS[0]} $SOURCES')
596 env.Depends(py_file, source)
597 env.Depends(cc_file, source)
598
599 swig_modules.append(Value(module))
600 cc_swig_sources.append(File(cc_file))
601 PySource(package, py_file)
602
603# Generate the main swig init file
604def makeSwigInit(target, source, env):
605 f = file(str(target[0]), 'w')
606 print >>f, 'extern "C" {'
607 for module in source:
608 print >>f, ' void init_%s();' % module.get_contents()
609 print >>f, '}'
610 print >>f, 'void initSwig() {'
611 for module in source:
612 print >>f, ' init_%s();' % module.get_contents()
613 print >>f, '}'
614 f.close()
615
616env.Command('python/swig/init.cc', swig_modules, makeSwigInit)
617Source('python/swig/init.cc')
618
619# Generate traceflags.py
620def traceFlagsPy(target, source, env):
621 assert(len(target) == 1)
622
623 f = file(str(target[0]), 'w')
624
625 allFlags = []
626 for s in source:
627 val = eval(s.get_contents())
628 allFlags.append(val)
629
630 print >>f, 'baseFlags = ['
631 for flag, compound, desc in allFlags:
632 if not compound:
633 print >>f, " '%s'," % flag
634 print >>f, " ]"
635 print >>f
636
637 print >>f, 'compoundFlags = ['
638 print >>f, " 'All',"
639 for flag, compound, desc in allFlags:
640 if compound:
641 print >>f, " '%s'," % flag
642 print >>f, " ]"
643 print >>f
644
645 print >>f, "allFlags = frozenset(baseFlags + compoundFlags)"
646 print >>f
647
648 print >>f, 'compoundFlagMap = {'
649 all = tuple([flag for flag,compound,desc in allFlags if not compound])
650 print >>f, " 'All' : %s," % (all, )
651 for flag, compound, desc in allFlags:
652 if compound:
653 print >>f, " '%s' : %s," % (flag, compound)
654 print >>f, " }"
655 print >>f
656
657 print >>f, 'flagDescriptions = {'
658 print >>f, " 'All' : 'All flags',"
659 for flag, compound, desc in allFlags:
660 print >>f, " '%s' : '%s'," % (flag, desc)
661 print >>f, " }"
662
663 f.close()
664
665def traceFlagsCC(target, source, env):
666 assert(len(target) == 1)
667
668 f = file(str(target[0]), 'w')
669
670 allFlags = []
671 for s in source:
672 val = eval(s.get_contents())
673 allFlags.append(val)
674
675 # file header
676 print >>f, '''
677/*
678 * DO NOT EDIT THIS FILE! Automatically generated
679 */
680
681#include "base/traceflags.hh"
682
683using namespace Trace;
684
685const char *Trace::flagStrings[] =
686{'''
687
688 # The string array is used by SimpleEnumParam to map the strings
689 # provided by the user to enum values.
690 for flag, compound, desc in allFlags:
691 if not compound:
692 print >>f, ' "%s",' % flag
693
694 print >>f, ' "All",'
695 for flag, compound, desc in allFlags:
696 if compound:
697 print >>f, ' "%s",' % flag
698
699 print >>f, '};'
700 print >>f
701 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
702 print >>f
703
704 #
705 # Now define the individual compound flag arrays. There is an array
706 # for each compound flag listing the component base flags.
707 #
708 all = tuple([flag for flag,compound,desc in allFlags if not compound])
709 print >>f, 'static const Flags AllMap[] = {'
710 for flag, compound, desc in allFlags:
711 if not compound:
712 print >>f, " %s," % flag
713 print >>f, '};'
714 print >>f
715
716 for flag, compound, desc in allFlags:
717 if not compound:
718 continue
719 print >>f, 'static const Flags %sMap[] = {' % flag
720 for flag in compound:
721 print >>f, " %s," % flag
722 print >>f, " (Flags)-1"
723 print >>f, '};'
724 print >>f
725
726 #
727 # Finally the compoundFlags[] array maps the compound flags
728 # to their individual arrays/
729 #
730 print >>f, 'const Flags *Trace::compoundFlags[] ='
731 print >>f, '{'
732 print >>f, ' AllMap,'
733 for flag, compound, desc in allFlags:
734 if compound:
735 print >>f, ' %sMap,' % flag
736 # file trailer
737 print >>f, '};'
738
739 f.close()
740
741def traceFlagsHH(target, source, env):
742 assert(len(target) == 1)
743
744 f = file(str(target[0]), 'w')
745
746 allFlags = []
747 for s in source:
748 val = eval(s.get_contents())
749 allFlags.append(val)
750
751 # file header boilerplate
752 print >>f, '''
753/*
754 * DO NOT EDIT THIS FILE!
755 *
756 * Automatically generated from traceflags.py
757 */
758
759#ifndef __BASE_TRACE_FLAGS_HH__
760#define __BASE_TRACE_FLAGS_HH__
761
762namespace Trace {
763
764enum Flags {'''
765
766 # Generate the enum. Base flags come first, then compound flags.
767 idx = 0
768 for flag, compound, desc in allFlags:
769 if not compound:
770 print >>f, ' %s = %d,' % (flag, idx)
771 idx += 1
772
773 numBaseFlags = idx
774 print >>f, ' NumFlags = %d,' % idx
775
776 # put a comment in here to separate base from compound flags
777 print >>f, '''
778// The remaining enum values are *not* valid indices for Trace::flags.
779// They are "compound" flags, which correspond to sets of base
780// flags, and are used by changeFlag.'''
781
782 print >>f, ' All = %d,' % idx
783 idx += 1
784 for flag, compound, desc in allFlags:
785 if compound:
786 print >>f, ' %s = %d,' % (flag, idx)
787 idx += 1
788
789 numCompoundFlags = idx - numBaseFlags
790 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags
791
792 # trailer boilerplate
793 print >>f, '''\
794}; // enum Flags
795
796// Array of strings for SimpleEnumParam
797extern const char *flagStrings[];
798extern const int numFlagStrings;
799
800// Array of arraay pointers: for each compound flag, gives the list of
801// base flags to set. Inidividual flag arrays are terminated by -1.
802extern const Flags *compoundFlags[];
803
804/* namespace Trace */ }
805
806#endif // __BASE_TRACE_FLAGS_HH__
807'''
808
809 f.close()
810
811flags = [ Value(f) for f in trace_flags ]
812env.Command('base/traceflags.py', flags, traceFlagsPy)
813PySource('m5', 'base/traceflags.py')
814
815env.Command('base/traceflags.hh', flags, traceFlagsHH)
816env.Command('base/traceflags.cc', flags, traceFlagsCC)
817Source('base/traceflags.cc')
818
819# Generate program_info.cc
820def programInfo(target, source, env):
821 def gen_file(target, rev, node, date):
822 pi_stats = file(target, 'w')
823 print >>pi_stats, 'const char *hgRev = "%s:%s";' % (rev, node)
824 print >>pi_stats, 'const char *hgDate = "%s";' % date
825 pi_stats.close()
826
827 target = str(target[0])
828 scons_dir = str(source[0].get_contents())
829 try:
830 import mercurial.demandimport, mercurial.hg, mercurial.ui
831 import mercurial.util, mercurial.node
832 if not exists(scons_dir) or not isdir(scons_dir) or \
833 not exists(joinpath(scons_dir, ".hg")):
834 raise ValueError
835 repo = mercurial.hg.repository(mercurial.ui.ui(), scons_dir)
836 rev = mercurial.node.nullrev + repo.changelog.count()
837 changenode = repo.changelog.node(rev)
838 changes = repo.changelog.read(changenode)
839 date = mercurial.util.datestr(changes[2])
840
841 gen_file(target, rev, mercurial.node.hex(changenode), date)
842
843 mercurial.demandimport.disable()
844 except ImportError:
845 gen_file(target, "Unknown", "Unknown", "Unknown")
846
847 except:
848 print "in except"
849 gen_file(target, "Unknown", "Unknown", "Unknown")
850 mercurial.demandimport.disable()
851
852env.Command('base/program_info.cc',
853 Value(str(SCons.Node.FS.default_fs.SConstruct_dir)),
854 programInfo)
855
856# embed python files. All .py files that have been indicated by a
857# PySource() call in a SConscript need to be embedded into the M5
858# library. To do that, we compile the file to byte code, marshal the
859# byte code, compress it, and then generate an assembly file that
860# inserts the result into the data section with symbols indicating the
861# beginning, and end (and with the size at the end)
862py_sources_tnodes = {}
863for pysource in py_sources:
864 py_sources_tnodes[pysource.tnode] = pysource
865
866def objectifyPyFile(target, source, env):
867 '''Action function to compile a .py into a code object, marshal
868 it, compress it, and stick it into an asm file so the code appears
869 as just bytes with a label in the data section'''
870
871 src = file(str(source[0]), 'r').read()
872 dst = file(str(target[0]), 'w')
873
874 pysource = py_sources_tnodes[source[0]]
875 compiled = compile(src, pysource.debugname, 'exec')
876 marshalled = marshal.dumps(compiled)
877 compressed = zlib.compress(marshalled)
878 data = compressed
879
880 # Some C/C++ compilers prepend an underscore to global symbol
881 # names, so if they're going to do that, we need to prepend that
882 # leading underscore to globals in the assembly file.
883 if env['LEADING_UNDERSCORE']:
884 sym = '_' + pysource.symname
885 else:
886 sym = pysource.symname
887
888 step = 16
889 print >>dst, ".data"
890 print >>dst, ".globl %s_beg" % sym
891 print >>dst, ".globl %s_end" % sym
892 print >>dst, "%s_beg:" % sym
893 for i in xrange(0, len(data), step):
894 x = array.array('B', data[i:i+step])
895 print >>dst, ".byte", ','.join([str(d) for d in x])
896 print >>dst, "%s_end:" % sym
897 print >>dst, ".long %d" % len(marshalled)
898
899for source in py_sources:
900 env.Command(source.assembly, source.tnode, objectifyPyFile)
901 Source(source.assembly)
902
903# Generate init_python.cc which creates a bunch of EmbeddedPyModule
904# structs that describe the embedded python code. One such struct
905# contains information about the importer that python uses to get at
906# the embedded files, and then there's a list of all of the rest that
907# the importer uses to load the rest on demand.
908py_sources_symbols = {}
909for pysource in py_sources:
910 py_sources_symbols[pysource.symname] = pysource
911def pythonInit(target, source, env):
912 dst = file(str(target[0]), 'w')
913
914 def dump_mod(sym, endchar=','):
915 pysource = py_sources_symbols[sym]
916 print >>dst, ' { "%s",' % pysource.arcname
917 print >>dst, ' "%s",' % pysource.modpath
918 print >>dst, ' %s_beg, %s_end,' % (sym, sym)
919 print >>dst, ' %s_end - %s_beg,' % (sym, sym)
920 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar)
921
922 print >>dst, '#include "sim/init.hh"'
923
924 for sym in source:
925 sym = sym.get_contents()
926 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym)
927
928 print >>dst, "const EmbeddedPyModule embeddedPyImporter = "
929 dump_mod("PyEMB_importer", endchar=';');
930 print >>dst
931
932 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {"
933 for i,sym in enumerate(source):
934 sym = sym.get_contents()
935 if sym == "PyEMB_importer":
936 # Skip the importer since we've already exported it
937 continue
938 dump_mod(sym)
939 print >>dst, " { 0, 0, 0, 0, 0, 0 }"
940 print >>dst, "};"
941
942symbols = [Value(s.symname) for s in py_sources]
943env.Command('sim/init_python.cc', symbols, pythonInit)
944Source('sim/init_python.cc')
945
946########################################################################
947#
948# Define binaries. Each different build type (debug, opt, etc.) gets
949# a slightly different build environment.
950#
951
952# List of constructed environments to pass back to SConstruct
953envList = []
954
955# This function adds the specified sources to the given build
956# environment, and returns a list of all the corresponding SCons
957# Object nodes (including an extra one for date.cc). We explicitly
958# add the Object nodes so we can set up special dependencies for
959# date.cc.
960def make_objs(sources, env, static):
961 if static:
962 XObject = env.StaticObject
963 else:
964 XObject = env.SharedObject
965
966 objs = [ XObject(s) for s in sources ]
967
968 # make date.cc depend on all other objects so it always gets
969 # recompiled whenever anything else does
970 date_obj = XObject('base/date.cc')
971
972 # Make the generation of program_info.cc dependend on all
973 # the other cc files and the compiling of program_info.cc
974 # dependent on all the objects but program_info.o
975 pinfo_obj = XObject('base/program_info.cc')
976 env.Depends('base/program_info.cc', sources)
977 env.Depends(date_obj, objs)
978 env.Depends(pinfo_obj, objs)
979 objs.extend([date_obj, pinfo_obj])
980 return objs
981
982# Function to create a new build environment as clone of current
983# environment 'env' with modified object suffix and optional stripped
984# binary. Additional keyword arguments are appended to corresponding
985# build environment vars.
986def makeEnv(label, objsfx, strip = False, **kwargs):
987 # SCons doesn't know to append a library suffix when there is a '.' in the
988 # name. Use '_' instead.
989 libname = 'm5_' + label
990 exename = 'm5.' + label
991
992 new_env = env.Copy(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
993 new_env.Label = label
994 new_env.Append(**kwargs)
995
996 swig_env = new_env.Copy()
997 if env['GCC']:
998 swig_env.Append(CCFLAGS='-Wno-uninitialized')
999 swig_env.Append(CCFLAGS='-Wno-sign-compare')
1000 swig_env.Append(CCFLAGS='-Wno-parentheses')
1001
1002 static_objs = make_objs(cc_lib_sources, new_env, static=True)
1003 shared_objs = make_objs(cc_lib_sources, new_env, static=False)
1004 static_objs += [ swig_env.StaticObject(s) for s in cc_swig_sources ]
1005 shared_objs += [ swig_env.SharedObject(s) for s in cc_swig_sources ]
1006
1007 # First make a library of everything but main() so other programs can
1008 # link against m5.
1009 static_lib = new_env.StaticLibrary(libname, static_objs + static_objs)
1010 shared_lib = new_env.SharedLibrary(libname, shared_objs + shared_objs)
1011
1012 for target, sources in unit_tests:
1013 objs = [ new_env.StaticObject(s) for s in sources ]
1014 new_env.Program("unittest/%s.%s" % (target, label), objs + static_lib)
1015
1016 # Now link a stub with main() and the static library.
1017 objects = [new_env.Object(s) for s in cc_bin_sources] + static_lib
1018 if strip:
1019 unstripped_exe = exename + '.unstripped'
1020 new_env.Program(unstripped_exe, objects)
1021 if sys.platform == 'sunos5':
1022 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1023 else:
1024 cmd = 'strip $SOURCE -o $TARGET'
1025 targets = new_env.Command(exename, unstripped_exe, cmd)
1026 else:
1027 targets = new_env.Program(exename, objects)
1028
1029 new_env.M5Binary = targets[0]
1030 envList.append(new_env)
1031
1032# Debug binary
1033ccflags = {}
1034if env['GCC']:
1035 if sys.platform == 'sunos5':
1036 ccflags['debug'] = '-gstabs+'
1037 else:
1038 ccflags['debug'] = '-ggdb3'
1039 ccflags['opt'] = '-g -O3'
1040 ccflags['fast'] = '-O3'
1041 ccflags['prof'] = '-O3 -g -pg'
1042elif env['SUNCC']:
1043 ccflags['debug'] = '-g0'
1044 ccflags['opt'] = '-g -O'
1045 ccflags['fast'] = '-fast'
1046 ccflags['prof'] = '-fast -g -pg'
1047elif env['ICC']:
1048 ccflags['debug'] = '-g -O0'
1049 ccflags['opt'] = '-g -O'
1050 ccflags['fast'] = '-fast'
1051 ccflags['prof'] = '-fast -g -pg'
1052else:
1053 print 'Unknown compiler, please fix compiler options'
1054 Exit(1)
1055
1056makeEnv('debug', '.do',
1057 CCFLAGS = Split(ccflags['debug']),
1058 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1059
1060# Optimized binary
1061makeEnv('opt', '.o',
1062 CCFLAGS = Split(ccflags['opt']),
1063 CPPDEFINES = ['TRACING_ON=1'])
1064
1065# "Fast" binary
1066makeEnv('fast', '.fo', strip = True,
1067 CCFLAGS = Split(ccflags['fast']),
1068 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1069
1070# Profiled binary
1071makeEnv('prof', '.po',
1072 CCFLAGS = Split(ccflags['prof']),
1073 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1074 LINKFLAGS = '-pg')
1075
1076Return('envList')