SConscript (5863:f73e06bc8765) SConscript (6108:66014cd0dc61)
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, 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
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, 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.ExportVariables])
51build_env = dict([(opt, env[opt]) for opt in export_vars])
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#
178trace_flags = {}
179def TraceFlag(name, desc=None):
180 if name in trace_flags:
181 raise AttributeError, "Flag %s already specified" % name
182 trace_flags[name] = (name, (), desc)
183
184def CompoundFlag(name, flags, desc=None):
185 if name in trace_flags:
186 raise AttributeError, "Flag %s already specified" % name
187
188 compound = tuple(flags)
189 for flag in compound:
190 if flag not in trace_flags:
191 raise AttributeError, "Trace flag %s not found" % flag
192 if trace_flags[flag][1]:
193 raise AttributeError, \
194 "Compound flag can't point to another compound flag"
195
196 trace_flags[name] = (name, compound, desc)
197
198Export('TraceFlag')
199Export('CompoundFlag')
200
201########################################################################
202#
203# Set some compiler variables
204#
205
206# Include file paths are rooted in this directory. SCons will
207# automatically expand '.' to refer to both the source directory and
208# the corresponding build directory to pick up generated include
209# files.
210env.Append(CPPPATH=Dir('.'))
211
212for extra_dir in extras_dir_list:
213 env.Append(CPPPATH=Dir(extra_dir))
214
215# Add a flag defining what THE_ISA should be for all compilation
216env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
217
218# Workaround for bug in SCons version > 0.97d20071212
219# Scons bug id: 2006 M5 Bug id: 308
220for root, dirs, files in os.walk(base_dir, topdown=True):
221 Dir(root[len(base_dir) + 1:])
222
223########################################################################
224#
225# Walk the tree and execute all SConscripts in subdirectories
226#
227
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
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):
241 if 'SConscript' in files:
242 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
243 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
244
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#
178trace_flags = {}
179def TraceFlag(name, desc=None):
180 if name in trace_flags:
181 raise AttributeError, "Flag %s already specified" % name
182 trace_flags[name] = (name, (), desc)
183
184def CompoundFlag(name, flags, desc=None):
185 if name in trace_flags:
186 raise AttributeError, "Flag %s already specified" % name
187
188 compound = tuple(flags)
189 for flag in compound:
190 if flag not in trace_flags:
191 raise AttributeError, "Trace flag %s not found" % flag
192 if trace_flags[flag][1]:
193 raise AttributeError, \
194 "Compound flag can't point to another compound flag"
195
196 trace_flags[name] = (name, compound, desc)
197
198Export('TraceFlag')
199Export('CompoundFlag')
200
201########################################################################
202#
203# Set some compiler variables
204#
205
206# Include file paths are rooted in this directory. SCons will
207# automatically expand '.' to refer to both the source directory and
208# the corresponding build directory to pick up generated include
209# files.
210env.Append(CPPPATH=Dir('.'))
211
212for extra_dir in extras_dir_list:
213 env.Append(CPPPATH=Dir(extra_dir))
214
215# Add a flag defining what THE_ISA should be for all compilation
216env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
217
218# Workaround for bug in SCons version > 0.97d20071212
219# Scons bug id: 2006 M5 Bug id: 308
220for root, dirs, files in os.walk(base_dir, topdown=True):
221 Dir(root[len(base_dir) + 1:])
222
223########################################################################
224#
225# Walk the tree and execute all SConscripts in subdirectories
226#
227
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
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):
241 if 'SConscript' in files:
242 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
243 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
244
245for opt in env.ExportVariables:
245for opt in export_vars:
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 == 'defines':
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 == 'defines':
295 mod.__dict__['buildEnv'] = 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 build_env, hg_info = [ x.get_contents() for x in source ]
361 print >>f, "buildEnv = %s" % build_env
362 print >>f, "hgRev = '%s'" % hg_info
363 f.close()
364
365defines_info = [ Value(build_env), Value(env['HG_INFO']) ]
366# Generate a file with all of the compile options in it
367env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile)
368PySource('m5', 'python/m5/defines.py')
369
370# Generate python file containing info about the M5 source code
371def makeInfoPyFile(target, source, env):
372 f = file(str(target[0]), 'w')
373 for src in source:
374 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
375 print >>f, "%s = %s" % (src, repr(data))
376 f.close()
377
378# Generate a file that wraps the basic top level files
379env.Command('python/m5/info.py',
380 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
381 makeInfoPyFile)
382PySource('m5', 'python/m5/info.py')
383
384# Generate the __init__.py file for m5.objects
385def makeObjectsInitFile(target, source, env):
386 f = file(str(target[0]), 'w')
387 print >>f, 'from params import *'
388 print >>f, 'from m5.SimObject import *'
389 for module in source:
390 print >>f, 'from %s import *' % module.get_contents()
391 f.close()
392
393# Generate an __init__.py file for the objects package
394env.Command('python/m5/objects/__init__.py',
395 [ Value(o) for o in sort_list(sim_object_modfiles) ],
396 makeObjectsInitFile)
397PySource('m5.objects', 'python/m5/objects/__init__.py')
398
399########################################################################
400#
401# Create all of the SimObject param headers and enum headers
402#
403
404def createSimObjectParam(target, source, env):
405 assert len(target) == 1 and len(source) == 1
406
407 hh_file = file(target[0].abspath, 'w')
408 name = str(source[0].get_contents())
409 obj = sim_objects[name]
410
411 print >>hh_file, obj.cxx_decl()
412
413def createSwigParam(target, source, env):
414 assert len(target) == 1 and len(source) == 1
415
416 i_file = file(target[0].abspath, 'w')
417 name = str(source[0].get_contents())
418 param = all_params[name]
419
420 for line in param.swig_decl():
421 print >>i_file, line
422
423def createEnumStrings(target, source, env):
424 assert len(target) == 1 and len(source) == 1
425
426 cc_file = file(target[0].abspath, 'w')
427 name = str(source[0].get_contents())
428 obj = all_enums[name]
429
430 print >>cc_file, obj.cxx_def()
431 cc_file.close()
432
433def createEnumParam(target, source, env):
434 assert len(target) == 1 and len(source) == 1
435
436 hh_file = file(target[0].abspath, 'w')
437 name = str(source[0].get_contents())
438 obj = all_enums[name]
439
440 print >>hh_file, obj.cxx_decl()
441
442# Generate all of the SimObject param struct header files
443params_hh_files = []
444for name,simobj in sim_objects.iteritems():
445 extra_deps = [ File(py_modules[simobj.__module__]) ]
446
447 hh_file = File('params/%s.hh' % name)
448 params_hh_files.append(hh_file)
449 env.Command(hh_file, Value(name), createSimObjectParam)
450 env.Depends(hh_file, depends + extra_deps)
451
452# Generate any parameter header files needed
453params_i_files = []
454for name,param in all_params.iteritems():
455 if isinstance(param, m5.params.VectorParamDesc):
456 ext = 'vptype'
457 else:
458 ext = 'ptype'
459
460 i_file = File('params/%s_%s.i' % (name, ext))
461 params_i_files.append(i_file)
462 env.Command(i_file, Value(name), createSwigParam)
463 env.Depends(i_file, depends)
464
465# Generate all enum header files
466for name,enum in all_enums.iteritems():
467 extra_deps = [ File(py_modules[enum.__module__]) ]
468
469 cc_file = File('enums/%s.cc' % name)
470 env.Command(cc_file, Value(name), createEnumStrings)
471 env.Depends(cc_file, depends + extra_deps)
472 Source(cc_file)
473
474 hh_file = File('enums/%s.hh' % name)
475 env.Command(hh_file, Value(name), createEnumParam)
476 env.Depends(hh_file, depends + extra_deps)
477
478# Build the big monolithic swigged params module (wraps all SimObject
479# param structs and enum structs)
480def buildParams(target, source, env):
481 names = [ s.get_contents() for s in source ]
482 objs = [ sim_objects[name] for name in names ]
483 out = file(target[0].abspath, 'w')
484
485 ordered_objs = []
486 obj_seen = set()
487 def order_obj(obj):
488 name = str(obj)
489 if name in obj_seen:
490 return
491
492 obj_seen.add(name)
493 if str(obj) != 'SimObject':
494 order_obj(obj.__bases__[0])
495
496 ordered_objs.append(obj)
497
498 for obj in objs:
499 order_obj(obj)
500
501 enums = set()
502 predecls = []
503 pd_seen = set()
504
505 def add_pds(*pds):
506 for pd in pds:
507 if pd not in pd_seen:
508 predecls.append(pd)
509 pd_seen.add(pd)
510
511 for obj in ordered_objs:
512 params = obj._params.local.values()
513 for param in params:
514 ptype = param.ptype
515 if issubclass(ptype, m5.params.Enum):
516 if ptype not in enums:
517 enums.add(ptype)
518 pds = param.swig_predecls()
519 if isinstance(pds, (list, tuple)):
520 add_pds(*pds)
521 else:
522 add_pds(pds)
523
524 print >>out, '%module params'
525
526 print >>out, '%{'
527 for obj in ordered_objs:
528 print >>out, '#include "params/%s.hh"' % obj
529 print >>out, '%}'
530
531 for pd in predecls:
532 print >>out, pd
533
534 enums = list(enums)
535 enums.sort()
536 for enum in enums:
537 print >>out, '%%include "enums/%s.hh"' % enum.__name__
538 print >>out
539
540 for obj in ordered_objs:
541 if obj.swig_objdecls:
542 for decl in obj.swig_objdecls:
543 print >>out, decl
544 continue
545
546 class_path = obj.cxx_class.split('::')
547 classname = class_path[-1]
548 namespaces = class_path[:-1]
549 namespaces.reverse()
550
551 code = ''
552
553 if namespaces:
554 code += '// avoid name conflicts\n'
555 sep_string = '_COLONS_'
556 flat_name = sep_string.join(class_path)
557 code += '%%rename(%s) %s;\n' % (flat_name, classname)
558
559 code += '// stop swig from creating/wrapping default ctor/dtor\n'
560 code += '%%nodefault %s;\n' % classname
561 code += 'class %s ' % classname
562 if obj._base:
563 code += ': public %s' % obj._base.cxx_class
564 code += ' {};\n'
565
566 for ns in namespaces:
567 new_code = 'namespace %s {\n' % ns
568 new_code += code
569 new_code += '}\n'
570 code = new_code
571
572 print >>out, code
573
574 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj
575 for obj in ordered_objs:
576 print >>out, '%%include "params/%s.hh"' % obj
577
578params_file = File('params/params.i')
579names = sort_list(sim_objects.keys())
580env.Command(params_file, [ Value(v) for v in names ], buildParams)
581env.Depends(params_file, params_hh_files + params_i_files + depends)
582SwigSource('m5.objects', params_file)
583
584# Build all swig modules
585swig_modules = []
586cc_swig_sources = []
587for source,package in swig_sources:
588 filename = str(source)
589 assert filename.endswith('.i')
590
591 base = '.'.join(filename.split('.')[:-1])
592 module = basename(base)
593 cc_file = base + '_wrap.cc'
594 py_file = base + '.py'
595
596 env.Command([cc_file, py_file], source,
597 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
598 '-o ${TARGETS[0]} $SOURCES')
599 env.Depends(py_file, source)
600 env.Depends(cc_file, source)
601
602 swig_modules.append(Value(module))
603 cc_swig_sources.append(File(cc_file))
604 PySource(package, py_file)
605
606# Generate the main swig init file
607def makeSwigInit(target, source, env):
608 f = file(str(target[0]), 'w')
609 print >>f, 'extern "C" {'
610 for module in source:
611 print >>f, ' void init_%s();' % module.get_contents()
612 print >>f, '}'
613 print >>f, 'void initSwig() {'
614 for module in source:
615 print >>f, ' init_%s();' % module.get_contents()
616 print >>f, '}'
617 f.close()
618
619env.Command('python/swig/init.cc', swig_modules, makeSwigInit)
620Source('python/swig/init.cc')
621
622# Generate traceflags.py
623def traceFlagsPy(target, source, env):
624 assert(len(target) == 1)
625
626 f = file(str(target[0]), 'w')
627
628 allFlags = []
629 for s in source:
630 val = eval(s.get_contents())
631 allFlags.append(val)
632
633 allFlags.sort()
634
635 print >>f, 'basic = ['
636 for flag, compound, desc in allFlags:
637 if not compound:
638 print >>f, " '%s'," % flag
639 print >>f, " ]"
640 print >>f
641
642 print >>f, 'compound = ['
643 print >>f, " 'All',"
644 for flag, compound, desc in allFlags:
645 if compound:
646 print >>f, " '%s'," % flag
647 print >>f, " ]"
648 print >>f
649
650 print >>f, "all = frozenset(basic + compound)"
651 print >>f
652
653 print >>f, 'compoundMap = {'
654 all = tuple([flag for flag,compound,desc in allFlags if not compound])
655 print >>f, " 'All' : %s," % (all, )
656 for flag, compound, desc in allFlags:
657 if compound:
658 print >>f, " '%s' : %s," % (flag, compound)
659 print >>f, " }"
660 print >>f
661
662 print >>f, 'descriptions = {'
663 print >>f, " 'All' : 'All flags',"
664 for flag, compound, desc in allFlags:
665 print >>f, " '%s' : '%s'," % (flag, desc)
666 print >>f, " }"
667
668 f.close()
669
670def traceFlagsCC(target, source, env):
671 assert(len(target) == 1)
672
673 f = file(str(target[0]), 'w')
674
675 allFlags = []
676 for s in source:
677 val = eval(s.get_contents())
678 allFlags.append(val)
679
680 # file header
681 print >>f, '''
682/*
683 * DO NOT EDIT THIS FILE! Automatically generated
684 */
685
686#include "base/traceflags.hh"
687
688using namespace Trace;
689
690const char *Trace::flagStrings[] =
691{'''
692
693 # The string array is used by SimpleEnumParam to map the strings
694 # provided by the user to enum values.
695 for flag, compound, desc in allFlags:
696 if not compound:
697 print >>f, ' "%s",' % flag
698
699 print >>f, ' "All",'
700 for flag, compound, desc in allFlags:
701 if compound:
702 print >>f, ' "%s",' % flag
703
704 print >>f, '};'
705 print >>f
706 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
707 print >>f
708
709 #
710 # Now define the individual compound flag arrays. There is an array
711 # for each compound flag listing the component base flags.
712 #
713 all = tuple([flag for flag,compound,desc in allFlags if not compound])
714 print >>f, 'static const Flags AllMap[] = {'
715 for flag, compound, desc in allFlags:
716 if not compound:
717 print >>f, " %s," % flag
718 print >>f, '};'
719 print >>f
720
721 for flag, compound, desc in allFlags:
722 if not compound:
723 continue
724 print >>f, 'static const Flags %sMap[] = {' % flag
725 for flag in compound:
726 print >>f, " %s," % flag
727 print >>f, " (Flags)-1"
728 print >>f, '};'
729 print >>f
730
731 #
732 # Finally the compoundFlags[] array maps the compound flags
733 # to their individual arrays/
734 #
735 print >>f, 'const Flags *Trace::compoundFlags[] ='
736 print >>f, '{'
737 print >>f, ' AllMap,'
738 for flag, compound, desc in allFlags:
739 if compound:
740 print >>f, ' %sMap,' % flag
741 # file trailer
742 print >>f, '};'
743
744 f.close()
745
746def traceFlagsHH(target, source, env):
747 assert(len(target) == 1)
748
749 f = file(str(target[0]), 'w')
750
751 allFlags = []
752 for s in source:
753 val = eval(s.get_contents())
754 allFlags.append(val)
755
756 # file header boilerplate
757 print >>f, '''
758/*
759 * DO NOT EDIT THIS FILE!
760 *
761 * Automatically generated from traceflags.py
762 */
763
764#ifndef __BASE_TRACE_FLAGS_HH__
765#define __BASE_TRACE_FLAGS_HH__
766
767namespace Trace {
768
769enum Flags {'''
770
771 # Generate the enum. Base flags come first, then compound flags.
772 idx = 0
773 for flag, compound, desc in allFlags:
774 if not compound:
775 print >>f, ' %s = %d,' % (flag, idx)
776 idx += 1
777
778 numBaseFlags = idx
779 print >>f, ' NumFlags = %d,' % idx
780
781 # put a comment in here to separate base from compound flags
782 print >>f, '''
783// The remaining enum values are *not* valid indices for Trace::flags.
784// They are "compound" flags, which correspond to sets of base
785// flags, and are used by changeFlag.'''
786
787 print >>f, ' All = %d,' % idx
788 idx += 1
789 for flag, compound, desc in allFlags:
790 if compound:
791 print >>f, ' %s = %d,' % (flag, idx)
792 idx += 1
793
794 numCompoundFlags = idx - numBaseFlags
795 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags
796
797 # trailer boilerplate
798 print >>f, '''\
799}; // enum Flags
800
801// Array of strings for SimpleEnumParam
802extern const char *flagStrings[];
803extern const int numFlagStrings;
804
805// Array of arraay pointers: for each compound flag, gives the list of
806// base flags to set. Inidividual flag arrays are terminated by -1.
807extern const Flags *compoundFlags[];
808
809/* namespace Trace */ }
810
811#endif // __BASE_TRACE_FLAGS_HH__
812'''
813
814 f.close()
815
816flags = [ Value(f) for f in trace_flags.values() ]
817env.Command('base/traceflags.py', flags, traceFlagsPy)
818PySource('m5', 'base/traceflags.py')
819
820env.Command('base/traceflags.hh', flags, traceFlagsHH)
821env.Command('base/traceflags.cc', flags, traceFlagsCC)
822Source('base/traceflags.cc')
823
824# embed python files. All .py files that have been indicated by a
825# PySource() call in a SConscript need to be embedded into the M5
826# library. To do that, we compile the file to byte code, marshal the
827# byte code, compress it, and then generate an assembly file that
828# inserts the result into the data section with symbols indicating the
829# beginning, and end (and with the size at the end)
830py_sources_tnodes = {}
831for pysource in py_sources:
832 py_sources_tnodes[pysource.tnode] = pysource
833
834def objectifyPyFile(target, source, env):
835 '''Action function to compile a .py into a code object, marshal
836 it, compress it, and stick it into an asm file so the code appears
837 as just bytes with a label in the data section'''
838
839 src = file(str(source[0]), 'r').read()
840 dst = file(str(target[0]), 'w')
841
842 pysource = py_sources_tnodes[source[0]]
843 compiled = compile(src, pysource.debugname, 'exec')
844 marshalled = marshal.dumps(compiled)
845 compressed = zlib.compress(marshalled)
846 data = compressed
847
848 # Some C/C++ compilers prepend an underscore to global symbol
849 # names, so if they're going to do that, we need to prepend that
850 # leading underscore to globals in the assembly file.
851 if env['LEADING_UNDERSCORE']:
852 sym = '_' + pysource.symname
853 else:
854 sym = pysource.symname
855
856 step = 16
857 print >>dst, ".data"
858 print >>dst, ".globl %s_beg" % sym
859 print >>dst, ".globl %s_end" % sym
860 print >>dst, "%s_beg:" % sym
861 for i in xrange(0, len(data), step):
862 x = array.array('B', data[i:i+step])
863 print >>dst, ".byte", ','.join([str(d) for d in x])
864 print >>dst, "%s_end:" % sym
865 print >>dst, ".long %d" % len(marshalled)
866
867for source in py_sources:
868 env.Command(source.assembly, source.tnode, objectifyPyFile)
869 Source(source.assembly)
870
871# Generate init_python.cc which creates a bunch of EmbeddedPyModule
872# structs that describe the embedded python code. One such struct
873# contains information about the importer that python uses to get at
874# the embedded files, and then there's a list of all of the rest that
875# the importer uses to load the rest on demand.
876py_sources_symbols = {}
877for pysource in py_sources:
878 py_sources_symbols[pysource.symname] = pysource
879def pythonInit(target, source, env):
880 dst = file(str(target[0]), 'w')
881
882 def dump_mod(sym, endchar=','):
883 pysource = py_sources_symbols[sym]
884 print >>dst, ' { "%s",' % pysource.arcname
885 print >>dst, ' "%s",' % pysource.modpath
886 print >>dst, ' %s_beg, %s_end,' % (sym, sym)
887 print >>dst, ' %s_end - %s_beg,' % (sym, sym)
888 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar)
889
890 print >>dst, '#include "sim/init.hh"'
891
892 for sym in source:
893 sym = sym.get_contents()
894 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym)
895
896 print >>dst, "const EmbeddedPyModule embeddedPyImporter = "
897 dump_mod("PyEMB_importer", endchar=';');
898 print >>dst
899
900 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {"
901 for i,sym in enumerate(source):
902 sym = sym.get_contents()
903 if sym == "PyEMB_importer":
904 # Skip the importer since we've already exported it
905 continue
906 dump_mod(sym)
907 print >>dst, " { 0, 0, 0, 0, 0, 0 }"
908 print >>dst, "};"
909
910symbols = [Value(s.symname) for s in py_sources]
911env.Command('sim/init_python.cc', symbols, pythonInit)
912Source('sim/init_python.cc')
913
914########################################################################
915#
916# Define binaries. Each different build type (debug, opt, etc.) gets
917# a slightly different build environment.
918#
919
920# List of constructed environments to pass back to SConstruct
921envList = []
922
923# This function adds the specified sources to the given build
924# environment, and returns a list of all the corresponding SCons
925# Object nodes (including an extra one for date.cc). We explicitly
926# add the Object nodes so we can set up special dependencies for
927# date.cc.
928def make_objs(sources, env, static):
929 if static:
930 XObject = env.StaticObject
931 else:
932 XObject = env.SharedObject
933
934 objs = [ XObject(s) for s in sources ]
935
936 # make date.cc depend on all other objects so it always gets
937 # recompiled whenever anything else does
938 date_obj = XObject('base/date.cc')
939
940 env.Depends(date_obj, objs)
941 objs.append(date_obj)
942 return objs
943
944# Function to create a new build environment as clone of current
945# environment 'env' with modified object suffix and optional stripped
946# binary. Additional keyword arguments are appended to corresponding
947# build environment vars.
948def makeEnv(label, objsfx, strip = False, **kwargs):
949 # SCons doesn't know to append a library suffix when there is a '.' in the
950 # name. Use '_' instead.
951 libname = 'm5_' + label
952 exename = 'm5.' + label
953
954 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
955 new_env.Label = label
956 new_env.Append(**kwargs)
957
958 swig_env = new_env.Clone()
959 if env['GCC']:
960 swig_env.Append(CCFLAGS='-Wno-uninitialized')
961 swig_env.Append(CCFLAGS='-Wno-sign-compare')
962 swig_env.Append(CCFLAGS='-Wno-parentheses')
963
964 static_objs = make_objs(cc_lib_sources, new_env, static=True)
965 shared_objs = make_objs(cc_lib_sources, new_env, static=False)
966 static_objs += [ swig_env.StaticObject(s) for s in cc_swig_sources ]
967 shared_objs += [ swig_env.SharedObject(s) for s in cc_swig_sources ]
968
969 # First make a library of everything but main() so other programs can
970 # link against m5.
971 static_lib = new_env.StaticLibrary(libname, static_objs)
972 shared_lib = new_env.SharedLibrary(libname, shared_objs)
973
974 for target, sources in unit_tests:
975 objs = [ new_env.StaticObject(s) for s in sources ]
976 new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs)
977
978 # Now link a stub with main() and the static library.
979 objects = [new_env.Object(s) for s in cc_bin_sources] + static_objs
980 if strip:
981 unstripped_exe = exename + '.unstripped'
982 new_env.Program(unstripped_exe, objects)
983 if sys.platform == 'sunos5':
984 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
985 else:
986 cmd = 'strip $SOURCE -o $TARGET'
987 targets = new_env.Command(exename, unstripped_exe, cmd)
988 else:
989 targets = new_env.Program(exename, objects)
990
991 new_env.M5Binary = targets[0]
992 envList.append(new_env)
993
994# Debug binary
995ccflags = {}
996if env['GCC']:
997 if sys.platform == 'sunos5':
998 ccflags['debug'] = '-gstabs+'
999 else:
1000 ccflags['debug'] = '-ggdb3'
1001 ccflags['opt'] = '-g -O3'
1002 ccflags['fast'] = '-O3'
1003 ccflags['prof'] = '-O3 -g -pg'
1004elif env['SUNCC']:
1005 ccflags['debug'] = '-g0'
1006 ccflags['opt'] = '-g -O'
1007 ccflags['fast'] = '-fast'
1008 ccflags['prof'] = '-fast -g -pg'
1009elif env['ICC']:
1010 ccflags['debug'] = '-g -O0'
1011 ccflags['opt'] = '-g -O'
1012 ccflags['fast'] = '-fast'
1013 ccflags['prof'] = '-fast -g -pg'
1014else:
1015 print 'Unknown compiler, please fix compiler options'
1016 Exit(1)
1017
1018makeEnv('debug', '.do',
1019 CCFLAGS = Split(ccflags['debug']),
1020 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1021
1022# Optimized binary
1023makeEnv('opt', '.o',
1024 CCFLAGS = Split(ccflags['opt']),
1025 CPPDEFINES = ['TRACING_ON=1'])
1026
1027# "Fast" binary
1028makeEnv('fast', '.fo', strip = True,
1029 CCFLAGS = Split(ccflags['fast']),
1030 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1031
1032# Profiled binary
1033makeEnv('prof', '.po',
1034 CCFLAGS = Split(ccflags['prof']),
1035 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1036 LINKFLAGS = '-pg')
1037
1038Return('envList')
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 == 'defines':
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 == 'defines':
295 mod.__dict__['buildEnv'] = 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 build_env, hg_info = [ x.get_contents() for x in source ]
361 print >>f, "buildEnv = %s" % build_env
362 print >>f, "hgRev = '%s'" % hg_info
363 f.close()
364
365defines_info = [ Value(build_env), Value(env['HG_INFO']) ]
366# Generate a file with all of the compile options in it
367env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile)
368PySource('m5', 'python/m5/defines.py')
369
370# Generate python file containing info about the M5 source code
371def makeInfoPyFile(target, source, env):
372 f = file(str(target[0]), 'w')
373 for src in source:
374 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
375 print >>f, "%s = %s" % (src, repr(data))
376 f.close()
377
378# Generate a file that wraps the basic top level files
379env.Command('python/m5/info.py',
380 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
381 makeInfoPyFile)
382PySource('m5', 'python/m5/info.py')
383
384# Generate the __init__.py file for m5.objects
385def makeObjectsInitFile(target, source, env):
386 f = file(str(target[0]), 'w')
387 print >>f, 'from params import *'
388 print >>f, 'from m5.SimObject import *'
389 for module in source:
390 print >>f, 'from %s import *' % module.get_contents()
391 f.close()
392
393# Generate an __init__.py file for the objects package
394env.Command('python/m5/objects/__init__.py',
395 [ Value(o) for o in sort_list(sim_object_modfiles) ],
396 makeObjectsInitFile)
397PySource('m5.objects', 'python/m5/objects/__init__.py')
398
399########################################################################
400#
401# Create all of the SimObject param headers and enum headers
402#
403
404def createSimObjectParam(target, source, env):
405 assert len(target) == 1 and len(source) == 1
406
407 hh_file = file(target[0].abspath, 'w')
408 name = str(source[0].get_contents())
409 obj = sim_objects[name]
410
411 print >>hh_file, obj.cxx_decl()
412
413def createSwigParam(target, source, env):
414 assert len(target) == 1 and len(source) == 1
415
416 i_file = file(target[0].abspath, 'w')
417 name = str(source[0].get_contents())
418 param = all_params[name]
419
420 for line in param.swig_decl():
421 print >>i_file, line
422
423def createEnumStrings(target, source, env):
424 assert len(target) == 1 and len(source) == 1
425
426 cc_file = file(target[0].abspath, 'w')
427 name = str(source[0].get_contents())
428 obj = all_enums[name]
429
430 print >>cc_file, obj.cxx_def()
431 cc_file.close()
432
433def createEnumParam(target, source, env):
434 assert len(target) == 1 and len(source) == 1
435
436 hh_file = file(target[0].abspath, 'w')
437 name = str(source[0].get_contents())
438 obj = all_enums[name]
439
440 print >>hh_file, obj.cxx_decl()
441
442# Generate all of the SimObject param struct header files
443params_hh_files = []
444for name,simobj in sim_objects.iteritems():
445 extra_deps = [ File(py_modules[simobj.__module__]) ]
446
447 hh_file = File('params/%s.hh' % name)
448 params_hh_files.append(hh_file)
449 env.Command(hh_file, Value(name), createSimObjectParam)
450 env.Depends(hh_file, depends + extra_deps)
451
452# Generate any parameter header files needed
453params_i_files = []
454for name,param in all_params.iteritems():
455 if isinstance(param, m5.params.VectorParamDesc):
456 ext = 'vptype'
457 else:
458 ext = 'ptype'
459
460 i_file = File('params/%s_%s.i' % (name, ext))
461 params_i_files.append(i_file)
462 env.Command(i_file, Value(name), createSwigParam)
463 env.Depends(i_file, depends)
464
465# Generate all enum header files
466for name,enum in all_enums.iteritems():
467 extra_deps = [ File(py_modules[enum.__module__]) ]
468
469 cc_file = File('enums/%s.cc' % name)
470 env.Command(cc_file, Value(name), createEnumStrings)
471 env.Depends(cc_file, depends + extra_deps)
472 Source(cc_file)
473
474 hh_file = File('enums/%s.hh' % name)
475 env.Command(hh_file, Value(name), createEnumParam)
476 env.Depends(hh_file, depends + extra_deps)
477
478# Build the big monolithic swigged params module (wraps all SimObject
479# param structs and enum structs)
480def buildParams(target, source, env):
481 names = [ s.get_contents() for s in source ]
482 objs = [ sim_objects[name] for name in names ]
483 out = file(target[0].abspath, 'w')
484
485 ordered_objs = []
486 obj_seen = set()
487 def order_obj(obj):
488 name = str(obj)
489 if name in obj_seen:
490 return
491
492 obj_seen.add(name)
493 if str(obj) != 'SimObject':
494 order_obj(obj.__bases__[0])
495
496 ordered_objs.append(obj)
497
498 for obj in objs:
499 order_obj(obj)
500
501 enums = set()
502 predecls = []
503 pd_seen = set()
504
505 def add_pds(*pds):
506 for pd in pds:
507 if pd not in pd_seen:
508 predecls.append(pd)
509 pd_seen.add(pd)
510
511 for obj in ordered_objs:
512 params = obj._params.local.values()
513 for param in params:
514 ptype = param.ptype
515 if issubclass(ptype, m5.params.Enum):
516 if ptype not in enums:
517 enums.add(ptype)
518 pds = param.swig_predecls()
519 if isinstance(pds, (list, tuple)):
520 add_pds(*pds)
521 else:
522 add_pds(pds)
523
524 print >>out, '%module params'
525
526 print >>out, '%{'
527 for obj in ordered_objs:
528 print >>out, '#include "params/%s.hh"' % obj
529 print >>out, '%}'
530
531 for pd in predecls:
532 print >>out, pd
533
534 enums = list(enums)
535 enums.sort()
536 for enum in enums:
537 print >>out, '%%include "enums/%s.hh"' % enum.__name__
538 print >>out
539
540 for obj in ordered_objs:
541 if obj.swig_objdecls:
542 for decl in obj.swig_objdecls:
543 print >>out, decl
544 continue
545
546 class_path = obj.cxx_class.split('::')
547 classname = class_path[-1]
548 namespaces = class_path[:-1]
549 namespaces.reverse()
550
551 code = ''
552
553 if namespaces:
554 code += '// avoid name conflicts\n'
555 sep_string = '_COLONS_'
556 flat_name = sep_string.join(class_path)
557 code += '%%rename(%s) %s;\n' % (flat_name, classname)
558
559 code += '// stop swig from creating/wrapping default ctor/dtor\n'
560 code += '%%nodefault %s;\n' % classname
561 code += 'class %s ' % classname
562 if obj._base:
563 code += ': public %s' % obj._base.cxx_class
564 code += ' {};\n'
565
566 for ns in namespaces:
567 new_code = 'namespace %s {\n' % ns
568 new_code += code
569 new_code += '}\n'
570 code = new_code
571
572 print >>out, code
573
574 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj
575 for obj in ordered_objs:
576 print >>out, '%%include "params/%s.hh"' % obj
577
578params_file = File('params/params.i')
579names = sort_list(sim_objects.keys())
580env.Command(params_file, [ Value(v) for v in names ], buildParams)
581env.Depends(params_file, params_hh_files + params_i_files + depends)
582SwigSource('m5.objects', params_file)
583
584# Build all swig modules
585swig_modules = []
586cc_swig_sources = []
587for source,package in swig_sources:
588 filename = str(source)
589 assert filename.endswith('.i')
590
591 base = '.'.join(filename.split('.')[:-1])
592 module = basename(base)
593 cc_file = base + '_wrap.cc'
594 py_file = base + '.py'
595
596 env.Command([cc_file, py_file], source,
597 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
598 '-o ${TARGETS[0]} $SOURCES')
599 env.Depends(py_file, source)
600 env.Depends(cc_file, source)
601
602 swig_modules.append(Value(module))
603 cc_swig_sources.append(File(cc_file))
604 PySource(package, py_file)
605
606# Generate the main swig init file
607def makeSwigInit(target, source, env):
608 f = file(str(target[0]), 'w')
609 print >>f, 'extern "C" {'
610 for module in source:
611 print >>f, ' void init_%s();' % module.get_contents()
612 print >>f, '}'
613 print >>f, 'void initSwig() {'
614 for module in source:
615 print >>f, ' init_%s();' % module.get_contents()
616 print >>f, '}'
617 f.close()
618
619env.Command('python/swig/init.cc', swig_modules, makeSwigInit)
620Source('python/swig/init.cc')
621
622# Generate traceflags.py
623def traceFlagsPy(target, source, env):
624 assert(len(target) == 1)
625
626 f = file(str(target[0]), 'w')
627
628 allFlags = []
629 for s in source:
630 val = eval(s.get_contents())
631 allFlags.append(val)
632
633 allFlags.sort()
634
635 print >>f, 'basic = ['
636 for flag, compound, desc in allFlags:
637 if not compound:
638 print >>f, " '%s'," % flag
639 print >>f, " ]"
640 print >>f
641
642 print >>f, 'compound = ['
643 print >>f, " 'All',"
644 for flag, compound, desc in allFlags:
645 if compound:
646 print >>f, " '%s'," % flag
647 print >>f, " ]"
648 print >>f
649
650 print >>f, "all = frozenset(basic + compound)"
651 print >>f
652
653 print >>f, 'compoundMap = {'
654 all = tuple([flag for flag,compound,desc in allFlags if not compound])
655 print >>f, " 'All' : %s," % (all, )
656 for flag, compound, desc in allFlags:
657 if compound:
658 print >>f, " '%s' : %s," % (flag, compound)
659 print >>f, " }"
660 print >>f
661
662 print >>f, 'descriptions = {'
663 print >>f, " 'All' : 'All flags',"
664 for flag, compound, desc in allFlags:
665 print >>f, " '%s' : '%s'," % (flag, desc)
666 print >>f, " }"
667
668 f.close()
669
670def traceFlagsCC(target, source, env):
671 assert(len(target) == 1)
672
673 f = file(str(target[0]), 'w')
674
675 allFlags = []
676 for s in source:
677 val = eval(s.get_contents())
678 allFlags.append(val)
679
680 # file header
681 print >>f, '''
682/*
683 * DO NOT EDIT THIS FILE! Automatically generated
684 */
685
686#include "base/traceflags.hh"
687
688using namespace Trace;
689
690const char *Trace::flagStrings[] =
691{'''
692
693 # The string array is used by SimpleEnumParam to map the strings
694 # provided by the user to enum values.
695 for flag, compound, desc in allFlags:
696 if not compound:
697 print >>f, ' "%s",' % flag
698
699 print >>f, ' "All",'
700 for flag, compound, desc in allFlags:
701 if compound:
702 print >>f, ' "%s",' % flag
703
704 print >>f, '};'
705 print >>f
706 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
707 print >>f
708
709 #
710 # Now define the individual compound flag arrays. There is an array
711 # for each compound flag listing the component base flags.
712 #
713 all = tuple([flag for flag,compound,desc in allFlags if not compound])
714 print >>f, 'static const Flags AllMap[] = {'
715 for flag, compound, desc in allFlags:
716 if not compound:
717 print >>f, " %s," % flag
718 print >>f, '};'
719 print >>f
720
721 for flag, compound, desc in allFlags:
722 if not compound:
723 continue
724 print >>f, 'static const Flags %sMap[] = {' % flag
725 for flag in compound:
726 print >>f, " %s," % flag
727 print >>f, " (Flags)-1"
728 print >>f, '};'
729 print >>f
730
731 #
732 # Finally the compoundFlags[] array maps the compound flags
733 # to their individual arrays/
734 #
735 print >>f, 'const Flags *Trace::compoundFlags[] ='
736 print >>f, '{'
737 print >>f, ' AllMap,'
738 for flag, compound, desc in allFlags:
739 if compound:
740 print >>f, ' %sMap,' % flag
741 # file trailer
742 print >>f, '};'
743
744 f.close()
745
746def traceFlagsHH(target, source, env):
747 assert(len(target) == 1)
748
749 f = file(str(target[0]), 'w')
750
751 allFlags = []
752 for s in source:
753 val = eval(s.get_contents())
754 allFlags.append(val)
755
756 # file header boilerplate
757 print >>f, '''
758/*
759 * DO NOT EDIT THIS FILE!
760 *
761 * Automatically generated from traceflags.py
762 */
763
764#ifndef __BASE_TRACE_FLAGS_HH__
765#define __BASE_TRACE_FLAGS_HH__
766
767namespace Trace {
768
769enum Flags {'''
770
771 # Generate the enum. Base flags come first, then compound flags.
772 idx = 0
773 for flag, compound, desc in allFlags:
774 if not compound:
775 print >>f, ' %s = %d,' % (flag, idx)
776 idx += 1
777
778 numBaseFlags = idx
779 print >>f, ' NumFlags = %d,' % idx
780
781 # put a comment in here to separate base from compound flags
782 print >>f, '''
783// The remaining enum values are *not* valid indices for Trace::flags.
784// They are "compound" flags, which correspond to sets of base
785// flags, and are used by changeFlag.'''
786
787 print >>f, ' All = %d,' % idx
788 idx += 1
789 for flag, compound, desc in allFlags:
790 if compound:
791 print >>f, ' %s = %d,' % (flag, idx)
792 idx += 1
793
794 numCompoundFlags = idx - numBaseFlags
795 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags
796
797 # trailer boilerplate
798 print >>f, '''\
799}; // enum Flags
800
801// Array of strings for SimpleEnumParam
802extern const char *flagStrings[];
803extern const int numFlagStrings;
804
805// Array of arraay pointers: for each compound flag, gives the list of
806// base flags to set. Inidividual flag arrays are terminated by -1.
807extern const Flags *compoundFlags[];
808
809/* namespace Trace */ }
810
811#endif // __BASE_TRACE_FLAGS_HH__
812'''
813
814 f.close()
815
816flags = [ Value(f) for f in trace_flags.values() ]
817env.Command('base/traceflags.py', flags, traceFlagsPy)
818PySource('m5', 'base/traceflags.py')
819
820env.Command('base/traceflags.hh', flags, traceFlagsHH)
821env.Command('base/traceflags.cc', flags, traceFlagsCC)
822Source('base/traceflags.cc')
823
824# embed python files. All .py files that have been indicated by a
825# PySource() call in a SConscript need to be embedded into the M5
826# library. To do that, we compile the file to byte code, marshal the
827# byte code, compress it, and then generate an assembly file that
828# inserts the result into the data section with symbols indicating the
829# beginning, and end (and with the size at the end)
830py_sources_tnodes = {}
831for pysource in py_sources:
832 py_sources_tnodes[pysource.tnode] = pysource
833
834def objectifyPyFile(target, source, env):
835 '''Action function to compile a .py into a code object, marshal
836 it, compress it, and stick it into an asm file so the code appears
837 as just bytes with a label in the data section'''
838
839 src = file(str(source[0]), 'r').read()
840 dst = file(str(target[0]), 'w')
841
842 pysource = py_sources_tnodes[source[0]]
843 compiled = compile(src, pysource.debugname, 'exec')
844 marshalled = marshal.dumps(compiled)
845 compressed = zlib.compress(marshalled)
846 data = compressed
847
848 # Some C/C++ compilers prepend an underscore to global symbol
849 # names, so if they're going to do that, we need to prepend that
850 # leading underscore to globals in the assembly file.
851 if env['LEADING_UNDERSCORE']:
852 sym = '_' + pysource.symname
853 else:
854 sym = pysource.symname
855
856 step = 16
857 print >>dst, ".data"
858 print >>dst, ".globl %s_beg" % sym
859 print >>dst, ".globl %s_end" % sym
860 print >>dst, "%s_beg:" % sym
861 for i in xrange(0, len(data), step):
862 x = array.array('B', data[i:i+step])
863 print >>dst, ".byte", ','.join([str(d) for d in x])
864 print >>dst, "%s_end:" % sym
865 print >>dst, ".long %d" % len(marshalled)
866
867for source in py_sources:
868 env.Command(source.assembly, source.tnode, objectifyPyFile)
869 Source(source.assembly)
870
871# Generate init_python.cc which creates a bunch of EmbeddedPyModule
872# structs that describe the embedded python code. One such struct
873# contains information about the importer that python uses to get at
874# the embedded files, and then there's a list of all of the rest that
875# the importer uses to load the rest on demand.
876py_sources_symbols = {}
877for pysource in py_sources:
878 py_sources_symbols[pysource.symname] = pysource
879def pythonInit(target, source, env):
880 dst = file(str(target[0]), 'w')
881
882 def dump_mod(sym, endchar=','):
883 pysource = py_sources_symbols[sym]
884 print >>dst, ' { "%s",' % pysource.arcname
885 print >>dst, ' "%s",' % pysource.modpath
886 print >>dst, ' %s_beg, %s_end,' % (sym, sym)
887 print >>dst, ' %s_end - %s_beg,' % (sym, sym)
888 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar)
889
890 print >>dst, '#include "sim/init.hh"'
891
892 for sym in source:
893 sym = sym.get_contents()
894 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym)
895
896 print >>dst, "const EmbeddedPyModule embeddedPyImporter = "
897 dump_mod("PyEMB_importer", endchar=';');
898 print >>dst
899
900 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {"
901 for i,sym in enumerate(source):
902 sym = sym.get_contents()
903 if sym == "PyEMB_importer":
904 # Skip the importer since we've already exported it
905 continue
906 dump_mod(sym)
907 print >>dst, " { 0, 0, 0, 0, 0, 0 }"
908 print >>dst, "};"
909
910symbols = [Value(s.symname) for s in py_sources]
911env.Command('sim/init_python.cc', symbols, pythonInit)
912Source('sim/init_python.cc')
913
914########################################################################
915#
916# Define binaries. Each different build type (debug, opt, etc.) gets
917# a slightly different build environment.
918#
919
920# List of constructed environments to pass back to SConstruct
921envList = []
922
923# This function adds the specified sources to the given build
924# environment, and returns a list of all the corresponding SCons
925# Object nodes (including an extra one for date.cc). We explicitly
926# add the Object nodes so we can set up special dependencies for
927# date.cc.
928def make_objs(sources, env, static):
929 if static:
930 XObject = env.StaticObject
931 else:
932 XObject = env.SharedObject
933
934 objs = [ XObject(s) for s in sources ]
935
936 # make date.cc depend on all other objects so it always gets
937 # recompiled whenever anything else does
938 date_obj = XObject('base/date.cc')
939
940 env.Depends(date_obj, objs)
941 objs.append(date_obj)
942 return objs
943
944# Function to create a new build environment as clone of current
945# environment 'env' with modified object suffix and optional stripped
946# binary. Additional keyword arguments are appended to corresponding
947# build environment vars.
948def makeEnv(label, objsfx, strip = False, **kwargs):
949 # SCons doesn't know to append a library suffix when there is a '.' in the
950 # name. Use '_' instead.
951 libname = 'm5_' + label
952 exename = 'm5.' + label
953
954 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
955 new_env.Label = label
956 new_env.Append(**kwargs)
957
958 swig_env = new_env.Clone()
959 if env['GCC']:
960 swig_env.Append(CCFLAGS='-Wno-uninitialized')
961 swig_env.Append(CCFLAGS='-Wno-sign-compare')
962 swig_env.Append(CCFLAGS='-Wno-parentheses')
963
964 static_objs = make_objs(cc_lib_sources, new_env, static=True)
965 shared_objs = make_objs(cc_lib_sources, new_env, static=False)
966 static_objs += [ swig_env.StaticObject(s) for s in cc_swig_sources ]
967 shared_objs += [ swig_env.SharedObject(s) for s in cc_swig_sources ]
968
969 # First make a library of everything but main() so other programs can
970 # link against m5.
971 static_lib = new_env.StaticLibrary(libname, static_objs)
972 shared_lib = new_env.SharedLibrary(libname, shared_objs)
973
974 for target, sources in unit_tests:
975 objs = [ new_env.StaticObject(s) for s in sources ]
976 new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs)
977
978 # Now link a stub with main() and the static library.
979 objects = [new_env.Object(s) for s in cc_bin_sources] + static_objs
980 if strip:
981 unstripped_exe = exename + '.unstripped'
982 new_env.Program(unstripped_exe, objects)
983 if sys.platform == 'sunos5':
984 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
985 else:
986 cmd = 'strip $SOURCE -o $TARGET'
987 targets = new_env.Command(exename, unstripped_exe, cmd)
988 else:
989 targets = new_env.Program(exename, objects)
990
991 new_env.M5Binary = targets[0]
992 envList.append(new_env)
993
994# Debug binary
995ccflags = {}
996if env['GCC']:
997 if sys.platform == 'sunos5':
998 ccflags['debug'] = '-gstabs+'
999 else:
1000 ccflags['debug'] = '-ggdb3'
1001 ccflags['opt'] = '-g -O3'
1002 ccflags['fast'] = '-O3'
1003 ccflags['prof'] = '-O3 -g -pg'
1004elif env['SUNCC']:
1005 ccflags['debug'] = '-g0'
1006 ccflags['opt'] = '-g -O'
1007 ccflags['fast'] = '-fast'
1008 ccflags['prof'] = '-fast -g -pg'
1009elif env['ICC']:
1010 ccflags['debug'] = '-g -O0'
1011 ccflags['opt'] = '-g -O'
1012 ccflags['fast'] = '-fast'
1013 ccflags['prof'] = '-fast -g -pg'
1014else:
1015 print 'Unknown compiler, please fix compiler options'
1016 Exit(1)
1017
1018makeEnv('debug', '.do',
1019 CCFLAGS = Split(ccflags['debug']),
1020 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1021
1022# Optimized binary
1023makeEnv('opt', '.o',
1024 CCFLAGS = Split(ccflags['opt']),
1025 CPPDEFINES = ['TRACING_ON=1'])
1026
1027# "Fast" binary
1028makeEnv('fast', '.fo', strip = True,
1029 CCFLAGS = Split(ccflags['fast']),
1030 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1031
1032# Profiled binary
1033makeEnv('prof', '.po',
1034 CCFLAGS = Split(ccflags['prof']),
1035 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1036 LINKFLAGS = '-pg')
1037
1038Return('envList')