SConscript (7675:2221ec64132f) SConscript (7677:c6e283904437)
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 bisect
33import imp
34import marshal
35import os
36import re
37import sys
38import zlib
39
40from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
41
42import SCons
43
44# This file defines how to build a particular configuration of M5
45# based on variable settings in the 'env' build environment.
46
47Import('*')
48
49# Children need to see the environment
50Export('env')
51
52build_env = [(opt, env[opt]) for opt in export_vars]
53
54from m5.util import code_formatter
55
56########################################################################
57# Code for adding source files of various types
58#
59class SourceMeta(type):
60 def __init__(cls, name, bases, dict):
61 super(SourceMeta, cls).__init__(name, bases, dict)
62 cls.all = []
63
64 def get(cls, **kwargs):
65 for src in cls.all:
66 for attr,value in kwargs.iteritems():
67 if getattr(src, attr) != value:
68 break
69 else:
70 yield src
71
72class SourceFile(object):
73 __metaclass__ = SourceMeta
74 def __init__(self, source):
75 tnode = source
76 if not isinstance(source, SCons.Node.FS.File):
77 tnode = File(source)
78
79 self.tnode = tnode
80 self.snode = tnode.srcnode()
81 self.filename = str(tnode)
82 self.dirname = dirname(self.filename)
83 self.basename = basename(self.filename)
84 index = self.basename.rfind('.')
85 if index <= 0:
86 # dot files aren't extensions
87 self.extname = self.basename, None
88 else:
89 self.extname = self.basename[:index], self.basename[index+1:]
90
91 for base in type(self).__mro__:
92 if issubclass(base, SourceFile):
93 base.all.append(self)
94
95 def __lt__(self, other): return self.filename < other.filename
96 def __le__(self, other): return self.filename <= other.filename
97 def __gt__(self, other): return self.filename > other.filename
98 def __ge__(self, other): return self.filename >= other.filename
99 def __eq__(self, other): return self.filename == other.filename
100 def __ne__(self, other): return self.filename != other.filename
101
102class Source(SourceFile):
103 '''Add a c/c++ source file to the build'''
104 def __init__(self, source, Werror=True, swig=False, bin_only=False,
105 skip_lib=False):
106 super(Source, self).__init__(source)
107
108 self.Werror = Werror
109 self.swig = swig
110 self.bin_only = bin_only
111 self.skip_lib = bin_only or skip_lib
112
113class PySource(SourceFile):
114 '''Add a python source file to the named package'''
115 invalid_sym_char = re.compile('[^A-z0-9_]')
116 modules = {}
117 tnodes = {}
118 symnames = {}
119
120 def __init__(self, package, source):
121 super(PySource, self).__init__(source)
122
123 modname,ext = self.extname
124 assert ext == 'py'
125
126 if package:
127 path = package.split('.')
128 else:
129 path = []
130
131 modpath = path[:]
132 if modname != '__init__':
133 modpath += [ modname ]
134 modpath = '.'.join(modpath)
135
136 arcpath = path + [ self.basename ]
137 abspath = self.snode.abspath
138 if not exists(abspath):
139 abspath = self.tnode.abspath
140
141 self.package = package
142 self.modname = modname
143 self.modpath = modpath
144 self.arcname = joinpath(*arcpath)
145 self.abspath = abspath
146 self.compiled = File(self.filename + 'c')
147 self.cpp = File(self.filename + '.cc')
148 self.symname = PySource.invalid_sym_char.sub('_', modpath)
149
150 PySource.modules[modpath] = self
151 PySource.tnodes[self.tnode] = self
152 PySource.symnames[self.symname] = self
153
154class SimObject(PySource):
155 '''Add a SimObject python file as a python source object and add
156 it to a list of sim object modules'''
157
158 fixed = False
159 modnames = []
160
161 def __init__(self, source):
162 super(SimObject, self).__init__('m5.objects', source)
163 if self.fixed:
164 raise AttributeError, "Too late to call SimObject now."
165
166 bisect.insort_right(SimObject.modnames, self.modname)
167
168class SwigSource(SourceFile):
169 '''Add a swig file to build'''
170
171 def __init__(self, package, source):
172 super(SwigSource, self).__init__(source)
173
174 modname,ext = self.extname
175 assert ext == 'i'
176
177 self.module = modname
178 cc_file = joinpath(self.dirname, modname + '_wrap.cc')
179 py_file = joinpath(self.dirname, modname + '.py')
180
181 self.cc_source = Source(cc_file, swig=True)
182 self.py_source = PySource(package, py_file)
183
184unit_tests = []
185def UnitTest(target, sources):
186 if not isinstance(sources, (list, tuple)):
187 sources = [ sources ]
188
189 sources = [ Source(src, skip_lib=True) for src in sources ]
190 unit_tests.append((target, sources))
191
192# Children should have access
193Export('Source')
194Export('PySource')
195Export('SimObject')
196Export('SwigSource')
197Export('UnitTest')
198
199########################################################################
200#
201# Trace Flags
202#
203trace_flags = {}
204def TraceFlag(name, desc=None):
205 if name in trace_flags:
206 raise AttributeError, "Flag %s already specified" % name
207 trace_flags[name] = (name, (), desc)
208
209def CompoundFlag(name, flags, desc=None):
210 if name in trace_flags:
211 raise AttributeError, "Flag %s already specified" % name
212
213 compound = tuple(flags)
214 trace_flags[name] = (name, compound, desc)
215
216Export('TraceFlag')
217Export('CompoundFlag')
218
219########################################################################
220#
221# Set some compiler variables
222#
223
224# Include file paths are rooted in this directory. SCons will
225# automatically expand '.' to refer to both the source directory and
226# the corresponding build directory to pick up generated include
227# files.
228env.Append(CPPPATH=Dir('.'))
229
230for extra_dir in extras_dir_list:
231 env.Append(CPPPATH=Dir(extra_dir))
232
233# Workaround for bug in SCons version > 0.97d20071212
234# Scons bug id: 2006 M5 Bug id: 308
235for root, dirs, files in os.walk(base_dir, topdown=True):
236 Dir(root[len(base_dir) + 1:])
237
238########################################################################
239#
240# Walk the tree and execute all SConscripts in subdirectories
241#
242
243here = Dir('.').srcnode().abspath
244for root, dirs, files in os.walk(base_dir, topdown=True):
245 if root == here:
246 # we don't want to recurse back into this SConscript
247 continue
248
249 if 'SConscript' in files:
250 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
251 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
252
253for extra_dir in extras_dir_list:
254 prefix_len = len(dirname(extra_dir)) + 1
255 for root, dirs, files in os.walk(extra_dir, topdown=True):
256 if 'SConscript' in files:
257 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
258 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
259
260for opt in export_vars:
261 env.ConfigFile(opt)
262
263def makeTheISA(source, target, env):
264 isas = [ src.get_contents() for src in source ]
265 target_isa = env['TARGET_ISA']
266 def define(isa):
267 return isa.upper() + '_ISA'
268
269 def namespace(isa):
270 return isa[0].upper() + isa[1:].lower() + 'ISA'
271
272
273 code = code_formatter()
274 code('''\
275#ifndef __CONFIG_THE_ISA_HH__
276#define __CONFIG_THE_ISA_HH__
277
278''')
279
280 for i,isa in enumerate(isas):
281 code('#define $0 $1', define(isa), i + 1)
282
283 code('''
284
285#define THE_ISA ${{define(target_isa)}}
286#define TheISA ${{namespace(target_isa)}}
287
288#endif // __CONFIG_THE_ISA_HH__''')
289
290 code.write(str(target[0]))
291
292env.Command('config/the_isa.hh', map(Value, all_isa_list), makeTheISA)
293
294########################################################################
295#
296# Prevent any SimObjects from being added after this point, they
297# should all have been added in the SConscripts above
298#
299SimObject.fixed = True
300
301class DictImporter(object):
302 '''This importer takes a dictionary of arbitrary module names that
303 map to arbitrary filenames.'''
304 def __init__(self, modules):
305 self.modules = modules
306 self.installed = set()
307
308 def __del__(self):
309 self.unload()
310
311 def unload(self):
312 import sys
313 for module in self.installed:
314 del sys.modules[module]
315 self.installed = set()
316
317 def find_module(self, fullname, path):
318 if fullname == 'm5.defines':
319 return self
320
321 if fullname == 'm5.objects':
322 return self
323
324 if fullname.startswith('m5.internal'):
325 return None
326
327 source = self.modules.get(fullname, None)
328 if source is not None and fullname.startswith('m5.objects'):
329 return self
330
331 return None
332
333 def load_module(self, fullname):
334 mod = imp.new_module(fullname)
335 sys.modules[fullname] = mod
336 self.installed.add(fullname)
337
338 mod.__loader__ = self
339 if fullname == 'm5.objects':
340 mod.__path__ = fullname.split('.')
341 return mod
342
343 if fullname == 'm5.defines':
344 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
345 return mod
346
347 source = self.modules[fullname]
348 if source.modname == '__init__':
349 mod.__path__ = source.modpath
350 mod.__file__ = source.abspath
351
352 exec file(source.abspath, 'r') in mod.__dict__
353
354 return mod
355
356import m5.SimObject
357import m5.params
358from m5.util import code_formatter
359
360m5.SimObject.clear()
361m5.params.clear()
362
363# install the python importer so we can grab stuff from the source
364# tree itself. We can't have SimObjects added after this point or
365# else we won't know about them for the rest of the stuff.
366importer = DictImporter(PySource.modules)
367sys.meta_path[0:0] = [ importer ]
368
369# import all sim objects so we can populate the all_objects list
370# make sure that we're working with a list, then let's sort it
371for modname in SimObject.modnames:
372 exec('from m5.objects import %s' % modname)
373
374# we need to unload all of the currently imported modules so that they
375# will be re-imported the next time the sconscript is run
376importer.unload()
377sys.meta_path.remove(importer)
378
379sim_objects = m5.SimObject.allClasses
380all_enums = m5.params.allEnums
381
382all_params = {}
383for name,obj in sorted(sim_objects.iteritems()):
384 for param in obj._params.local.values():
385 # load the ptype attribute now because it depends on the
386 # current version of SimObject.allClasses, but when scons
387 # actually uses the value, all versions of
388 # SimObject.allClasses will have been loaded
389 param.ptype
390
391 if not hasattr(param, 'swig_decl'):
392 continue
393 pname = param.ptype_str
394 if pname not in all_params:
395 all_params[pname] = param
396
397########################################################################
398#
399# calculate extra dependencies
400#
401module_depends = ["m5", "m5.SimObject", "m5.params"]
402depends = [ PySource.modules[dep].snode for dep in module_depends ]
403
404########################################################################
405#
406# Commands for the basic automatically generated python files
407#
408
409# Generate Python file containing a dict specifying the current
410# buildEnv flags.
411def makeDefinesPyFile(target, source, env):
412 build_env, hg_info = [ x.get_contents() for x in source ]
413
414 code = code_formatter()
415 code("""
416import m5.internal
417import m5.util
418
419buildEnv = m5.util.SmartDict($build_env)
420hgRev = '$hg_info'
421
422compileDate = m5.internal.core.compileDate
423_globals = globals()
424for key,val in m5.internal.core.__dict__.iteritems():
425 if key.startswith('flag_'):
426 flag = key[5:]
427 _globals[flag] = val
428del _globals
429""")
430 code.write(target[0].abspath)
431
432defines_info = [ Value(build_env), Value(env['HG_INFO']) ]
433# Generate a file with all of the compile options in it
434env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile)
435PySource('m5', 'python/m5/defines.py')
436
437# Generate python file containing info about the M5 source code
438def makeInfoPyFile(target, source, env):
439 code = code_formatter()
440 for src in source:
441 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
442 code('$src = ${{repr(data)}}')
443 code.write(str(target[0]))
444
445# Generate a file that wraps the basic top level files
446env.Command('python/m5/info.py',
447 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
448 makeInfoPyFile)
449PySource('m5', 'python/m5/info.py')
450
451########################################################################
452#
453# Create all of the SimObject param headers and enum headers
454#
455
456def createSimObjectParam(target, source, env):
457 assert len(target) == 1 and len(source) == 1
458
459 name = str(source[0].get_contents())
460 obj = sim_objects[name]
461
462 code = code_formatter()
463 obj.cxx_decl(code)
464 code.write(target[0].abspath)
465
466def createSwigParam(target, source, env):
467 assert len(target) == 1 and len(source) == 1
468
469 name = str(source[0].get_contents())
470 param = all_params[name]
471
472 code = code_formatter()
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 bisect
33import imp
34import marshal
35import os
36import re
37import sys
38import zlib
39
40from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
41
42import SCons
43
44# This file defines how to build a particular configuration of M5
45# based on variable settings in the 'env' build environment.
46
47Import('*')
48
49# Children need to see the environment
50Export('env')
51
52build_env = [(opt, env[opt]) for opt in export_vars]
53
54from m5.util import code_formatter
55
56########################################################################
57# Code for adding source files of various types
58#
59class SourceMeta(type):
60 def __init__(cls, name, bases, dict):
61 super(SourceMeta, cls).__init__(name, bases, dict)
62 cls.all = []
63
64 def get(cls, **kwargs):
65 for src in cls.all:
66 for attr,value in kwargs.iteritems():
67 if getattr(src, attr) != value:
68 break
69 else:
70 yield src
71
72class SourceFile(object):
73 __metaclass__ = SourceMeta
74 def __init__(self, source):
75 tnode = source
76 if not isinstance(source, SCons.Node.FS.File):
77 tnode = File(source)
78
79 self.tnode = tnode
80 self.snode = tnode.srcnode()
81 self.filename = str(tnode)
82 self.dirname = dirname(self.filename)
83 self.basename = basename(self.filename)
84 index = self.basename.rfind('.')
85 if index <= 0:
86 # dot files aren't extensions
87 self.extname = self.basename, None
88 else:
89 self.extname = self.basename[:index], self.basename[index+1:]
90
91 for base in type(self).__mro__:
92 if issubclass(base, SourceFile):
93 base.all.append(self)
94
95 def __lt__(self, other): return self.filename < other.filename
96 def __le__(self, other): return self.filename <= other.filename
97 def __gt__(self, other): return self.filename > other.filename
98 def __ge__(self, other): return self.filename >= other.filename
99 def __eq__(self, other): return self.filename == other.filename
100 def __ne__(self, other): return self.filename != other.filename
101
102class Source(SourceFile):
103 '''Add a c/c++ source file to the build'''
104 def __init__(self, source, Werror=True, swig=False, bin_only=False,
105 skip_lib=False):
106 super(Source, self).__init__(source)
107
108 self.Werror = Werror
109 self.swig = swig
110 self.bin_only = bin_only
111 self.skip_lib = bin_only or skip_lib
112
113class PySource(SourceFile):
114 '''Add a python source file to the named package'''
115 invalid_sym_char = re.compile('[^A-z0-9_]')
116 modules = {}
117 tnodes = {}
118 symnames = {}
119
120 def __init__(self, package, source):
121 super(PySource, self).__init__(source)
122
123 modname,ext = self.extname
124 assert ext == 'py'
125
126 if package:
127 path = package.split('.')
128 else:
129 path = []
130
131 modpath = path[:]
132 if modname != '__init__':
133 modpath += [ modname ]
134 modpath = '.'.join(modpath)
135
136 arcpath = path + [ self.basename ]
137 abspath = self.snode.abspath
138 if not exists(abspath):
139 abspath = self.tnode.abspath
140
141 self.package = package
142 self.modname = modname
143 self.modpath = modpath
144 self.arcname = joinpath(*arcpath)
145 self.abspath = abspath
146 self.compiled = File(self.filename + 'c')
147 self.cpp = File(self.filename + '.cc')
148 self.symname = PySource.invalid_sym_char.sub('_', modpath)
149
150 PySource.modules[modpath] = self
151 PySource.tnodes[self.tnode] = self
152 PySource.symnames[self.symname] = self
153
154class SimObject(PySource):
155 '''Add a SimObject python file as a python source object and add
156 it to a list of sim object modules'''
157
158 fixed = False
159 modnames = []
160
161 def __init__(self, source):
162 super(SimObject, self).__init__('m5.objects', source)
163 if self.fixed:
164 raise AttributeError, "Too late to call SimObject now."
165
166 bisect.insort_right(SimObject.modnames, self.modname)
167
168class SwigSource(SourceFile):
169 '''Add a swig file to build'''
170
171 def __init__(self, package, source):
172 super(SwigSource, self).__init__(source)
173
174 modname,ext = self.extname
175 assert ext == 'i'
176
177 self.module = modname
178 cc_file = joinpath(self.dirname, modname + '_wrap.cc')
179 py_file = joinpath(self.dirname, modname + '.py')
180
181 self.cc_source = Source(cc_file, swig=True)
182 self.py_source = PySource(package, py_file)
183
184unit_tests = []
185def UnitTest(target, sources):
186 if not isinstance(sources, (list, tuple)):
187 sources = [ sources ]
188
189 sources = [ Source(src, skip_lib=True) for src in sources ]
190 unit_tests.append((target, sources))
191
192# Children should have access
193Export('Source')
194Export('PySource')
195Export('SimObject')
196Export('SwigSource')
197Export('UnitTest')
198
199########################################################################
200#
201# Trace Flags
202#
203trace_flags = {}
204def TraceFlag(name, desc=None):
205 if name in trace_flags:
206 raise AttributeError, "Flag %s already specified" % name
207 trace_flags[name] = (name, (), desc)
208
209def CompoundFlag(name, flags, desc=None):
210 if name in trace_flags:
211 raise AttributeError, "Flag %s already specified" % name
212
213 compound = tuple(flags)
214 trace_flags[name] = (name, compound, desc)
215
216Export('TraceFlag')
217Export('CompoundFlag')
218
219########################################################################
220#
221# Set some compiler variables
222#
223
224# Include file paths are rooted in this directory. SCons will
225# automatically expand '.' to refer to both the source directory and
226# the corresponding build directory to pick up generated include
227# files.
228env.Append(CPPPATH=Dir('.'))
229
230for extra_dir in extras_dir_list:
231 env.Append(CPPPATH=Dir(extra_dir))
232
233# Workaround for bug in SCons version > 0.97d20071212
234# Scons bug id: 2006 M5 Bug id: 308
235for root, dirs, files in os.walk(base_dir, topdown=True):
236 Dir(root[len(base_dir) + 1:])
237
238########################################################################
239#
240# Walk the tree and execute all SConscripts in subdirectories
241#
242
243here = Dir('.').srcnode().abspath
244for root, dirs, files in os.walk(base_dir, topdown=True):
245 if root == here:
246 # we don't want to recurse back into this SConscript
247 continue
248
249 if 'SConscript' in files:
250 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
251 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
252
253for extra_dir in extras_dir_list:
254 prefix_len = len(dirname(extra_dir)) + 1
255 for root, dirs, files in os.walk(extra_dir, topdown=True):
256 if 'SConscript' in files:
257 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
258 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
259
260for opt in export_vars:
261 env.ConfigFile(opt)
262
263def makeTheISA(source, target, env):
264 isas = [ src.get_contents() for src in source ]
265 target_isa = env['TARGET_ISA']
266 def define(isa):
267 return isa.upper() + '_ISA'
268
269 def namespace(isa):
270 return isa[0].upper() + isa[1:].lower() + 'ISA'
271
272
273 code = code_formatter()
274 code('''\
275#ifndef __CONFIG_THE_ISA_HH__
276#define __CONFIG_THE_ISA_HH__
277
278''')
279
280 for i,isa in enumerate(isas):
281 code('#define $0 $1', define(isa), i + 1)
282
283 code('''
284
285#define THE_ISA ${{define(target_isa)}}
286#define TheISA ${{namespace(target_isa)}}
287
288#endif // __CONFIG_THE_ISA_HH__''')
289
290 code.write(str(target[0]))
291
292env.Command('config/the_isa.hh', map(Value, all_isa_list), makeTheISA)
293
294########################################################################
295#
296# Prevent any SimObjects from being added after this point, they
297# should all have been added in the SConscripts above
298#
299SimObject.fixed = True
300
301class DictImporter(object):
302 '''This importer takes a dictionary of arbitrary module names that
303 map to arbitrary filenames.'''
304 def __init__(self, modules):
305 self.modules = modules
306 self.installed = set()
307
308 def __del__(self):
309 self.unload()
310
311 def unload(self):
312 import sys
313 for module in self.installed:
314 del sys.modules[module]
315 self.installed = set()
316
317 def find_module(self, fullname, path):
318 if fullname == 'm5.defines':
319 return self
320
321 if fullname == 'm5.objects':
322 return self
323
324 if fullname.startswith('m5.internal'):
325 return None
326
327 source = self.modules.get(fullname, None)
328 if source is not None and fullname.startswith('m5.objects'):
329 return self
330
331 return None
332
333 def load_module(self, fullname):
334 mod = imp.new_module(fullname)
335 sys.modules[fullname] = mod
336 self.installed.add(fullname)
337
338 mod.__loader__ = self
339 if fullname == 'm5.objects':
340 mod.__path__ = fullname.split('.')
341 return mod
342
343 if fullname == 'm5.defines':
344 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
345 return mod
346
347 source = self.modules[fullname]
348 if source.modname == '__init__':
349 mod.__path__ = source.modpath
350 mod.__file__ = source.abspath
351
352 exec file(source.abspath, 'r') in mod.__dict__
353
354 return mod
355
356import m5.SimObject
357import m5.params
358from m5.util import code_formatter
359
360m5.SimObject.clear()
361m5.params.clear()
362
363# install the python importer so we can grab stuff from the source
364# tree itself. We can't have SimObjects added after this point or
365# else we won't know about them for the rest of the stuff.
366importer = DictImporter(PySource.modules)
367sys.meta_path[0:0] = [ importer ]
368
369# import all sim objects so we can populate the all_objects list
370# make sure that we're working with a list, then let's sort it
371for modname in SimObject.modnames:
372 exec('from m5.objects import %s' % modname)
373
374# we need to unload all of the currently imported modules so that they
375# will be re-imported the next time the sconscript is run
376importer.unload()
377sys.meta_path.remove(importer)
378
379sim_objects = m5.SimObject.allClasses
380all_enums = m5.params.allEnums
381
382all_params = {}
383for name,obj in sorted(sim_objects.iteritems()):
384 for param in obj._params.local.values():
385 # load the ptype attribute now because it depends on the
386 # current version of SimObject.allClasses, but when scons
387 # actually uses the value, all versions of
388 # SimObject.allClasses will have been loaded
389 param.ptype
390
391 if not hasattr(param, 'swig_decl'):
392 continue
393 pname = param.ptype_str
394 if pname not in all_params:
395 all_params[pname] = param
396
397########################################################################
398#
399# calculate extra dependencies
400#
401module_depends = ["m5", "m5.SimObject", "m5.params"]
402depends = [ PySource.modules[dep].snode for dep in module_depends ]
403
404########################################################################
405#
406# Commands for the basic automatically generated python files
407#
408
409# Generate Python file containing a dict specifying the current
410# buildEnv flags.
411def makeDefinesPyFile(target, source, env):
412 build_env, hg_info = [ x.get_contents() for x in source ]
413
414 code = code_formatter()
415 code("""
416import m5.internal
417import m5.util
418
419buildEnv = m5.util.SmartDict($build_env)
420hgRev = '$hg_info'
421
422compileDate = m5.internal.core.compileDate
423_globals = globals()
424for key,val in m5.internal.core.__dict__.iteritems():
425 if key.startswith('flag_'):
426 flag = key[5:]
427 _globals[flag] = val
428del _globals
429""")
430 code.write(target[0].abspath)
431
432defines_info = [ Value(build_env), Value(env['HG_INFO']) ]
433# Generate a file with all of the compile options in it
434env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile)
435PySource('m5', 'python/m5/defines.py')
436
437# Generate python file containing info about the M5 source code
438def makeInfoPyFile(target, source, env):
439 code = code_formatter()
440 for src in source:
441 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
442 code('$src = ${{repr(data)}}')
443 code.write(str(target[0]))
444
445# Generate a file that wraps the basic top level files
446env.Command('python/m5/info.py',
447 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
448 makeInfoPyFile)
449PySource('m5', 'python/m5/info.py')
450
451########################################################################
452#
453# Create all of the SimObject param headers and enum headers
454#
455
456def createSimObjectParam(target, source, env):
457 assert len(target) == 1 and len(source) == 1
458
459 name = str(source[0].get_contents())
460 obj = sim_objects[name]
461
462 code = code_formatter()
463 obj.cxx_decl(code)
464 code.write(target[0].abspath)
465
466def createSwigParam(target, source, env):
467 assert len(target) == 1 and len(source) == 1
468
469 name = str(source[0].get_contents())
470 param = all_params[name]
471
472 code = code_formatter()
473 code('%module(package="m5.internal.swig") ${name}_$0', param.file_ext)
473 code('%module(package="m5.internal") $0_${name}', param.file_ext)
474 param.swig_decl(code)
475 code.write(target[0].abspath)
476
477def createEnumStrings(target, source, env):
478 assert len(target) == 1 and len(source) == 1
479
480 name = str(source[0].get_contents())
481 obj = all_enums[name]
482
483 code = code_formatter()
484 obj.cxx_def(code)
485 code.write(target[0].abspath)
486
487def createEnumParam(target, source, env):
488 assert len(target) == 1 and len(source) == 1
489
490 name = str(source[0].get_contents())
491 obj = all_enums[name]
492
493 code = code_formatter()
494 obj.cxx_decl(code)
495 code.write(target[0].abspath)
496
497def createEnumSwig(target, source, env):
498 assert len(target) == 1 and len(source) == 1
499
500 name = str(source[0].get_contents())
501 obj = all_enums[name]
502
503 code = code_formatter()
504 code('''\
474 param.swig_decl(code)
475 code.write(target[0].abspath)
476
477def createEnumStrings(target, source, env):
478 assert len(target) == 1 and len(source) == 1
479
480 name = str(source[0].get_contents())
481 obj = all_enums[name]
482
483 code = code_formatter()
484 obj.cxx_def(code)
485 code.write(target[0].abspath)
486
487def createEnumParam(target, source, env):
488 assert len(target) == 1 and len(source) == 1
489
490 name = str(source[0].get_contents())
491 obj = all_enums[name]
492
493 code = code_formatter()
494 obj.cxx_decl(code)
495 code.write(target[0].abspath)
496
497def createEnumSwig(target, source, env):
498 assert len(target) == 1 and len(source) == 1
499
500 name = str(source[0].get_contents())
501 obj = all_enums[name]
502
503 code = code_formatter()
504 code('''\
505%module(package="m5.internal.enums") $name
505%module(package="m5.internal") enum_$name
506
507%{
508#include "enums/$name.hh"
509%}
510
511%include "enums/$name.hh"
512''')
513 code.write(target[0].abspath)
514
515# Generate all of the SimObject param struct header files
516params_hh_files = []
517for name,simobj in sorted(sim_objects.iteritems()):
518 py_source = PySource.modules[simobj.__module__]
519 extra_deps = [ py_source.tnode ]
520
521 hh_file = File('params/%s.hh' % name)
522 params_hh_files.append(hh_file)
523 env.Command(hh_file, Value(name), createSimObjectParam)
524 env.Depends(hh_file, depends + extra_deps)
525
526# Generate any parameter header files needed
527params_i_files = []
528for name,param in all_params.iteritems():
506
507%{
508#include "enums/$name.hh"
509%}
510
511%include "enums/$name.hh"
512''')
513 code.write(target[0].abspath)
514
515# Generate all of the SimObject param struct header files
516params_hh_files = []
517for name,simobj in sorted(sim_objects.iteritems()):
518 py_source = PySource.modules[simobj.__module__]
519 extra_deps = [ py_source.tnode ]
520
521 hh_file = File('params/%s.hh' % name)
522 params_hh_files.append(hh_file)
523 env.Command(hh_file, Value(name), createSimObjectParam)
524 env.Depends(hh_file, depends + extra_deps)
525
526# Generate any parameter header files needed
527params_i_files = []
528for name,param in all_params.iteritems():
529 i_file = File('params/%s_%s.i' % (name, param.file_ext))
529 i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name))
530 params_i_files.append(i_file)
531 env.Command(i_file, Value(name), createSwigParam)
532 env.Depends(i_file, depends)
530 params_i_files.append(i_file)
531 env.Command(i_file, Value(name), createSwigParam)
532 env.Depends(i_file, depends)
533 SwigSource('m5.internal.swig', i_file)
533 SwigSource('m5.internal', i_file)
534
535# Generate all enum header files
536for name,enum in sorted(all_enums.iteritems()):
537 py_source = PySource.modules[enum.__module__]
538 extra_deps = [ py_source.tnode ]
539
540 cc_file = File('enums/%s.cc' % name)
541 env.Command(cc_file, Value(name), createEnumStrings)
542 env.Depends(cc_file, depends + extra_deps)
543 Source(cc_file)
544
545 hh_file = File('enums/%s.hh' % name)
546 env.Command(hh_file, Value(name), createEnumParam)
547 env.Depends(hh_file, depends + extra_deps)
548
534
535# Generate all enum header files
536for name,enum in sorted(all_enums.iteritems()):
537 py_source = PySource.modules[enum.__module__]
538 extra_deps = [ py_source.tnode ]
539
540 cc_file = File('enums/%s.cc' % name)
541 env.Command(cc_file, Value(name), createEnumStrings)
542 env.Depends(cc_file, depends + extra_deps)
543 Source(cc_file)
544
545 hh_file = File('enums/%s.hh' % name)
546 env.Command(hh_file, Value(name), createEnumParam)
547 env.Depends(hh_file, depends + extra_deps)
548
549 i_file = File('enums/%s.i' % name)
549 i_file = File('python/m5/internal/enum_%s.i' % name)
550 env.Command(i_file, Value(name), createEnumSwig)
551 env.Depends(i_file, depends + extra_deps)
550 env.Command(i_file, Value(name), createEnumSwig)
551 env.Depends(i_file, depends + extra_deps)
552 SwigSource('m5.internal.enums', i_file)
552 SwigSource('m5.internal', i_file)
553
554def buildParam(target, source, env):
555 name = source[0].get_contents()
556 obj = sim_objects[name]
557 class_path = obj.cxx_class.split('::')
558 classname = class_path[-1]
559 namespaces = class_path[:-1]
560 params = obj._params.local.values()
561
562 code = code_formatter()
563
553
554def buildParam(target, source, env):
555 name = source[0].get_contents()
556 obj = sim_objects[name]
557 class_path = obj.cxx_class.split('::')
558 classname = class_path[-1]
559 namespaces = class_path[:-1]
560 params = obj._params.local.values()
561
562 code = code_formatter()
563
564 code('%module(package="m5.internal.params") $name')
564 code('%module(package="m5.internal") param_$name')
565 code()
566 code('%{')
567 code('#include "params/$obj.hh"')
568 for param in params:
569 param.cxx_predecls(code)
570 code('%}')
571 code()
572
573 for param in params:
574 param.swig_predecls(code)
575
576 code()
577 if obj._base:
565 code()
566 code('%{')
567 code('#include "params/$obj.hh"')
568 for param in params:
569 param.cxx_predecls(code)
570 code('%}')
571 code()
572
573 for param in params:
574 param.swig_predecls(code)
575
576 code()
577 if obj._base:
578 code('%import "params/${{obj._base}}.i"')
578 code('%import "python/m5/internal/param_${{obj._base}}.i"')
579 code()
580 obj.swig_objdecls(code)
581 code()
582
583 code('%include "params/$obj.hh"')
584
585 code.write(target[0].abspath)
586
587for name in sim_objects.iterkeys():
579 code()
580 obj.swig_objdecls(code)
581 code()
582
583 code('%include "params/$obj.hh"')
584
585 code.write(target[0].abspath)
586
587for name in sim_objects.iterkeys():
588 params_file = File('params/%s.i' % name)
588 params_file = File('python/m5/internal/param_%s.i' % name)
589 env.Command(params_file, Value(name), buildParam)
590 env.Depends(params_file, depends)
589 env.Command(params_file, Value(name), buildParam)
590 env.Depends(params_file, depends)
591 SwigSource('m5.internal.params', params_file)
591 SwigSource('m5.internal', params_file)
592
593# Generate the main swig init file
594def makeEmbeddedSwigInit(target, source, env):
595 code = code_formatter()
596 module = source[0].get_contents()
597 code('''\
598#include "sim/init.hh"
599
600extern "C" {
601 void init_${module}();
602}
603
604EmbeddedSwig embed_swig_${module}(init_${module});
605''')
606 code.write(str(target[0]))
607
608# Build all swig modules
609for swig in SwigSource.all:
610 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
611 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
612 '-o ${TARGETS[0]} $SOURCES')
613 init_file = 'python/swig/init_%s.cc' % swig.module
614 env.Command(init_file, Value(swig.module), makeEmbeddedSwigInit)
615 Source(init_file)
616 env.Depends(swig.py_source.tnode, swig.tnode)
617 env.Depends(swig.cc_source.tnode, swig.tnode)
618
619def getFlags(source_flags):
620 flagsMap = {}
621 flagsList = []
622 for s in source_flags:
623 val = eval(s.get_contents())
624 name, compound, desc = val
625 flagsList.append(val)
626 flagsMap[name] = bool(compound)
627
628 for name, compound, desc in flagsList:
629 for flag in compound:
630 if flag not in flagsMap:
631 raise AttributeError, "Trace flag %s not found" % flag
632 if flagsMap[flag]:
633 raise AttributeError, \
634 "Compound flag can't point to another compound flag"
635
636 flagsList.sort()
637 return flagsList
638
639
640# Generate traceflags.py
641def traceFlagsPy(target, source, env):
642 assert(len(target) == 1)
643 code = code_formatter()
644
645 allFlags = getFlags(source)
646
647 code('basic = [')
648 code.indent()
649 for flag, compound, desc in allFlags:
650 if not compound:
651 code("'$flag',")
652 code(']')
653 code.dedent()
654 code()
655
656 code('compound = [')
657 code.indent()
658 code("'All',")
659 for flag, compound, desc in allFlags:
660 if compound:
661 code("'$flag',")
662 code("]")
663 code.dedent()
664 code()
665
666 code("all = frozenset(basic + compound)")
667 code()
668
669 code('compoundMap = {')
670 code.indent()
671 all = tuple([flag for flag,compound,desc in allFlags if not compound])
672 code("'All' : $all,")
673 for flag, compound, desc in allFlags:
674 if compound:
675 code("'$flag' : $compound,")
676 code('}')
677 code.dedent()
678 code()
679
680 code('descriptions = {')
681 code.indent()
682 code("'All' : 'All flags',")
683 for flag, compound, desc in allFlags:
684 code("'$flag' : '$desc',")
685 code("}")
686 code.dedent()
687
688 code.write(str(target[0]))
689
690def traceFlagsCC(target, source, env):
691 assert(len(target) == 1)
692
693 allFlags = getFlags(source)
694 code = code_formatter()
695
696 # file header
697 code('''
698/*
699 * DO NOT EDIT THIS FILE! Automatically generated
700 */
701
702#include "base/traceflags.hh"
703
704using namespace Trace;
705
706const char *Trace::flagStrings[] =
707{''')
708
709 code.indent()
710 # The string array is used by SimpleEnumParam to map the strings
711 # provided by the user to enum values.
712 for flag, compound, desc in allFlags:
713 if not compound:
714 code('"$flag",')
715
716 code('"All",')
717 for flag, compound, desc in allFlags:
718 if compound:
719 code('"$flag",')
720 code.dedent()
721
722 code('''\
723};
724
725const int Trace::numFlagStrings = ${{len(allFlags) + 1}};
726
727''')
728
729 # Now define the individual compound flag arrays. There is an array
730 # for each compound flag listing the component base flags.
731 all = tuple([flag for flag,compound,desc in allFlags if not compound])
732 code('static const Flags AllMap[] = {')
733 code.indent()
734 for flag, compound, desc in allFlags:
735 if not compound:
736 code('$flag,')
737 code.dedent()
738 code('};')
739 code()
740
741 for flag, compound, desc in allFlags:
742 if not compound:
743 continue
744 code('static const Flags ${flag}Map[] = {')
745 code.indent()
746 for flag in compound:
747 code('$flag,')
748 code('(Flags)-1')
749 code.dedent()
750 code('};')
751 code()
752
753 # Finally the compoundFlags[] array maps the compound flags
754 # to their individual arrays/
755 code('const Flags *Trace::compoundFlags[] = {')
756 code.indent()
757 code('AllMap,')
758 for flag, compound, desc in allFlags:
759 if compound:
760 code('${flag}Map,')
761 # file trailer
762 code.dedent()
763 code('};')
764
765 code.write(str(target[0]))
766
767def traceFlagsHH(target, source, env):
768 assert(len(target) == 1)
769
770 allFlags = getFlags(source)
771 code = code_formatter()
772
773 # file header boilerplate
774 code('''\
775/*
776 * DO NOT EDIT THIS FILE!
777 *
778 * Automatically generated from traceflags.py
779 */
780
781#ifndef __BASE_TRACE_FLAGS_HH__
782#define __BASE_TRACE_FLAGS_HH__
783
784namespace Trace {
785
786enum Flags {''')
787
788 # Generate the enum. Base flags come first, then compound flags.
789 idx = 0
790 code.indent()
791 for flag, compound, desc in allFlags:
792 if not compound:
793 code('$flag = $idx,')
794 idx += 1
795
796 numBaseFlags = idx
797 code('NumFlags = $idx,')
798 code.dedent()
799 code()
800
801 # put a comment in here to separate base from compound flags
802 code('''
803// The remaining enum values are *not* valid indices for Trace::flags.
804// They are "compound" flags, which correspond to sets of base
805// flags, and are used by changeFlag.''')
806
807 code.indent()
808 code('All = $idx,')
809 idx += 1
810 for flag, compound, desc in allFlags:
811 if compound:
812 code('$flag = $idx,')
813 idx += 1
814
815 numCompoundFlags = idx - numBaseFlags
816 code('NumCompoundFlags = $numCompoundFlags')
817 code.dedent()
818
819 # trailer boilerplate
820 code('''\
821}; // enum Flags
822
823// Array of strings for SimpleEnumParam
824extern const char *flagStrings[];
825extern const int numFlagStrings;
826
827// Array of arraay pointers: for each compound flag, gives the list of
828// base flags to set. Inidividual flag arrays are terminated by -1.
829extern const Flags *compoundFlags[];
830
831/* namespace Trace */ }
832
833#endif // __BASE_TRACE_FLAGS_HH__
834''')
835
836 code.write(str(target[0]))
837
838flags = map(Value, trace_flags.values())
839env.Command('base/traceflags.py', flags, traceFlagsPy)
840PySource('m5', 'base/traceflags.py')
841
842env.Command('base/traceflags.hh', flags, traceFlagsHH)
843env.Command('base/traceflags.cc', flags, traceFlagsCC)
844Source('base/traceflags.cc')
845
846# Embed python files. All .py files that have been indicated by a
847# PySource() call in a SConscript need to be embedded into the M5
848# library. To do that, we compile the file to byte code, marshal the
849# byte code, compress it, and then generate a c++ file that
850# inserts the result into an array.
851def embedPyFile(target, source, env):
852 def c_str(string):
853 if string is None:
854 return "0"
855 return '"%s"' % string
856
857 '''Action function to compile a .py into a code object, marshal
858 it, compress it, and stick it into an asm file so the code appears
859 as just bytes with a label in the data section'''
860
861 src = file(str(source[0]), 'r').read()
862
863 pysource = PySource.tnodes[source[0]]
864 compiled = compile(src, pysource.abspath, 'exec')
865 marshalled = marshal.dumps(compiled)
866 compressed = zlib.compress(marshalled)
867 data = compressed
868 sym = pysource.symname
869
870 code = code_formatter()
871 code('''\
872#include "sim/init.hh"
873
874namespace {
875
876const char data_${sym}[] = {
877''')
878 code.indent()
879 step = 16
880 for i in xrange(0, len(data), step):
881 x = array.array('B', data[i:i+step])
882 code(''.join('%d,' % d for d in x))
883 code.dedent()
884
885 code('''};
886
887EmbeddedPython embedded_${sym}(
888 ${{c_str(pysource.arcname)}},
889 ${{c_str(pysource.abspath)}},
890 ${{c_str(pysource.modpath)}},
891 data_${sym},
892 ${{len(data)}},
893 ${{len(marshalled)}});
894
895/* namespace */ }
896''')
897 code.write(str(target[0]))
898
899for source in PySource.all:
900 env.Command(source.cpp, source.tnode, embedPyFile)
901 Source(source.cpp)
902
903########################################################################
904#
905# Define binaries. Each different build type (debug, opt, etc.) gets
906# a slightly different build environment.
907#
908
909# List of constructed environments to pass back to SConstruct
910envList = []
911
912date_source = Source('base/date.cc', skip_lib=True)
913
914# Function to create a new build environment as clone of current
915# environment 'env' with modified object suffix and optional stripped
916# binary. Additional keyword arguments are appended to corresponding
917# build environment vars.
918def makeEnv(label, objsfx, strip = False, **kwargs):
919 # SCons doesn't know to append a library suffix when there is a '.' in the
920 # name. Use '_' instead.
921 libname = 'm5_' + label
922 exename = 'm5.' + label
923
924 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
925 new_env.Label = label
926 new_env.Append(**kwargs)
927
928 swig_env = new_env.Clone()
929 swig_env.Append(CCFLAGS='-Werror')
930 if env['GCC']:
931 swig_env.Append(CCFLAGS='-Wno-uninitialized')
932 swig_env.Append(CCFLAGS='-Wno-sign-compare')
933 swig_env.Append(CCFLAGS='-Wno-parentheses')
934
935 werror_env = new_env.Clone()
936 werror_env.Append(CCFLAGS='-Werror')
937
938 def make_obj(source, static, extra_deps = None):
939 '''This function adds the specified source to the correct
940 build environment, and returns the corresponding SCons Object
941 nodes'''
942
943 if source.swig:
944 env = swig_env
945 elif source.Werror:
946 env = werror_env
947 else:
948 env = new_env
949
950 if static:
951 obj = env.StaticObject(source.tnode)
952 else:
953 obj = env.SharedObject(source.tnode)
954
955 if extra_deps:
956 env.Depends(obj, extra_deps)
957
958 return obj
959
960 static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)]
961 shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)]
962
963 static_date = make_obj(date_source, static=True, extra_deps=static_objs)
964 static_objs.append(static_date)
965
966 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
967 shared_objs.append(shared_date)
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 = [ make_obj(s, static=True) 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 bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ]
980 progname = exename
981 if strip:
982 progname += '.unstripped'
983
984 targets = new_env.Program(progname, bin_objs + static_objs)
985
986 if strip:
987 if sys.platform == 'sunos5':
988 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
989 else:
990 cmd = 'strip $SOURCE -o $TARGET'
991 targets = new_env.Command(exename, progname, cmd)
992
993 new_env.M5Binary = targets[0]
994 envList.append(new_env)
995
996# Debug binary
997ccflags = {}
998if env['GCC']:
999 if sys.platform == 'sunos5':
1000 ccflags['debug'] = '-gstabs+'
1001 else:
1002 ccflags['debug'] = '-ggdb3'
1003 ccflags['opt'] = '-g -O3'
1004 ccflags['fast'] = '-O3'
1005 ccflags['prof'] = '-O3 -g -pg'
1006elif env['SUNCC']:
1007 ccflags['debug'] = '-g0'
1008 ccflags['opt'] = '-g -O'
1009 ccflags['fast'] = '-fast'
1010 ccflags['prof'] = '-fast -g -pg'
1011elif env['ICC']:
1012 ccflags['debug'] = '-g -O0'
1013 ccflags['opt'] = '-g -O'
1014 ccflags['fast'] = '-fast'
1015 ccflags['prof'] = '-fast -g -pg'
1016else:
1017 print 'Unknown compiler, please fix compiler options'
1018 Exit(1)
1019
1020makeEnv('debug', '.do',
1021 CCFLAGS = Split(ccflags['debug']),
1022 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1023
1024# Optimized binary
1025makeEnv('opt', '.o',
1026 CCFLAGS = Split(ccflags['opt']),
1027 CPPDEFINES = ['TRACING_ON=1'])
1028
1029# "Fast" binary
1030makeEnv('fast', '.fo', strip = True,
1031 CCFLAGS = Split(ccflags['fast']),
1032 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1033
1034# Profiled binary
1035makeEnv('prof', '.po',
1036 CCFLAGS = Split(ccflags['prof']),
1037 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1038 LINKFLAGS = '-pg')
1039
1040Return('envList')
592
593# Generate the main swig init file
594def makeEmbeddedSwigInit(target, source, env):
595 code = code_formatter()
596 module = source[0].get_contents()
597 code('''\
598#include "sim/init.hh"
599
600extern "C" {
601 void init_${module}();
602}
603
604EmbeddedSwig embed_swig_${module}(init_${module});
605''')
606 code.write(str(target[0]))
607
608# Build all swig modules
609for swig in SwigSource.all:
610 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
611 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
612 '-o ${TARGETS[0]} $SOURCES')
613 init_file = 'python/swig/init_%s.cc' % swig.module
614 env.Command(init_file, Value(swig.module), makeEmbeddedSwigInit)
615 Source(init_file)
616 env.Depends(swig.py_source.tnode, swig.tnode)
617 env.Depends(swig.cc_source.tnode, swig.tnode)
618
619def getFlags(source_flags):
620 flagsMap = {}
621 flagsList = []
622 for s in source_flags:
623 val = eval(s.get_contents())
624 name, compound, desc = val
625 flagsList.append(val)
626 flagsMap[name] = bool(compound)
627
628 for name, compound, desc in flagsList:
629 for flag in compound:
630 if flag not in flagsMap:
631 raise AttributeError, "Trace flag %s not found" % flag
632 if flagsMap[flag]:
633 raise AttributeError, \
634 "Compound flag can't point to another compound flag"
635
636 flagsList.sort()
637 return flagsList
638
639
640# Generate traceflags.py
641def traceFlagsPy(target, source, env):
642 assert(len(target) == 1)
643 code = code_formatter()
644
645 allFlags = getFlags(source)
646
647 code('basic = [')
648 code.indent()
649 for flag, compound, desc in allFlags:
650 if not compound:
651 code("'$flag',")
652 code(']')
653 code.dedent()
654 code()
655
656 code('compound = [')
657 code.indent()
658 code("'All',")
659 for flag, compound, desc in allFlags:
660 if compound:
661 code("'$flag',")
662 code("]")
663 code.dedent()
664 code()
665
666 code("all = frozenset(basic + compound)")
667 code()
668
669 code('compoundMap = {')
670 code.indent()
671 all = tuple([flag for flag,compound,desc in allFlags if not compound])
672 code("'All' : $all,")
673 for flag, compound, desc in allFlags:
674 if compound:
675 code("'$flag' : $compound,")
676 code('}')
677 code.dedent()
678 code()
679
680 code('descriptions = {')
681 code.indent()
682 code("'All' : 'All flags',")
683 for flag, compound, desc in allFlags:
684 code("'$flag' : '$desc',")
685 code("}")
686 code.dedent()
687
688 code.write(str(target[0]))
689
690def traceFlagsCC(target, source, env):
691 assert(len(target) == 1)
692
693 allFlags = getFlags(source)
694 code = code_formatter()
695
696 # file header
697 code('''
698/*
699 * DO NOT EDIT THIS FILE! Automatically generated
700 */
701
702#include "base/traceflags.hh"
703
704using namespace Trace;
705
706const char *Trace::flagStrings[] =
707{''')
708
709 code.indent()
710 # The string array is used by SimpleEnumParam to map the strings
711 # provided by the user to enum values.
712 for flag, compound, desc in allFlags:
713 if not compound:
714 code('"$flag",')
715
716 code('"All",')
717 for flag, compound, desc in allFlags:
718 if compound:
719 code('"$flag",')
720 code.dedent()
721
722 code('''\
723};
724
725const int Trace::numFlagStrings = ${{len(allFlags) + 1}};
726
727''')
728
729 # Now define the individual compound flag arrays. There is an array
730 # for each compound flag listing the component base flags.
731 all = tuple([flag for flag,compound,desc in allFlags if not compound])
732 code('static const Flags AllMap[] = {')
733 code.indent()
734 for flag, compound, desc in allFlags:
735 if not compound:
736 code('$flag,')
737 code.dedent()
738 code('};')
739 code()
740
741 for flag, compound, desc in allFlags:
742 if not compound:
743 continue
744 code('static const Flags ${flag}Map[] = {')
745 code.indent()
746 for flag in compound:
747 code('$flag,')
748 code('(Flags)-1')
749 code.dedent()
750 code('};')
751 code()
752
753 # Finally the compoundFlags[] array maps the compound flags
754 # to their individual arrays/
755 code('const Flags *Trace::compoundFlags[] = {')
756 code.indent()
757 code('AllMap,')
758 for flag, compound, desc in allFlags:
759 if compound:
760 code('${flag}Map,')
761 # file trailer
762 code.dedent()
763 code('};')
764
765 code.write(str(target[0]))
766
767def traceFlagsHH(target, source, env):
768 assert(len(target) == 1)
769
770 allFlags = getFlags(source)
771 code = code_formatter()
772
773 # file header boilerplate
774 code('''\
775/*
776 * DO NOT EDIT THIS FILE!
777 *
778 * Automatically generated from traceflags.py
779 */
780
781#ifndef __BASE_TRACE_FLAGS_HH__
782#define __BASE_TRACE_FLAGS_HH__
783
784namespace Trace {
785
786enum Flags {''')
787
788 # Generate the enum. Base flags come first, then compound flags.
789 idx = 0
790 code.indent()
791 for flag, compound, desc in allFlags:
792 if not compound:
793 code('$flag = $idx,')
794 idx += 1
795
796 numBaseFlags = idx
797 code('NumFlags = $idx,')
798 code.dedent()
799 code()
800
801 # put a comment in here to separate base from compound flags
802 code('''
803// The remaining enum values are *not* valid indices for Trace::flags.
804// They are "compound" flags, which correspond to sets of base
805// flags, and are used by changeFlag.''')
806
807 code.indent()
808 code('All = $idx,')
809 idx += 1
810 for flag, compound, desc in allFlags:
811 if compound:
812 code('$flag = $idx,')
813 idx += 1
814
815 numCompoundFlags = idx - numBaseFlags
816 code('NumCompoundFlags = $numCompoundFlags')
817 code.dedent()
818
819 # trailer boilerplate
820 code('''\
821}; // enum Flags
822
823// Array of strings for SimpleEnumParam
824extern const char *flagStrings[];
825extern const int numFlagStrings;
826
827// Array of arraay pointers: for each compound flag, gives the list of
828// base flags to set. Inidividual flag arrays are terminated by -1.
829extern const Flags *compoundFlags[];
830
831/* namespace Trace */ }
832
833#endif // __BASE_TRACE_FLAGS_HH__
834''')
835
836 code.write(str(target[0]))
837
838flags = map(Value, trace_flags.values())
839env.Command('base/traceflags.py', flags, traceFlagsPy)
840PySource('m5', 'base/traceflags.py')
841
842env.Command('base/traceflags.hh', flags, traceFlagsHH)
843env.Command('base/traceflags.cc', flags, traceFlagsCC)
844Source('base/traceflags.cc')
845
846# Embed python files. All .py files that have been indicated by a
847# PySource() call in a SConscript need to be embedded into the M5
848# library. To do that, we compile the file to byte code, marshal the
849# byte code, compress it, and then generate a c++ file that
850# inserts the result into an array.
851def embedPyFile(target, source, env):
852 def c_str(string):
853 if string is None:
854 return "0"
855 return '"%s"' % string
856
857 '''Action function to compile a .py into a code object, marshal
858 it, compress it, and stick it into an asm file so the code appears
859 as just bytes with a label in the data section'''
860
861 src = file(str(source[0]), 'r').read()
862
863 pysource = PySource.tnodes[source[0]]
864 compiled = compile(src, pysource.abspath, 'exec')
865 marshalled = marshal.dumps(compiled)
866 compressed = zlib.compress(marshalled)
867 data = compressed
868 sym = pysource.symname
869
870 code = code_formatter()
871 code('''\
872#include "sim/init.hh"
873
874namespace {
875
876const char data_${sym}[] = {
877''')
878 code.indent()
879 step = 16
880 for i in xrange(0, len(data), step):
881 x = array.array('B', data[i:i+step])
882 code(''.join('%d,' % d for d in x))
883 code.dedent()
884
885 code('''};
886
887EmbeddedPython embedded_${sym}(
888 ${{c_str(pysource.arcname)}},
889 ${{c_str(pysource.abspath)}},
890 ${{c_str(pysource.modpath)}},
891 data_${sym},
892 ${{len(data)}},
893 ${{len(marshalled)}});
894
895/* namespace */ }
896''')
897 code.write(str(target[0]))
898
899for source in PySource.all:
900 env.Command(source.cpp, source.tnode, embedPyFile)
901 Source(source.cpp)
902
903########################################################################
904#
905# Define binaries. Each different build type (debug, opt, etc.) gets
906# a slightly different build environment.
907#
908
909# List of constructed environments to pass back to SConstruct
910envList = []
911
912date_source = Source('base/date.cc', skip_lib=True)
913
914# Function to create a new build environment as clone of current
915# environment 'env' with modified object suffix and optional stripped
916# binary. Additional keyword arguments are appended to corresponding
917# build environment vars.
918def makeEnv(label, objsfx, strip = False, **kwargs):
919 # SCons doesn't know to append a library suffix when there is a '.' in the
920 # name. Use '_' instead.
921 libname = 'm5_' + label
922 exename = 'm5.' + label
923
924 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
925 new_env.Label = label
926 new_env.Append(**kwargs)
927
928 swig_env = new_env.Clone()
929 swig_env.Append(CCFLAGS='-Werror')
930 if env['GCC']:
931 swig_env.Append(CCFLAGS='-Wno-uninitialized')
932 swig_env.Append(CCFLAGS='-Wno-sign-compare')
933 swig_env.Append(CCFLAGS='-Wno-parentheses')
934
935 werror_env = new_env.Clone()
936 werror_env.Append(CCFLAGS='-Werror')
937
938 def make_obj(source, static, extra_deps = None):
939 '''This function adds the specified source to the correct
940 build environment, and returns the corresponding SCons Object
941 nodes'''
942
943 if source.swig:
944 env = swig_env
945 elif source.Werror:
946 env = werror_env
947 else:
948 env = new_env
949
950 if static:
951 obj = env.StaticObject(source.tnode)
952 else:
953 obj = env.SharedObject(source.tnode)
954
955 if extra_deps:
956 env.Depends(obj, extra_deps)
957
958 return obj
959
960 static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)]
961 shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)]
962
963 static_date = make_obj(date_source, static=True, extra_deps=static_objs)
964 static_objs.append(static_date)
965
966 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
967 shared_objs.append(shared_date)
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 = [ make_obj(s, static=True) 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 bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ]
980 progname = exename
981 if strip:
982 progname += '.unstripped'
983
984 targets = new_env.Program(progname, bin_objs + static_objs)
985
986 if strip:
987 if sys.platform == 'sunos5':
988 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
989 else:
990 cmd = 'strip $SOURCE -o $TARGET'
991 targets = new_env.Command(exename, progname, cmd)
992
993 new_env.M5Binary = targets[0]
994 envList.append(new_env)
995
996# Debug binary
997ccflags = {}
998if env['GCC']:
999 if sys.platform == 'sunos5':
1000 ccflags['debug'] = '-gstabs+'
1001 else:
1002 ccflags['debug'] = '-ggdb3'
1003 ccflags['opt'] = '-g -O3'
1004 ccflags['fast'] = '-O3'
1005 ccflags['prof'] = '-O3 -g -pg'
1006elif env['SUNCC']:
1007 ccflags['debug'] = '-g0'
1008 ccflags['opt'] = '-g -O'
1009 ccflags['fast'] = '-fast'
1010 ccflags['prof'] = '-fast -g -pg'
1011elif env['ICC']:
1012 ccflags['debug'] = '-g -O0'
1013 ccflags['opt'] = '-g -O'
1014 ccflags['fast'] = '-fast'
1015 ccflags['prof'] = '-fast -g -pg'
1016else:
1017 print 'Unknown compiler, please fix compiler options'
1018 Exit(1)
1019
1020makeEnv('debug', '.do',
1021 CCFLAGS = Split(ccflags['debug']),
1022 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1023
1024# Optimized binary
1025makeEnv('opt', '.o',
1026 CCFLAGS = Split(ccflags['opt']),
1027 CPPDEFINES = ['TRACING_ON=1'])
1028
1029# "Fast" binary
1030makeEnv('fast', '.fo', strip = True,
1031 CCFLAGS = Split(ccflags['fast']),
1032 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1033
1034# Profiled binary
1035makeEnv('prof', '.po',
1036 CCFLAGS = Split(ccflags['prof']),
1037 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1038 LINKFLAGS = '-pg')
1039
1040Return('envList')