SConscript revision 6656
12623SN/A# -*- mode:python -*-
22623SN/A
32623SN/A# Copyright (c) 2004-2005 The Regents of The University of Michigan
42623SN/A# All rights reserved.
52623SN/A#
62623SN/A# Redistribution and use in source and binary forms, with or without
72623SN/A# modification, are permitted provided that the following conditions are
82623SN/A# met: redistributions of source code must retain the above copyright
92623SN/A# notice, this list of conditions and the following disclaimer;
102623SN/A# redistributions in binary form must reproduce the above copyright
112623SN/A# notice, this list of conditions and the following disclaimer in the
122623SN/A# documentation and/or other materials provided with the distribution;
132623SN/A# neither the name of the copyright holders nor the names of its
142623SN/A# contributors may be used to endorse or promote products derived from
152623SN/A# this software without specific prior written permission.
162623SN/A#
172623SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182623SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192623SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
202623SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
212623SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
222623SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
232623SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242623SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252623SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262623SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272665Ssaidi@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282665Ssaidi@eecs.umich.edu#
292623SN/A# Authors: Nathan Binkert
302623SN/A
313170Sstever@eecs.umich.eduimport array
322623SN/Aimport bisect
332623SN/Aimport imp
342623SN/Aimport marshal
353348Sbinkertn@umich.eduimport os
363348Sbinkertn@umich.eduimport re
372623SN/Aimport sys
382901Ssaidi@eecs.umich.eduimport zlib
392623SN/A
402623SN/Afrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath
412623SN/A
422623SN/Aimport SCons
432623SN/A
442623SN/A# This file defines how to build a particular configuration of M5
452623SN/A# based on variable settings in the 'env' build environment.
462623SN/A
472623SN/AImport('*')
482623SN/A
492623SN/A# Children need to see the environment
502623SN/AExport('env')
512623SN/A
522623SN/Abuild_env = [(opt, env[opt]) for opt in export_vars]
532623SN/A
542623SN/A########################################################################
552623SN/A# Code for adding source files of various types
562623SN/A#
572623SN/Aclass SourceMeta(type):
582623SN/A    def __init__(cls, name, bases, dict):
592623SN/A        super(SourceMeta, cls).__init__(name, bases, dict)
602623SN/A        cls.all = []
612856Srdreslin@umich.edu        
622856Srdreslin@umich.edu    def get(cls, **kwargs):
632856Srdreslin@umich.edu        for src in cls.all:
642856Srdreslin@umich.edu            for attr,value in kwargs.iteritems():
652856Srdreslin@umich.edu                if getattr(src, attr) != value:
662856Srdreslin@umich.edu                    break
672856Srdreslin@umich.edu            else:
682856Srdreslin@umich.edu                yield src
692856Srdreslin@umich.edu
702856Srdreslin@umich.educlass SourceFile(object):
712623SN/A    __metaclass__ = SourceMeta
722623SN/A    def __init__(self, source):
732623SN/A        tnode = source
742623SN/A        if not isinstance(source, SCons.Node.FS.File):
752623SN/A            tnode = File(source)
762856Srdreslin@umich.edu
772856Srdreslin@umich.edu        self.tnode = tnode
782856Srdreslin@umich.edu        self.snode = tnode.srcnode()
792623SN/A        self.filename = str(tnode)
802856Srdreslin@umich.edu        self.dirname = dirname(self.filename)
812856Srdreslin@umich.edu        self.basename = basename(self.filename)
822856Srdreslin@umich.edu        index = self.basename.rfind('.')
832623SN/A        if index <= 0:
842623SN/A            # dot files aren't extensions
852623SN/A            self.extname = self.basename, None
862680Sktlim@umich.edu        else:
872680Sktlim@umich.edu            self.extname = self.basename[:index], self.basename[index+1:]
882623SN/A
892623SN/A        for base in type(self).__mro__:
902680Sktlim@umich.edu            if issubclass(base, SourceFile):
912623SN/A                bisect.insort_right(base.all, self)       
922623SN/A
932623SN/A    def __lt__(self, other): return self.filename < other.filename
942623SN/A    def __le__(self, other): return self.filename <= other.filename
952623SN/A    def __gt__(self, other): return self.filename > other.filename
963349Sbinkertn@umich.edu    def __ge__(self, other): return self.filename >= other.filename
972623SN/A    def __eq__(self, other): return self.filename == other.filename
983184Srdreslin@umich.edu    def __ne__(self, other): return self.filename != other.filename
992623SN/A        
1002623SN/Aclass Source(SourceFile):
1012623SN/A    '''Add a c/c++ source file to the build'''
1022623SN/A    def __init__(self, source, Werror=True, swig=False, bin_only=False,
1033349Sbinkertn@umich.edu                 skip_lib=False):
1042623SN/A        super(Source, self).__init__(source)
1053310Srdreslin@umich.edu
1062623SN/A        self.Werror = Werror
1072623SN/A        self.swig = swig
1082623SN/A        self.bin_only = bin_only
1092623SN/A        self.skip_lib = bin_only or skip_lib
1103349Sbinkertn@umich.edu
1112623SN/Aclass PySource(SourceFile):
1123184Srdreslin@umich.edu    '''Add a python source file to the named package'''
1133184Srdreslin@umich.edu    invalid_sym_char = re.compile('[^A-z0-9_]')
1142623SN/A    modules = {}
1152623SN/A    tnodes = {}
1162623SN/A    symnames = {}
1172623SN/A    
1182623SN/A    def __init__(self, package, source):
1192626SN/A        super(PySource, self).__init__(source)
1202626SN/A
1212626SN/A        modname,ext = self.extname
1222623SN/A        assert ext == 'py'
1232623SN/A
1242623SN/A        if package:
1252657Ssaidi@eecs.umich.edu            path = package.split('.')
1262623SN/A        else:
1272623SN/A            path = []
1282623SN/A
1292623SN/A        modpath = path[:]
1302623SN/A        if modname != '__init__':
1312623SN/A            modpath += [ modname ]
1322623SN/A        modpath = '.'.join(modpath)
1332623SN/A
1342623SN/A        arcpath = path + [ self.basename ]
1352640Sstever@eecs.umich.edu        debugname = self.snode.abspath
1362623SN/A        if not exists(debugname):
1372623SN/A            debugname = self.tnode.abspath
1382623SN/A
1392663Sstever@eecs.umich.edu        self.package = package
1403170Sstever@eecs.umich.edu        self.modname = modname
1412641Sstever@eecs.umich.edu        self.modpath = modpath
1422623SN/A        self.arcname = joinpath(*arcpath)
1432623SN/A        self.debugname = debugname
1442663Sstever@eecs.umich.edu        self.compiled = File(self.filename + 'c')
1453170Sstever@eecs.umich.edu        self.assembly = File(self.filename + '.s')
1462641Sstever@eecs.umich.edu        self.symname = "PyEMB_" + PySource.invalid_sym_char.sub('_', modpath)
1472641Sstever@eecs.umich.edu
1482623SN/A        PySource.modules[modpath] = self
1492623SN/A        PySource.tnodes[self.tnode] = self
1502663Sstever@eecs.umich.edu        PySource.symnames[self.symname] = self
1513170Sstever@eecs.umich.edu
1522641Sstever@eecs.umich.educlass SimObject(PySource):
1532641Sstever@eecs.umich.edu    '''Add a SimObject python file as a python source object and add
1542623SN/A    it to a list of sim object modules'''
1552623SN/A
1562623SN/A    fixed = False
1572623SN/A    modnames = []
1582623SN/A
1592623SN/A    def __init__(self, source):
1602623SN/A        super(SimObject, self).__init__('m5.objects', source)
1612623SN/A        if self.fixed:
1622623SN/A            raise AttributeError, "Too late to call SimObject now."
1632623SN/A
1642915Sktlim@umich.edu        bisect.insort_right(SimObject.modnames, self.modname)
1652915Sktlim@umich.edu
1663177Shsul@eecs.umich.educlass SwigSource(SourceFile):
1673177Shsul@eecs.umich.edu    '''Add a swig file to build'''
1683145Shsul@eecs.umich.edu
1692623SN/A    def __init__(self, package, source):
1702623SN/A        super(SwigSource, self).__init__(source)
1712623SN/A
1722623SN/A        modname,ext = self.extname
1732623SN/A        assert ext == 'i'
1742623SN/A
1752623SN/A        self.module = modname
1762915Sktlim@umich.edu        cc_file = joinpath(self.dirname, modname + '_wrap.cc')
1772915Sktlim@umich.edu        py_file = joinpath(self.dirname, modname + '.py')
1783177Shsul@eecs.umich.edu
1793145Shsul@eecs.umich.edu        self.cc_source = Source(cc_file, swig=True)
1802915Sktlim@umich.edu        self.py_source = PySource(package, py_file)
1812915Sktlim@umich.edu
1822915Sktlim@umich.eduunit_tests = []
1832915Sktlim@umich.edudef UnitTest(target, sources):
1842915Sktlim@umich.edu    if not isinstance(sources, (list, tuple)):
1852915Sktlim@umich.edu        sources = [ sources ]
1863324Shsul@eecs.umich.edu
1873201Shsul@eecs.umich.edu    sources = [ Source(src, skip_lib=True) for src in sources ]
1883324Shsul@eecs.umich.edu    unit_tests.append((target, sources))
1893324Shsul@eecs.umich.edu
1903324Shsul@eecs.umich.edu# Children should have access
1913431Sgblack@eecs.umich.eduExport('Source')
1923431Sgblack@eecs.umich.eduExport('PySource')
1933431Sgblack@eecs.umich.eduExport('SimObject')
1943431Sgblack@eecs.umich.eduExport('SwigSource')
1953431Sgblack@eecs.umich.eduExport('UnitTest')
1963324Shsul@eecs.umich.edu
1972915Sktlim@umich.edu########################################################################
1982623SN/A#
1992623SN/A# Trace Flags
2002623SN/A#
2012798Sktlim@umich.edutrace_flags = {}
2022623SN/Adef TraceFlag(name, desc=None):
2032798Sktlim@umich.edu    if name in trace_flags:
2042798Sktlim@umich.edu        raise AttributeError, "Flag %s already specified" % name
2052623SN/A    trace_flags[name] = (name, (), desc)
2062798Sktlim@umich.edu
2072623SN/Adef CompoundFlag(name, flags, desc=None):
2082623SN/A    if name in trace_flags:
2092623SN/A        raise AttributeError, "Flag %s already specified" % name
2102623SN/A
2112623SN/A    compound = tuple(flags)
2122623SN/A    trace_flags[name] = (name, compound, desc)
2132623SN/A
2142623SN/AExport('TraceFlag')
2152623SN/AExport('CompoundFlag')
2162623SN/A
2172680Sktlim@umich.edu########################################################################
2182623SN/A#
2192680Sktlim@umich.edu# Set some compiler variables
2202680Sktlim@umich.edu#
2212680Sktlim@umich.edu
2222623SN/A# Include file paths are rooted in this directory.  SCons will
2233431Sgblack@eecs.umich.edu# automatically expand '.' to refer to both the source directory and
2243431Sgblack@eecs.umich.edu# the corresponding build directory to pick up generated include
2253431Sgblack@eecs.umich.edu# files.
2262623SN/Aenv.Append(CPPPATH=Dir('.'))
2272623SN/A
2282623SN/Afor extra_dir in extras_dir_list:
2292623SN/A    env.Append(CPPPATH=Dir(extra_dir))
2302623SN/A
2312623SN/A# Add a flag defining what THE_ISA should be for all compilation
2322623SN/Aenv.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
2332623SN/A
2342623SN/A# Workaround for bug in SCons version > 0.97d20071212
2352623SN/A# Scons bug id: 2006 M5 Bug id: 308 
2362683Sktlim@umich.edufor root, dirs, files in os.walk(base_dir, topdown=True):
2372623SN/A    Dir(root[len(base_dir) + 1:])
2382623SN/A
2392623SN/A########################################################################
2402623SN/A#
2412623SN/A# Walk the tree and execute all SConscripts in subdirectories
2423430Sgblack@eecs.umich.edu#
2433432Sgblack@eecs.umich.edu
2443430Sgblack@eecs.umich.eduhere = Dir('.').srcnode().abspath
2453431Sgblack@eecs.umich.edufor root, dirs, files in os.walk(base_dir, topdown=True):
2462623SN/A    if root == here:
2472623SN/A        # we don't want to recurse back into this SConscript
2482623SN/A        continue
2492623SN/A
2502623SN/A    if 'SConscript' in files:
2512623SN/A        build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
2522623SN/A        SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
2532623SN/A
2542683Sktlim@umich.edufor extra_dir in extras_dir_list:
2552623SN/A    prefix_len = len(dirname(extra_dir)) + 1
2562623SN/A    for root, dirs, files in os.walk(extra_dir, topdown=True):
2572626SN/A        if 'SConscript' in files:
2582626SN/A            build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
2592626SN/A            SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
2602626SN/A
2612626SN/Afor opt in export_vars:
2622623SN/A    env.ConfigFile(opt)
2632623SN/A
2642623SN/A########################################################################
2652623SN/A#
2662623SN/A# Prevent any SimObjects from being added after this point, they
2672623SN/A# should all have been added in the SConscripts above
2682623SN/A#
2692623SN/ASimObject.fixed = True
2702623SN/A
2712623SN/Aclass DictImporter(object):
2723169Sstever@eecs.umich.edu    '''This importer takes a dictionary of arbitrary module names that
2733169Sstever@eecs.umich.edu    map to arbitrary filenames.'''
2743349Sbinkertn@umich.edu    def __init__(self, modules):
2753169Sstever@eecs.umich.edu        self.modules = modules
2763169Sstever@eecs.umich.edu        self.installed = set()
2772623SN/A
2782623SN/A    def __del__(self):
2792623SN/A        self.unload()
2802623SN/A
2812623SN/A    def unload(self):
2822623SN/A        import sys
2833169Sstever@eecs.umich.edu        for module in self.installed:
2842623SN/A            del sys.modules[module]
2852623SN/A        self.installed = set()
2862623SN/A
2873169Sstever@eecs.umich.edu    def find_module(self, fullname, path):
2882623SN/A        if fullname == 'm5.defines':
2893169Sstever@eecs.umich.edu            return self
2902623SN/A
2912623SN/A        if fullname == 'm5.objects':
2923169Sstever@eecs.umich.edu            return self
2933169Sstever@eecs.umich.edu
2943170Sstever@eecs.umich.edu        if fullname.startswith('m5.internal'):
2953170Sstever@eecs.umich.edu            return None
2963170Sstever@eecs.umich.edu
2973170Sstever@eecs.umich.edu        source = self.modules.get(fullname, None)
2982623SN/A        if source is not None and fullname.startswith('m5.objects'):
2992623SN/A            return self
3002623SN/A
3013172Sstever@eecs.umich.edu        return None
3022623SN/A
3032623SN/A    def load_module(self, fullname):
3042623SN/A        mod = imp.new_module(fullname)
3052623SN/A        sys.modules[fullname] = mod
3062623SN/A        self.installed.add(fullname)
3072623SN/A
3082623SN/A        mod.__loader__ = self
3092623SN/A        if fullname == 'm5.objects':
3102623SN/A            mod.__path__ = fullname.split('.')
3112623SN/A            return mod
3122623SN/A
3132623SN/A        if fullname == 'm5.defines':
3142623SN/A            mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
3152623SN/A            return mod
3162623SN/A
3172623SN/A        source = self.modules[fullname]
3182623SN/A        if source.modname == '__init__':
3192623SN/A            mod.__path__ = source.modpath
3202623SN/A        mod.__file__ = source.snode.abspath
3212623SN/A
3222623SN/A        exec file(source.snode.abspath, 'r') in mod.__dict__
3232623SN/A
3242623SN/A        return mod
3252623SN/A
3262623SN/Aimport m5.SimObject
3272623SN/Aimport m5.params
3282623SN/A
3292623SN/Am5.SimObject.clear()
3302623SN/Am5.params.clear()
3312623SN/A
3322623SN/A# install the python importer so we can grab stuff from the source
3332623SN/A# tree itself.  We can't have SimObjects added after this point or
3342623SN/A# else we won't know about them for the rest of the stuff.
3352623SN/Aimporter = DictImporter(PySource.modules)
3362623SN/Asys.meta_path[0:0] = [ importer ]
3372623SN/A
3382623SN/A# import all sim objects so we can populate the all_objects list
3392623SN/A# make sure that we're working with a list, then let's sort it
3402623SN/Afor modname in SimObject.modnames:
3412623SN/A    exec('from m5.objects import %s' % modname)
3422623SN/A
3432623SN/A# we need to unload all of the currently imported modules so that they
3442623SN/A# will be re-imported the next time the sconscript is run
3452623SN/Aimporter.unload()
3462623SN/Asys.meta_path.remove(importer)
3472623SN/A
3482623SN/Asim_objects = m5.SimObject.allClasses
3492623SN/Aall_enums = m5.params.allEnums
3502623SN/A
3512623SN/Aall_params = {}
3522623SN/Afor name,obj in sorted(sim_objects.iteritems()):
3532623SN/A    for param in obj._params.local.values():
3543169Sstever@eecs.umich.edu        # load the ptype attribute now because it depends on the
3553169Sstever@eecs.umich.edu        # current version of SimObject.allClasses, but when scons
3563349Sbinkertn@umich.edu        # actually uses the value, all versions of
3573169Sstever@eecs.umich.edu        # SimObject.allClasses will have been loaded
3583169Sstever@eecs.umich.edu        param.ptype
3592623SN/A
3602623SN/A        if not hasattr(param, 'swig_decl'):
3612623SN/A            continue
3622623SN/A        pname = param.ptype_str
3632623SN/A        if pname not in all_params:
3642623SN/A            all_params[pname] = param
3653169Sstever@eecs.umich.edu
3662623SN/A########################################################################
3672623SN/A#
3682623SN/A# calculate extra dependencies
3693170Sstever@eecs.umich.edu#
3702623SN/Amodule_depends = ["m5", "m5.SimObject", "m5.params"]
3713170Sstever@eecs.umich.edudepends = [ PySource.modules[dep].tnode for dep in module_depends ]
3723170Sstever@eecs.umich.edu
3733170Sstever@eecs.umich.edu########################################################################
3742623SN/A#
3753170Sstever@eecs.umich.edu# Commands for the basic automatically generated python files
3763170Sstever@eecs.umich.edu#
3773170Sstever@eecs.umich.edu
3783170Sstever@eecs.umich.edu# Generate Python file containing a dict specifying the current
3792631SN/A# buildEnv flags.
3803170Sstever@eecs.umich.edudef makeDefinesPyFile(target, source, env):
3813170Sstever@eecs.umich.edu    build_env, hg_info = [ x.get_contents() for x in source ]
3823170Sstever@eecs.umich.edu
3833170Sstever@eecs.umich.edu    code = m5.util.code_formatter()
3843170Sstever@eecs.umich.edu    code("""
3853170Sstever@eecs.umich.eduimport m5.internal
3863170Sstever@eecs.umich.eduimport m5.util
3873170Sstever@eecs.umich.edu
3883170Sstever@eecs.umich.edubuildEnv = m5.util.SmartDict($build_env)
3893170Sstever@eecs.umich.eduhgRev = '$hg_info'
3903170Sstever@eecs.umich.edu
3913170Sstever@eecs.umich.educompileDate = m5.internal.core.compileDate
3923170Sstever@eecs.umich.edufor k,v in m5.internal.core.__dict__.iteritems():
3933170Sstever@eecs.umich.edu    if k.startswith('flag_'):
3943170Sstever@eecs.umich.edu        setattr(buildEnv, k[5:], v)
3952631SN/A""")
3962623SN/A    code.write(str(target[0]))
3972623SN/A
3982623SN/Adefines_info = [ Value(build_env), Value(env['HG_INFO']) ]
3993172Sstever@eecs.umich.edu# Generate a file with all of the compile options in it
4002623SN/Aenv.Command('python/m5/defines.py', defines_info, makeDefinesPyFile)
4012623SN/APySource('m5', 'python/m5/defines.py')
4022623SN/A
4032623SN/A# Generate python file containing info about the M5 source code
4042623SN/Adef makeInfoPyFile(target, source, env):
4052623SN/A    f = file(str(target[0]), 'w')
4062623SN/A    for src in source:
4072623SN/A        data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
4082623SN/A        print >>f, "%s = %s" % (src, repr(data))
4092623SN/A    f.close()
4102623SN/A
4112623SN/A# Generate a file that wraps the basic top level files
4122623SN/Aenv.Command('python/m5/info.py',
4132623SN/A            [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
4142623SN/A            makeInfoPyFile)
4152623SN/APySource('m5', 'python/m5/info.py')
4162623SN/A
4172623SN/A# Generate the __init__.py file for m5.objects
4182623SN/Adef makeObjectsInitFile(target, source, env):
4192623SN/A    f = file(str(target[0]), 'w')
4202623SN/A    print >>f, 'from params import *'
4212623SN/A    print >>f, 'from m5.SimObject import *'
4222623SN/A    for module in source:
4232623SN/A        print >>f, 'from %s import *' % module.get_contents()
4242623SN/A    f.close()
4252623SN/A
4262623SN/A# Generate an __init__.py file for the objects package
4272623SN/Aenv.Command('python/m5/objects/__init__.py',
4282623SN/A            map(Value, SimObject.modnames),
4292623SN/A            makeObjectsInitFile)
4302623SN/APySource('m5.objects', 'python/m5/objects/__init__.py')
4312623SN/A
4322623SN/A########################################################################
4332623SN/A#
4342623SN/A# Create all of the SimObject param headers and enum headers
4352623SN/A#
4362623SN/A
4372623SN/Adef createSimObjectParam(target, source, env):
4382623SN/A    assert len(target) == 1 and len(source) == 1
4392623SN/A
4402623SN/A    hh_file = file(target[0].abspath, 'w')
4412623SN/A    name = str(source[0].get_contents())
4422623SN/A    obj = sim_objects[name]
4432623SN/A
4442623SN/A    print >>hh_file, obj.cxx_decl()
4452623SN/A    hh_file.close()
4462623SN/A
4472623SN/Adef createSwigParam(target, source, env):
4482623SN/A    assert len(target) == 1 and len(source) == 1
4492623SN/A
4502623SN/A    i_file = file(target[0].abspath, 'w')
4512623SN/A    name = str(source[0].get_contents())
4522623SN/A    param = all_params[name]
4532623SN/A
4542623SN/A    for line in param.swig_decl():
4552623SN/A        print >>i_file, line
4562623SN/A    i_file.close()
4572623SN/A
4582623SN/Adef createEnumStrings(target, source, env):
4592623SN/A    assert len(target) == 1 and len(source) == 1
4602623SN/A
4612623SN/A    cc_file = file(target[0].abspath, 'w')
4623387Sgblack@eecs.umich.edu    name = str(source[0].get_contents())
4633387Sgblack@eecs.umich.edu    obj = all_enums[name]
4642626SN/A
4652662Sstever@eecs.umich.edu    print >>cc_file, obj.cxx_def()
4662623SN/A    cc_file.close()
4672623SN/A
4682662Sstever@eecs.umich.edudef createEnumParam(target, source, env):
4692662Sstever@eecs.umich.edu    assert len(target) == 1 and len(source) == 1
4702662Sstever@eecs.umich.edu
4712623SN/A    hh_file = file(target[0].abspath, 'w')
4722623SN/A    name = str(source[0].get_contents())
4732623SN/A    obj = all_enums[name]
4742623SN/A
4752623SN/A    print >>hh_file, obj.cxx_decl()
4762623SN/A    hh_file.close()
4772623SN/A
4782623SN/A# Generate all of the SimObject param struct header files
4792623SN/Aparams_hh_files = []
4802662Sstever@eecs.umich.edufor name,simobj in sorted(sim_objects.iteritems()):
4812623SN/A    py_source = PySource.modules[simobj.__module__]
4822662Sstever@eecs.umich.edu    extra_deps = [ py_source.tnode ]
4832803Ssaidi@eecs.umich.edu
4842803Ssaidi@eecs.umich.edu    hh_file = File('params/%s.hh' % name)
4852803Ssaidi@eecs.umich.edu    params_hh_files.append(hh_file)
4862803Ssaidi@eecs.umich.edu    env.Command(hh_file, Value(name), createSimObjectParam)
4872803Ssaidi@eecs.umich.edu    env.Depends(hh_file, depends + extra_deps)
4882623SN/A
4892623SN/A# Generate any parameter header files needed
4902623SN/Aparams_i_files = []
4912623SN/Afor name,param in all_params.iteritems():
4922623SN/A    i_file = File('params/%s_%s.i' % (name, param.file_ext))
4932623SN/A    params_i_files.append(i_file)
4942623SN/A    env.Command(i_file, Value(name), createSwigParam)
4952626SN/A    env.Depends(i_file, depends)
4962626SN/A
4972623SN/A# Generate all enum header files
4982623SN/Afor name,enum in sorted(all_enums.iteritems()):
4992623SN/A    py_source = PySource.modules[enum.__module__]
5002623SN/A    extra_deps = [ py_source.tnode ]
5012623SN/A
5022623SN/A    cc_file = File('enums/%s.cc' % name)
5032623SN/A    env.Command(cc_file, Value(name), createEnumStrings)
5042623SN/A    env.Depends(cc_file, depends + extra_deps)
5052623SN/A    Source(cc_file)
5062623SN/A
5072623SN/A    hh_file = File('enums/%s.hh' % name)
5082623SN/A    env.Command(hh_file, Value(name), createEnumParam)
5092623SN/A    env.Depends(hh_file, depends + extra_deps)
5103119Sktlim@umich.edu
5112623SN/A# Build the big monolithic swigged params module (wraps all SimObject
5122901Ssaidi@eecs.umich.edu# param structs and enum structs)
5133170Sstever@eecs.umich.edudef buildParams(target, source, env):
5142623SN/A    names = [ s.get_contents() for s in source ]
5152623SN/A    objs = [ sim_objects[name] for name in names ]
5162623SN/A    out = file(target[0].abspath, 'w')
5172623SN/A
5182623SN/A    ordered_objs = []
5192623SN/A    obj_seen = set()
5202623SN/A    def order_obj(obj):
5212623SN/A        name = str(obj)
5222623SN/A        if name in obj_seen:
5232623SN/A            return
5242623SN/A
5252623SN/A        obj_seen.add(name)
5262623SN/A        if str(obj) != 'SimObject':
5272623SN/A            order_obj(obj.__bases__[0])
5282623SN/A
5292623SN/A        ordered_objs.append(obj)
5302623SN/A
5312623SN/A    for obj in objs:
5322623SN/A        order_obj(obj)
5332623SN/A
5342623SN/A    enums = set()
5352623SN/A    predecls = []
5362623SN/A    pd_seen = set()
5372623SN/A
5382623SN/A    def add_pds(*pds):
5392623SN/A        for pd in pds:
5402623SN/A            if pd not in pd_seen:
5412623SN/A                predecls.append(pd)
5422623SN/A                pd_seen.add(pd)
5433119Sktlim@umich.edu
5442623SN/A    for obj in ordered_objs:
5452901Ssaidi@eecs.umich.edu        params = obj._params.local.values()
5463170Sstever@eecs.umich.edu        for param in params:
5472623SN/A            ptype = param.ptype
5482623SN/A            if issubclass(ptype, m5.params.Enum):
5492623SN/A                if ptype not in enums:
5502623SN/A                    enums.add(ptype)
5512623SN/A            pds = param.swig_predecls()
5522623SN/A            if isinstance(pds, (list, tuple)):
5532623SN/A                add_pds(*pds)
5542623SN/A            else:
5552623SN/A                add_pds(pds)
5562623SN/A
5572623SN/A    print >>out, '%module params'
5582623SN/A
5592623SN/A    print >>out, '%{'
5602623SN/A    for obj in ordered_objs:
5612623SN/A        print >>out, '#include "params/%s.hh"' % obj
5622623SN/A    print >>out, '%}'
5632623SN/A
5642623SN/A    for pd in predecls:
5652623SN/A        print >>out, pd
5662623SN/A
5672623SN/A    enums = list(enums)
5682623SN/A    enums.sort()
5692623SN/A    for enum in enums:
5702623SN/A        print >>out, '%%include "enums/%s.hh"' % enum.__name__
5712623SN/A    print >>out
5722623SN/A
5732623SN/A    for obj in ordered_objs:
5742623SN/A        if obj.swig_objdecls:
5753119Sktlim@umich.edu            for decl in obj.swig_objdecls:
5762623SN/A                print >>out, decl
5772623SN/A            continue
5782623SN/A
5792623SN/A        class_path = obj.cxx_class.split('::')
5802623SN/A        classname = class_path[-1]
5812623SN/A        namespaces = class_path[:-1]
5822623SN/A        namespaces.reverse()
5832901Ssaidi@eecs.umich.edu
5843170Sstever@eecs.umich.edu        code = ''
5852623SN/A
5862623SN/A        if namespaces:
5872623SN/A            code += '// avoid name conflicts\n'
5882623SN/A            sep_string = '_COLONS_'
5892623SN/A            flat_name = sep_string.join(class_path)
5902623SN/A            code += '%%rename(%s) %s;\n' % (flat_name, classname)
5912623SN/A
5922623SN/A        code += '// stop swig from creating/wrapping default ctor/dtor\n'
5932623SN/A        code += '%%nodefault %s;\n' % classname
5942623SN/A        code += 'class %s ' % classname
5952623SN/A        if obj._base:
5962623SN/A            code += ': public %s' % obj._base.cxx_class
5972623SN/A        code += ' {};\n'
5982623SN/A
5992623SN/A        for ns in namespaces:
600            new_code = 'namespace %s {\n' % ns
601            new_code += code
602            new_code += '}\n'
603            code = new_code
604
605        print >>out, code
606
607    print >>out, '%%include "src/sim/sim_object_params.hh"' % obj
608    for obj in ordered_objs:
609        print >>out, '%%include "params/%s.hh"' % obj
610
611params_file = File('params/params.i')
612names = sorted(sim_objects.keys())
613env.Command(params_file, map(Value, names), buildParams)
614env.Depends(params_file, params_hh_files + params_i_files + depends)
615SwigSource('m5.objects', params_file)
616
617# Build all swig modules
618for swig in SwigSource.all:
619    env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
620                '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
621                '-o ${TARGETS[0]} $SOURCES')
622    env.Depends(swig.py_source.tnode, swig.tnode)
623    env.Depends(swig.cc_source.tnode, swig.tnode)
624
625# Generate the main swig init file
626def makeSwigInit(target, source, env):
627    f = file(str(target[0]), 'w')
628    print >>f, 'extern "C" {'
629    for module in source:
630        print >>f, '    void init_%s();' % module.get_contents()
631    print >>f, '}'
632    print >>f, 'void initSwig() {'
633    for module in source:
634        print >>f, '    init_%s();' % module.get_contents()
635    print >>f, '}'
636    f.close()
637
638env.Command('python/swig/init.cc',
639            map(Value, sorted(s.module for s in SwigSource.all)),
640            makeSwigInit)
641Source('python/swig/init.cc')
642
643def getFlags(source_flags):
644    flagsMap = {}
645    flagsList = []
646    for s in source_flags:
647        val = eval(s.get_contents())
648        name, compound, desc = val
649        flagsList.append(val)
650        flagsMap[name] = bool(compound)
651    
652    for name, compound, desc in flagsList:
653        for flag in compound:
654            if flag not in flagsMap:
655                raise AttributeError, "Trace flag %s not found" % flag
656            if flagsMap[flag]:
657                raise AttributeError, \
658                    "Compound flag can't point to another compound flag"
659
660    flagsList.sort()
661    return flagsList
662
663
664# Generate traceflags.py
665def traceFlagsPy(target, source, env):
666    assert(len(target) == 1)
667
668    f = file(str(target[0]), 'w')
669   
670    allFlags = getFlags(source)
671
672    print >>f, 'basic = ['
673    for flag, compound, desc in allFlags:
674        if not compound:
675            print >>f, "    '%s'," % flag
676    print >>f, "    ]"
677    print >>f
678
679    print >>f, 'compound = ['
680    print >>f, "    'All',"
681    for flag, compound, desc in allFlags:
682        if compound:
683            print >>f, "    '%s'," % flag
684    print >>f, "    ]"
685    print >>f
686
687    print >>f, "all = frozenset(basic + compound)"
688    print >>f
689
690    print >>f, 'compoundMap = {'
691    all = tuple([flag for flag,compound,desc in allFlags if not compound])
692    print >>f, "    'All' : %s," % (all, )
693    for flag, compound, desc in allFlags:
694        if compound:
695            print >>f, "    '%s' : %s," % (flag, compound)
696    print >>f, "    }"
697    print >>f
698
699    print >>f, 'descriptions = {'
700    print >>f, "    'All' : 'All flags',"
701    for flag, compound, desc in allFlags:
702        print >>f, "    '%s' : '%s'," % (flag, desc)
703    print >>f, "    }"
704
705    f.close()
706
707def traceFlagsCC(target, source, env):
708    assert(len(target) == 1)
709
710    f = file(str(target[0]), 'w')
711
712    allFlags = getFlags(source)
713
714    # file header
715    print >>f, '''
716/*
717 * DO NOT EDIT THIS FILE! Automatically generated
718 */
719
720#include "base/traceflags.hh"
721
722using namespace Trace;
723
724const char *Trace::flagStrings[] =
725{'''
726
727    # The string array is used by SimpleEnumParam to map the strings
728    # provided by the user to enum values.
729    for flag, compound, desc in allFlags:
730        if not compound:
731            print >>f, '    "%s",' % flag
732
733    print >>f, '    "All",'
734    for flag, compound, desc in allFlags:
735        if compound:
736            print >>f, '    "%s",' % flag
737
738    print >>f, '};'
739    print >>f
740    print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
741    print >>f
742
743    #
744    # Now define the individual compound flag arrays.  There is an array
745    # for each compound flag listing the component base flags.
746    #
747    all = tuple([flag for flag,compound,desc in allFlags if not compound])
748    print >>f, 'static const Flags AllMap[] = {'
749    for flag, compound, desc in allFlags:
750        if not compound:
751            print >>f, "    %s," % flag
752    print >>f, '};'
753    print >>f
754
755    for flag, compound, desc in allFlags:
756        if not compound:
757            continue
758        print >>f, 'static const Flags %sMap[] = {' % flag
759        for flag in compound:
760            print >>f, "    %s," % flag
761        print >>f, "    (Flags)-1"
762        print >>f, '};'
763        print >>f
764
765    #
766    # Finally the compoundFlags[] array maps the compound flags
767    # to their individual arrays/
768    #
769    print >>f, 'const Flags *Trace::compoundFlags[] ='
770    print >>f, '{'
771    print >>f, '    AllMap,'
772    for flag, compound, desc in allFlags:
773        if compound:
774            print >>f, '    %sMap,' % flag
775    # file trailer
776    print >>f, '};'
777
778    f.close()
779
780def traceFlagsHH(target, source, env):
781    assert(len(target) == 1)
782
783    f = file(str(target[0]), 'w')
784
785    allFlags = getFlags(source)
786
787    # file header boilerplate
788    print >>f, '''
789/*
790 * DO NOT EDIT THIS FILE!
791 *
792 * Automatically generated from traceflags.py
793 */
794
795#ifndef __BASE_TRACE_FLAGS_HH__
796#define __BASE_TRACE_FLAGS_HH__
797
798namespace Trace {
799
800enum Flags {'''
801
802    # Generate the enum.  Base flags come first, then compound flags.
803    idx = 0
804    for flag, compound, desc in allFlags:
805        if not compound:
806            print >>f, '    %s = %d,' % (flag, idx)
807            idx += 1
808
809    numBaseFlags = idx
810    print >>f, '    NumFlags = %d,' % idx
811
812    # put a comment in here to separate base from compound flags
813    print >>f, '''
814// The remaining enum values are *not* valid indices for Trace::flags.
815// They are "compound" flags, which correspond to sets of base
816// flags, and are used by changeFlag.'''
817
818    print >>f, '    All = %d,' % idx
819    idx += 1
820    for flag, compound, desc in allFlags:
821        if compound:
822            print >>f, '    %s = %d,' % (flag, idx)
823            idx += 1
824
825    numCompoundFlags = idx - numBaseFlags
826    print >>f, '    NumCompoundFlags = %d' % numCompoundFlags
827
828    # trailer boilerplate
829    print >>f, '''\
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    f.close()
846
847flags = map(Value, trace_flags.values())
848env.Command('base/traceflags.py', flags, traceFlagsPy)
849PySource('m5', 'base/traceflags.py')
850
851env.Command('base/traceflags.hh', flags, traceFlagsHH)
852env.Command('base/traceflags.cc', flags, traceFlagsCC)
853Source('base/traceflags.cc')
854
855# embed python files.  All .py files that have been indicated by a
856# PySource() call in a SConscript need to be embedded into the M5
857# library.  To do that, we compile the file to byte code, marshal the
858# byte code, compress it, and then generate an assembly file that
859# inserts the result into the data section with symbols indicating the
860# beginning, and end (and with the size at the end)
861def objectifyPyFile(target, source, env):
862    '''Action function to compile a .py into a code object, marshal
863    it, compress it, and stick it into an asm file so the code appears
864    as just bytes with a label in the data section'''
865
866    src = file(str(source[0]), 'r').read()
867    dst = file(str(target[0]), 'w')
868
869    pysource = PySource.tnodes[source[0]]
870    compiled = compile(src, pysource.debugname, 'exec')
871    marshalled = marshal.dumps(compiled)
872    compressed = zlib.compress(marshalled)
873    data = compressed
874
875    # Some C/C++ compilers prepend an underscore to global symbol
876    # names, so if they're going to do that, we need to prepend that
877    # leading underscore to globals in the assembly file.
878    if env['LEADING_UNDERSCORE']:
879        sym = '_' + pysource.symname
880    else:
881        sym = pysource.symname
882
883    step = 16
884    print >>dst, ".data"
885    print >>dst, ".globl %s_beg" % sym
886    print >>dst, ".globl %s_end" % sym
887    print >>dst, "%s_beg:" % sym
888    for i in xrange(0, len(data), step):
889        x = array.array('B', data[i:i+step])
890        print >>dst, ".byte", ','.join([str(d) for d in x])
891    print >>dst, "%s_end:" % sym
892    print >>dst, ".long %d" % len(marshalled)
893
894for source in PySource.all:
895    env.Command(source.assembly, source.tnode, objectifyPyFile)
896    Source(source.assembly)
897
898# Generate init_python.cc which creates a bunch of EmbeddedPyModule
899# structs that describe the embedded python code.  One such struct
900# contains information about the importer that python uses to get at
901# the embedded files, and then there's a list of all of the rest that
902# the importer uses to load the rest on demand.
903def pythonInit(target, source, env):
904    dst = file(str(target[0]), 'w')
905
906    def dump_mod(sym, endchar=','):
907        pysource = PySource.symnames[sym]
908        print >>dst, '    { "%s",' % pysource.arcname
909        print >>dst, '      "%s",' % pysource.modpath
910        print >>dst, '       %s_beg, %s_end,' % (sym, sym)
911        print >>dst, '       %s_end - %s_beg,' % (sym, sym)
912        print >>dst, '       *(int *)%s_end }%s'  % (sym, endchar)
913    
914    print >>dst, '#include "sim/init.hh"'
915
916    for sym in source:
917        sym = sym.get_contents()
918        print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym)
919
920    print >>dst, "const EmbeddedPyModule embeddedPyImporter = "
921    dump_mod("PyEMB_importer", endchar=';');
922    print >>dst
923
924    print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {"
925    for i,sym in enumerate(source):
926        sym = sym.get_contents()
927        if sym == "PyEMB_importer":
928            # Skip the importer since we've already exported it
929            continue
930        dump_mod(sym)
931    print >>dst, "    { 0, 0, 0, 0, 0, 0 }"
932    print >>dst, "};"
933
934
935env.Command('sim/init_python.cc',
936            map(Value, (s.symname for s in PySource.all)),
937            pythonInit)
938Source('sim/init_python.cc')
939
940########################################################################
941#
942# Define binaries.  Each different build type (debug, opt, etc.) gets
943# a slightly different build environment.
944#
945
946# List of constructed environments to pass back to SConstruct
947envList = []
948
949date_source = Source('base/date.cc', skip_lib=True)
950
951# Function to create a new build environment as clone of current
952# environment 'env' with modified object suffix and optional stripped
953# binary.  Additional keyword arguments are appended to corresponding
954# build environment vars.
955def makeEnv(label, objsfx, strip = False, **kwargs):
956    # SCons doesn't know to append a library suffix when there is a '.' in the
957    # name.  Use '_' instead.
958    libname = 'm5_' + label
959    exename = 'm5.' + label
960
961    new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
962    new_env.Label = label
963    new_env.Append(**kwargs)
964
965    swig_env = new_env.Clone()
966    swig_env.Append(CCFLAGS='-Werror')
967    if env['GCC']:
968        swig_env.Append(CCFLAGS='-Wno-uninitialized')
969        swig_env.Append(CCFLAGS='-Wno-sign-compare')
970        swig_env.Append(CCFLAGS='-Wno-parentheses')
971
972    werror_env = new_env.Clone()
973    werror_env.Append(CCFLAGS='-Werror')
974
975    def make_obj(source, static, extra_deps = None):
976        '''This function adds the specified source to the correct
977        build environment, and returns the corresponding SCons Object
978        nodes'''
979
980        if source.swig:
981            env = swig_env
982        elif source.Werror:
983            env = werror_env
984        else:
985            env = new_env
986
987        if static:
988            obj = env.StaticObject(source.tnode)
989        else:
990            obj = env.SharedObject(source.tnode)
991
992        if extra_deps:
993            env.Depends(obj, extra_deps)
994
995        return obj
996
997    static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)]
998    shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)]
999
1000    static_date = make_obj(date_source, static=True, extra_deps=static_objs)
1001    static_objs.append(static_date)
1002    
1003    shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
1004    shared_objs.append(shared_date)
1005
1006    # First make a library of everything but main() so other programs can
1007    # link against m5.
1008    static_lib = new_env.StaticLibrary(libname, static_objs)
1009    shared_lib = new_env.SharedLibrary(libname, shared_objs)
1010
1011    for target, sources in unit_tests:
1012        objs = [ make_obj(s, static=True) for s in sources ]
1013        new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs)
1014
1015    # Now link a stub with main() and the static library.
1016    bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ]
1017    progname = exename
1018    if strip:
1019        progname += '.unstripped'
1020
1021    targets = new_env.Program(progname, bin_objs + static_objs)
1022
1023    if strip:
1024        if sys.platform == 'sunos5':
1025            cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1026        else:
1027            cmd = 'strip $SOURCE -o $TARGET'
1028        targets = new_env.Command(exename, progname, cmd)
1029            
1030    new_env.M5Binary = targets[0]
1031    envList.append(new_env)
1032
1033# Debug binary
1034ccflags = {}
1035if env['GCC']:
1036    if sys.platform == 'sunos5':
1037        ccflags['debug'] = '-gstabs+'
1038    else:
1039        ccflags['debug'] = '-ggdb3'
1040    ccflags['opt'] = '-g -O3'
1041    ccflags['fast'] = '-O3'
1042    ccflags['prof'] = '-O3 -g -pg'
1043elif env['SUNCC']:
1044    ccflags['debug'] = '-g0'
1045    ccflags['opt'] = '-g -O'
1046    ccflags['fast'] = '-fast'
1047    ccflags['prof'] = '-fast -g -pg'
1048elif env['ICC']:
1049    ccflags['debug'] = '-g -O0'
1050    ccflags['opt'] = '-g -O'
1051    ccflags['fast'] = '-fast'
1052    ccflags['prof'] = '-fast -g -pg'
1053else:
1054    print 'Unknown compiler, please fix compiler options'
1055    Exit(1)
1056
1057makeEnv('debug', '.do',
1058        CCFLAGS = Split(ccflags['debug']),
1059        CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1060
1061# Optimized binary
1062makeEnv('opt', '.o',
1063        CCFLAGS = Split(ccflags['opt']),
1064        CPPDEFINES = ['TRACING_ON=1'])
1065
1066# "Fast" binary
1067makeEnv('fast', '.fo', strip = True,
1068        CCFLAGS = Split(ccflags['fast']),
1069        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1070
1071# Profiled binary
1072makeEnv('prof', '.po',
1073        CCFLAGS = Split(ccflags['prof']),
1074        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1075        LINKFLAGS = '-pg')
1076
1077Return('envList')
1078