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