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