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