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