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