SConscript revision 7768
110388SAndreas.Sandberg@ARM.com# -*- mode:python -*-
210388SAndreas.Sandberg@ARM.com
311930Sandreas.sandberg@arm.com# Copyright (c) 2004-2005 The Regents of The University of Michigan
410388SAndreas.Sandberg@ARM.com# All rights reserved.
510388SAndreas.Sandberg@ARM.com#
610388SAndreas.Sandberg@ARM.com# Redistribution and use in source and binary forms, with or without
710388SAndreas.Sandberg@ARM.com# modification, are permitted provided that the following conditions are
810388SAndreas.Sandberg@ARM.com# met: redistributions of source code must retain the above copyright
910388SAndreas.Sandberg@ARM.com# notice, this list of conditions and the following disclaimer;
1010388SAndreas.Sandberg@ARM.com# redistributions in binary form must reproduce the above copyright
1110388SAndreas.Sandberg@ARM.com# notice, this list of conditions and the following disclaimer in the
1210388SAndreas.Sandberg@ARM.com# documentation and/or other materials provided with the distribution;
1310388SAndreas.Sandberg@ARM.com# neither the name of the copyright holders nor the names of its
1410388SAndreas.Sandberg@ARM.com# contributors may be used to endorse or promote products derived from
1510388SAndreas.Sandberg@ARM.com# this software without specific prior written permission.
1610388SAndreas.Sandberg@ARM.com#
1710388SAndreas.Sandberg@ARM.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1810388SAndreas.Sandberg@ARM.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1910388SAndreas.Sandberg@ARM.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2010388SAndreas.Sandberg@ARM.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2110388SAndreas.Sandberg@ARM.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2210388SAndreas.Sandberg@ARM.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2310388SAndreas.Sandberg@ARM.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2410388SAndreas.Sandberg@ARM.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2510388SAndreas.Sandberg@ARM.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2610388SAndreas.Sandberg@ARM.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2710388SAndreas.Sandberg@ARM.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2810388SAndreas.Sandberg@ARM.com#
2910388SAndreas.Sandberg@ARM.com# Authors: Nathan Binkert
3010388SAndreas.Sandberg@ARM.com
3110388SAndreas.Sandberg@ARM.comimport array
3210388SAndreas.Sandberg@ARM.comimport bisect
3310388SAndreas.Sandberg@ARM.comimport imp
3410388SAndreas.Sandberg@ARM.comimport marshal
3510388SAndreas.Sandberg@ARM.comimport os
3610388SAndreas.Sandberg@ARM.comimport re
3710388SAndreas.Sandberg@ARM.comimport sys
3810388SAndreas.Sandberg@ARM.comimport zlib
3910388SAndreas.Sandberg@ARM.com
4010388SAndreas.Sandberg@ARM.comfrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath
4110388SAndreas.Sandberg@ARM.com
4210388SAndreas.Sandberg@ARM.comimport SCons
4310388SAndreas.Sandberg@ARM.com
4410388SAndreas.Sandberg@ARM.com# This file defines how to build a particular configuration of M5
4510388SAndreas.Sandberg@ARM.com# based on variable settings in the 'env' build environment.
4610389SAndreas.Sandberg@ARM.com
4710390SAndreas.Sandberg@ARM.comImport('*')
4810391SAndreas.Sandberg@ARM.com
4910388SAndreas.Sandberg@ARM.com# Children need to see the environment
5010388SAndreas.Sandberg@ARM.comExport('env')
5110388SAndreas.Sandberg@ARM.com
5210389SAndreas.Sandberg@ARM.combuild_env = [(opt, env[opt]) for opt in export_vars]
5310390SAndreas.Sandberg@ARM.com
5410391SAndreas.Sandberg@ARM.comfrom m5.util import code_formatter
5510388SAndreas.Sandberg@ARM.com
5610388SAndreas.Sandberg@ARM.com########################################################################
5711930Sandreas.sandberg@arm.com# Code for adding source files of various types
5810389SAndreas.Sandberg@ARM.com#
5910390SAndreas.Sandberg@ARM.comclass SourceMeta(type):
6010391SAndreas.Sandberg@ARM.com    def __init__(cls, name, bases, dict):
6110391SAndreas.Sandberg@ARM.com        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