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