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