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