SConscript revision 7722
1955SN/A# -*- mode:python -*-
2955SN/A
31762SN/A# Copyright (c) 2004-2005 The Regents of The University of Michigan
4955SN/A# All rights reserved.
5955SN/A#
6955SN/A# Redistribution and use in source and binary forms, with or without
7955SN/A# modification, are permitted provided that the following conditions are
8955SN/A# met: redistributions of source code must retain the above copyright
9955SN/A# notice, this list of conditions and the following disclaimer;
10955SN/A# redistributions in binary form must reproduce the above copyright
11955SN/A# notice, this list of conditions and the following disclaimer in the
12955SN/A# documentation and/or other materials provided with the distribution;
13955SN/A# neither the name of the copyright holders nor the names of its
14955SN/A# contributors may be used to endorse or promote products derived from
15955SN/A# this software without specific prior written permission.
16955SN/A#
17955SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18955SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19955SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20955SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21955SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22955SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23955SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24955SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25955SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26955SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27955SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282665Ssaidi@eecs.umich.edu#
294762Snate@binkert.org# Authors: Nathan Binkert
30955SN/A
314762Snate@binkert.orgimport array
32955SN/Aimport bisect
33955SN/Aimport imp
344202Sbinkertn@umich.eduimport marshal
354382Sbinkertn@umich.eduimport os
364202Sbinkertn@umich.eduimport re
374762Snate@binkert.orgimport sys
384762Snate@binkert.orgimport zlib
394762Snate@binkert.org
40955SN/Afrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath
414381Sbinkertn@umich.edu
424381Sbinkertn@umich.eduimport SCons
43955SN/A
44955SN/A# This file defines how to build a particular configuration of M5
45955SN/A# based on variable settings in the 'env' build environment.
464202Sbinkertn@umich.edu
47955SN/AImport('*')
484382Sbinkertn@umich.edu
494382Sbinkertn@umich.edu# Children need to see the environment
504382Sbinkertn@umich.eduExport('env')
514762Snate@binkert.org
524762Snate@binkert.orgbuild_env = [(opt, env[opt]) for opt in export_vars]
534762Snate@binkert.org
544762Snate@binkert.orgfrom m5.util import code_formatter
554762Snate@binkert.org
564762Snate@binkert.org########################################################################
574762Snate@binkert.org# Code for adding source files of various types
584762Snate@binkert.org#
594762Snate@binkert.orgclass SourceMeta(type):
604762Snate@binkert.org    def __init__(cls, name, bases, dict):
614762Snate@binkert.org        super(SourceMeta, cls).__init__(name, bases, dict)
624762Snate@binkert.org        cls.all = []
634762Snate@binkert.org        
644762Snate@binkert.org    def get(cls, **kwargs):
654762Snate@binkert.org        for src in cls.all:
664762Snate@binkert.org            for attr,value in kwargs.iteritems():
674762Snate@binkert.org                if getattr(src, attr) != value:
684762Snate@binkert.org                    break
694762Snate@binkert.org            else:
704762Snate@binkert.org                yield src
714762Snate@binkert.org
724762Snate@binkert.orgclass SourceFile(object):
734762Snate@binkert.org    __metaclass__ = SourceMeta
744762Snate@binkert.org    def __init__(self, source):
754762Snate@binkert.org        tnode = source
764762Snate@binkert.org        if not isinstance(source, SCons.Node.FS.File):
774762Snate@binkert.org            tnode = File(source)
784762Snate@binkert.org
794762Snate@binkert.org        self.tnode = tnode
804762Snate@binkert.org        self.snode = tnode.srcnode()
814762Snate@binkert.org        self.filename = str(tnode)
824762Snate@binkert.org        self.dirname = dirname(self.filename)
834762Snate@binkert.org        self.basename = basename(self.filename)
844382Sbinkertn@umich.edu        index = self.basename.rfind('.')
854762Snate@binkert.org        if index <= 0:
864382Sbinkertn@umich.edu            # dot files aren't extensions
874762Snate@binkert.org            self.extname = self.basename, None
884381Sbinkertn@umich.edu        else:
894762Snate@binkert.org            self.extname = self.basename[:index], self.basename[index+1:]
904762Snate@binkert.org
914762Snate@binkert.org        for base in type(self).__mro__:
924762Snate@binkert.org            if issubclass(base, SourceFile):
934762Snate@binkert.org                base.all.append(self)
944762Snate@binkert.org
954762Snate@binkert.org    def __lt__(self, other): return self.filename < other.filename
964762Snate@binkert.org    def __le__(self, other): return self.filename <= other.filename
974762Snate@binkert.org    def __gt__(self, other): return self.filename > other.filename
984762Snate@binkert.org    def __ge__(self, other): return self.filename >= other.filename
994762Snate@binkert.org    def __eq__(self, other): return self.filename == other.filename
1004762Snate@binkert.org    def __ne__(self, other): return self.filename != other.filename
1014762Snate@binkert.org        
1024762Snate@binkert.orgclass Source(SourceFile):
1034762Snate@binkert.org    '''Add a c/c++ source file to the build'''
1044762Snate@binkert.org    def __init__(self, source, Werror=True, swig=False, bin_only=False,
1054762Snate@binkert.org                 skip_lib=False):
1064762Snate@binkert.org        super(Source, self).__init__(source)
1074762Snate@binkert.org
1084762Snate@binkert.org        self.Werror = Werror
1094762Snate@binkert.org        self.swig = swig
1104762Snate@binkert.org        self.bin_only = bin_only
1114762Snate@binkert.org        self.skip_lib = bin_only or skip_lib
1124762Snate@binkert.org
1134762Snate@binkert.orgclass PySource(SourceFile):
1144762Snate@binkert.org    '''Add a python source file to the named package'''
1154762Snate@binkert.org    invalid_sym_char = re.compile('[^A-z0-9_]')
1164762Snate@binkert.org    modules = {}
1174762Snate@binkert.org    tnodes = {}
1184762Snate@binkert.org    symnames = {}
1194762Snate@binkert.org    
1204762Snate@binkert.org    def __init__(self, package, source):
1214762Snate@binkert.org        super(PySource, self).__init__(source)
1224762Snate@binkert.org
1234762Snate@binkert.org        modname,ext = self.extname
1244762Snate@binkert.org        assert ext == 'py'
1254762Snate@binkert.org
1264762Snate@binkert.org        if package:
1274762Snate@binkert.org            path = package.split('.')
1284762Snate@binkert.org        else:
129955SN/A            path = []
1304382Sbinkertn@umich.edu
1314202Sbinkertn@umich.edu        modpath = path[:]
1324382Sbinkertn@umich.edu        if modname != '__init__':
1334382Sbinkertn@umich.edu            modpath += [ modname ]
1344382Sbinkertn@umich.edu        modpath = '.'.join(modpath)
1354382Sbinkertn@umich.edu
1364382Sbinkertn@umich.edu        arcpath = path + [ self.basename ]
1374382Sbinkertn@umich.edu        abspath = self.snode.abspath
1384382Sbinkertn@umich.edu        if not exists(abspath):
1394382Sbinkertn@umich.edu            abspath = self.tnode.abspath
1404382Sbinkertn@umich.edu
1412667Sstever@eecs.umich.edu        self.package = package
1422667Sstever@eecs.umich.edu        self.modname = modname
1432667Sstever@eecs.umich.edu        self.modpath = modpath
1442667Sstever@eecs.umich.edu        self.arcname = joinpath(*arcpath)
1452667Sstever@eecs.umich.edu        self.abspath = abspath
1462667Sstever@eecs.umich.edu        self.compiled = File(self.filename + 'c')
1472037SN/A        self.cpp = File(self.filename + '.cc')
1482037SN/A        self.symname = PySource.invalid_sym_char.sub('_', modpath)
1492037SN/A
1504382Sbinkertn@umich.edu        PySource.modules[modpath] = self
1514762Snate@binkert.org        PySource.tnodes[self.tnode] = self
1524202Sbinkertn@umich.edu        PySource.symnames[self.symname] = self
1534382Sbinkertn@umich.edu
1544202Sbinkertn@umich.educlass SimObject(PySource):
1554202Sbinkertn@umich.edu    '''Add a SimObject python file as a python source object and add
1564202Sbinkertn@umich.edu    it to a list of sim object modules'''
1574202Sbinkertn@umich.edu
1584202Sbinkertn@umich.edu    fixed = False
1594202Sbinkertn@umich.edu    modnames = []
1604762Snate@binkert.org
1614202Sbinkertn@umich.edu    def __init__(self, source):
1624202Sbinkertn@umich.edu        super(SimObject, self).__init__('m5.objects', source)
1634202Sbinkertn@umich.edu        if self.fixed:
1644202Sbinkertn@umich.edu            raise AttributeError, "Too late to call SimObject now."
1654202Sbinkertn@umich.edu
1661858SN/A        bisect.insort_right(SimObject.modnames, self.modname)
1671858SN/A
1681858SN/Aclass SwigSource(SourceFile):
1691085SN/A    '''Add a swig file to build'''
1704382Sbinkertn@umich.edu
1714382Sbinkertn@umich.edu    def __init__(self, package, source):
1724762Snate@binkert.org        super(SwigSource, self).__init__(source)
1734762Snate@binkert.org
1744762Snate@binkert.org        modname,ext = self.extname
1754762Snate@binkert.org        assert ext == 'i'
1764762Snate@binkert.org
1774762Snate@binkert.org        self.module = modname
1784762Snate@binkert.org        cc_file = joinpath(self.dirname, modname + '_wrap.cc')
1794762Snate@binkert.org        py_file = joinpath(self.dirname, modname + '.py')
1804762Snate@binkert.org
1814762Snate@binkert.org        self.cc_source = Source(cc_file, swig=True)
1824762Snate@binkert.org        self.py_source = PySource(package, py_file)
1834762Snate@binkert.org
1844762Snate@binkert.orgunit_tests = []
1854762Snate@binkert.orgdef UnitTest(target, sources):
1864762Snate@binkert.org    if not isinstance(sources, (list, tuple)):
1874762Snate@binkert.org        sources = [ sources ]
1884762Snate@binkert.org
1894762Snate@binkert.org    sources = [ Source(src, skip_lib=True) for src in sources ]
1904762Snate@binkert.org    unit_tests.append((target, sources))
1914762Snate@binkert.org
1924762Snate@binkert.org# Children should have access
1934762Snate@binkert.orgExport('Source')
1944762Snate@binkert.orgExport('PySource')
1954762Snate@binkert.orgExport('SimObject')
1964762Snate@binkert.orgExport('SwigSource')
1974762Snate@binkert.orgExport('UnitTest')
1984762Snate@binkert.org
1994762Snate@binkert.org########################################################################
2004762Snate@binkert.org#
2014762Snate@binkert.org# Trace Flags
2024762Snate@binkert.org#
2034762Snate@binkert.orgtrace_flags = {}
2044762Snate@binkert.orgdef TraceFlag(name, desc=None):
2054762Snate@binkert.org    if name in trace_flags:
2064762Snate@binkert.org        raise AttributeError, "Flag %s already specified" % name
2074382Sbinkertn@umich.edu    trace_flags[name] = (name, (), desc)
2084382Sbinkertn@umich.edu
2094762Snate@binkert.orgdef CompoundFlag(name, flags, desc=None):
2104762Snate@binkert.org    if name in trace_flags:
2114762Snate@binkert.org        raise AttributeError, "Flag %s already specified" % name
2124382Sbinkertn@umich.edu
2134382Sbinkertn@umich.edu    compound = tuple(flags)
2144762Snate@binkert.org    trace_flags[name] = (name, compound, desc)
2154382Sbinkertn@umich.edu
2164382Sbinkertn@umich.eduExport('TraceFlag')
2174762Snate@binkert.orgExport('CompoundFlag')
2184382Sbinkertn@umich.edu
2194382Sbinkertn@umich.edu########################################################################
2204762Snate@binkert.org#
2214382Sbinkertn@umich.edu# Set some compiler variables
2224762Snate@binkert.org#
2234762Snate@binkert.org
2244382Sbinkertn@umich.edu# Include file paths are rooted in this directory.  SCons will
2254382Sbinkertn@umich.edu# automatically expand '.' to refer to both the source directory and
2264762Snate@binkert.org# the corresponding build directory to pick up generated include
2274762Snate@binkert.org# files.
2284762Snate@binkert.orgenv.Append(CPPPATH=Dir('.'))
2294762Snate@binkert.org
2304762Snate@binkert.orgfor extra_dir in extras_dir_list:
2314762Snate@binkert.org    env.Append(CPPPATH=Dir(extra_dir))
2324762Snate@binkert.org
2334762Snate@binkert.org# Workaround for bug in SCons version > 0.97d20071212
2344762Snate@binkert.org# Scons bug id: 2006 M5 Bug id: 308 
2354762Snate@binkert.orgfor root, dirs, files in os.walk(base_dir, topdown=True):
2364762Snate@binkert.org    Dir(root[len(base_dir) + 1:])
2374762Snate@binkert.org
2384762Snate@binkert.org########################################################################
2394762Snate@binkert.org#
2404762Snate@binkert.org# Walk the tree and execute all SConscripts in subdirectories
2414762Snate@binkert.org#
2424762Snate@binkert.org
2434762Snate@binkert.orghere = Dir('.').srcnode().abspath
2444762Snate@binkert.orgfor root, dirs, files in os.walk(base_dir, topdown=True):
2454762Snate@binkert.org    if root == here:
2464762Snate@binkert.org        # we don't want to recurse back into this SConscript
2474762Snate@binkert.org        continue
2484762Snate@binkert.org
2494762Snate@binkert.org    if 'SConscript' in files:
2504762Snate@binkert.org        build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
2514762Snate@binkert.org        SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
2524762Snate@binkert.org
2534762Snate@binkert.orgfor extra_dir in extras_dir_list:
2544762Snate@binkert.org    prefix_len = len(dirname(extra_dir)) + 1
2554762Snate@binkert.org    for root, dirs, files in os.walk(extra_dir, topdown=True):
2564762Snate@binkert.org        if 'SConscript' in files:
2574762Snate@binkert.org            build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
2584762Snate@binkert.org            SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
2594762Snate@binkert.org
2604762Snate@binkert.orgfor opt in export_vars:
2614762Snate@binkert.org    env.ConfigFile(opt)
2624762Snate@binkert.org
2634762Snate@binkert.orgdef makeTheISA(source, target, env):
2644762Snate@binkert.org    isas = [ src.get_contents() for src in source ]
2654762Snate@binkert.org    target_isa = env['TARGET_ISA']
2664762Snate@binkert.org    def define(isa):
2674762Snate@binkert.org        return isa.upper() + '_ISA'
2684762Snate@binkert.org    
2694762Snate@binkert.org    def namespace(isa):
2704762Snate@binkert.org        return isa[0].upper() + isa[1:].lower() + 'ISA' 
2714762Snate@binkert.org
2724762Snate@binkert.org
2734762Snate@binkert.org    code = code_formatter()
2744762Snate@binkert.org    code('''\
2754382Sbinkertn@umich.edu#ifndef __CONFIG_THE_ISA_HH__
2764762Snate@binkert.org#define __CONFIG_THE_ISA_HH__
2774382Sbinkertn@umich.edu
2784762Snate@binkert.org''')
2794382Sbinkertn@umich.edu
2804762Snate@binkert.org    for i,isa in enumerate(isas):
2814762Snate@binkert.org        code('#define $0 $1', define(isa), i + 1)
2824762Snate@binkert.org
2834762Snate@binkert.org    code('''
2844382Sbinkertn@umich.edu
2854382Sbinkertn@umich.edu#define THE_ISA ${{define(target_isa)}}
2864382Sbinkertn@umich.edu#define TheISA ${{namespace(target_isa)}}
2874382Sbinkertn@umich.edu
2884382Sbinkertn@umich.edu#endif // __CONFIG_THE_ISA_HH__''')
2894382Sbinkertn@umich.edu
2904762Snate@binkert.org    code.write(str(target[0]))
2914382Sbinkertn@umich.edu
2924382Sbinkertn@umich.eduenv.Command('config/the_isa.hh', map(Value, all_isa_list), makeTheISA)
2934382Sbinkertn@umich.edu
2944382Sbinkertn@umich.edu########################################################################
2954762Snate@binkert.org#
2964762Snate@binkert.org# Prevent any SimObjects from being added after this point, they
2974762Snate@binkert.org# should all have been added in the SConscripts above
2984382Sbinkertn@umich.edu#
2994762Snate@binkert.orgSimObject.fixed = True
3004382Sbinkertn@umich.edu
3014382Sbinkertn@umich.educlass DictImporter(object):
3024382Sbinkertn@umich.edu    '''This importer takes a dictionary of arbitrary module names that
3034762Snate@binkert.org    map to arbitrary filenames.'''
3044762Snate@binkert.org    def __init__(self, modules):
3054382Sbinkertn@umich.edu        self.modules = modules
3064382Sbinkertn@umich.edu        self.installed = set()
3074382Sbinkertn@umich.edu
3084762Snate@binkert.org    def __del__(self):
3094382Sbinkertn@umich.edu        self.unload()
3104382Sbinkertn@umich.edu
3114762Snate@binkert.org    def unload(self):
3124762Snate@binkert.org        import sys
3134762Snate@binkert.org        for module in self.installed:
3144382Sbinkertn@umich.edu            del sys.modules[module]
3154382Sbinkertn@umich.edu        self.installed = set()
3164382Sbinkertn@umich.edu
3174382Sbinkertn@umich.edu    def find_module(self, fullname, path):
3184382Sbinkertn@umich.edu        if fullname == 'm5.defines':
3194382Sbinkertn@umich.edu            return self
3204382Sbinkertn@umich.edu
3214382Sbinkertn@umich.edu        if fullname == 'm5.objects':
3224382Sbinkertn@umich.edu            return self
3234382Sbinkertn@umich.edu
324955SN/A        if fullname.startswith('m5.internal'):
325955SN/A            return None
326955SN/A
327955SN/A        source = self.modules.get(fullname, None)
3281108SN/A        if source is not None and fullname.startswith('m5.objects'):
329955SN/A            return self
330955SN/A
331955SN/A        return None
332955SN/A
333955SN/A    def load_module(self, fullname):
334955SN/A        mod = imp.new_module(fullname)
335955SN/A        sys.modules[fullname] = mod
336955SN/A        self.installed.add(fullname)
337955SN/A
3382655Sstever@eecs.umich.edu        mod.__loader__ = self
3392655Sstever@eecs.umich.edu        if fullname == 'm5.objects':
3402655Sstever@eecs.umich.edu            mod.__path__ = fullname.split('.')
3412655Sstever@eecs.umich.edu            return mod
3422655Sstever@eecs.umich.edu
3432655Sstever@eecs.umich.edu        if fullname == 'm5.defines':
3442655Sstever@eecs.umich.edu            mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
3452655Sstever@eecs.umich.edu            return mod
3462655Sstever@eecs.umich.edu
3472655Sstever@eecs.umich.edu        source = self.modules[fullname]
3484762Snate@binkert.org        if source.modname == '__init__':
3492655Sstever@eecs.umich.edu            mod.__path__ = source.modpath
3502655Sstever@eecs.umich.edu        mod.__file__ = source.abspath
3514007Ssaidi@eecs.umich.edu
3524596Sbinkertn@umich.edu        exec file(source.abspath, 'r') in mod.__dict__
3534007Ssaidi@eecs.umich.edu
3544596Sbinkertn@umich.edu        return mod
3554596Sbinkertn@umich.edu
3562655Sstever@eecs.umich.eduimport m5.SimObject
3574382Sbinkertn@umich.eduimport m5.params
3582655Sstever@eecs.umich.edufrom m5.util import code_formatter
3592655Sstever@eecs.umich.edu
3602655Sstever@eecs.umich.edum5.SimObject.clear()
361955SN/Am5.params.clear()
3623918Ssaidi@eecs.umich.edu
3633918Ssaidi@eecs.umich.edu# install the python importer so we can grab stuff from the source
3643918Ssaidi@eecs.umich.edu# tree itself.  We can't have SimObjects added after this point or
3653918Ssaidi@eecs.umich.edu# else we won't know about them for the rest of the stuff.
3663918Ssaidi@eecs.umich.eduimporter = DictImporter(PySource.modules)
3673918Ssaidi@eecs.umich.edusys.meta_path[0:0] = [ importer ]
3683918Ssaidi@eecs.umich.edu
3693918Ssaidi@eecs.umich.edu# import all sim objects so we can populate the all_objects list
3703918Ssaidi@eecs.umich.edu# make sure that we're working with a list, then let's sort it
3713918Ssaidi@eecs.umich.edufor modname in SimObject.modnames:
3723918Ssaidi@eecs.umich.edu    exec('from m5.objects import %s' % modname)
3733918Ssaidi@eecs.umich.edu
3743918Ssaidi@eecs.umich.edu# we need to unload all of the currently imported modules so that they
3753918Ssaidi@eecs.umich.edu# will be re-imported the next time the sconscript is run
3763940Ssaidi@eecs.umich.eduimporter.unload()
3773940Ssaidi@eecs.umich.edusys.meta_path.remove(importer)
3783940Ssaidi@eecs.umich.edu
3793942Ssaidi@eecs.umich.edusim_objects = m5.SimObject.allClasses
3803940Ssaidi@eecs.umich.eduall_enums = m5.params.allEnums
3813515Ssaidi@eecs.umich.edu
3823918Ssaidi@eecs.umich.eduall_params = {}
3834762Snate@binkert.orgfor name,obj in sorted(sim_objects.iteritems()):
3843515Ssaidi@eecs.umich.edu    for param in obj._params.local.values():
3852655Sstever@eecs.umich.edu        # load the ptype attribute now because it depends on the
3863918Ssaidi@eecs.umich.edu        # current version of SimObject.allClasses, but when scons
3873619Sbinkertn@umich.edu        # actually uses the value, all versions of
388955SN/A        # SimObject.allClasses will have been loaded
389955SN/A        param.ptype
3902655Sstever@eecs.umich.edu
3913918Ssaidi@eecs.umich.edu        if not hasattr(param, 'swig_decl'):
3923619Sbinkertn@umich.edu            continue
393955SN/A        pname = param.ptype_str
394955SN/A        if pname not in all_params:
3952655Sstever@eecs.umich.edu            all_params[pname] = param
3963918Ssaidi@eecs.umich.edu
3973619Sbinkertn@umich.edu########################################################################
398955SN/A#
399955SN/A# calculate extra dependencies
4002655Sstever@eecs.umich.edu#
4013918Ssaidi@eecs.umich.edumodule_depends = ["m5", "m5.SimObject", "m5.params"]
4023683Sstever@eecs.umich.edudepends = [ PySource.modules[dep].snode for dep in module_depends ]
4032655Sstever@eecs.umich.edu
4041869SN/A########################################################################
4051869SN/A#
406# Commands for the basic automatically generated python files
407#
408
409# Generate Python file containing a dict specifying the current
410# buildEnv flags.
411def makeDefinesPyFile(target, source, env):
412    build_env, hg_info = [ x.get_contents() for x in source ]
413
414    code = code_formatter()
415    code("""
416import m5.internal
417import m5.util
418
419buildEnv = m5.util.SmartDict($build_env)
420hgRev = '$hg_info'
421
422compileDate = m5.internal.core.compileDate
423_globals = globals()
424for key,val in m5.internal.core.__dict__.iteritems():
425    if key.startswith('flag_'):
426        flag = key[5:]
427        _globals[flag] = val
428del _globals
429""")
430    code.write(target[0].abspath)
431
432defines_info = [ Value(build_env), Value(env['HG_INFO']) ]
433# Generate a file with all of the compile options in it
434env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile)
435PySource('m5', 'python/m5/defines.py')
436
437# Generate python file containing info about the M5 source code
438def makeInfoPyFile(target, source, env):
439    code = code_formatter()
440    for src in source:
441        data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
442        code('$src = ${{repr(data)}}')
443    code.write(str(target[0]))
444
445# Generate a file that wraps the basic top level files
446env.Command('python/m5/info.py',
447            [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
448            makeInfoPyFile)
449PySource('m5', 'python/m5/info.py')
450
451########################################################################
452#
453# Create all of the SimObject param headers and enum headers
454#
455
456def createSimObjectParam(target, source, env):
457    assert len(target) == 1 and len(source) == 1
458
459    name = str(source[0].get_contents())
460    obj = sim_objects[name]
461
462    code = code_formatter()
463    obj.cxx_decl(code)
464    code.write(target[0].abspath)
465
466def createSwigParam(target, source, env):
467    assert len(target) == 1 and len(source) == 1
468
469    name = str(source[0].get_contents())
470    param = all_params[name]
471
472    code = code_formatter()
473    code('%module(package="m5.internal") $0_${name}', param.file_ext)
474    param.swig_decl(code)
475    code.write(target[0].abspath)
476
477def createEnumStrings(target, source, env):
478    assert len(target) == 1 and len(source) == 1
479
480    name = str(source[0].get_contents())
481    obj = all_enums[name]
482
483    code = code_formatter()
484    obj.cxx_def(code)
485    code.write(target[0].abspath)
486
487def createEnumParam(target, source, env):
488    assert len(target) == 1 and len(source) == 1
489
490    name = str(source[0].get_contents())
491    obj = all_enums[name]
492
493    code = code_formatter()
494    obj.cxx_decl(code)
495    code.write(target[0].abspath)
496
497def createEnumSwig(target, source, env):
498    assert len(target) == 1 and len(source) == 1
499
500    name = str(source[0].get_contents())
501    obj = all_enums[name]
502
503    code = code_formatter()
504    code('''\
505%module(package="m5.internal") enum_$name
506
507%{
508#include "enums/$name.hh"
509%}
510
511%include "enums/$name.hh"
512''')
513    code.write(target[0].abspath)
514
515# Generate all of the SimObject param struct header files
516params_hh_files = []
517for name,simobj in sorted(sim_objects.iteritems()):
518    py_source = PySource.modules[simobj.__module__]
519    extra_deps = [ py_source.tnode ]
520
521    hh_file = File('params/%s.hh' % name)
522    params_hh_files.append(hh_file)
523    env.Command(hh_file, Value(name), createSimObjectParam)
524    env.Depends(hh_file, depends + extra_deps)
525
526# Generate any parameter header files needed
527params_i_files = []
528for name,param in all_params.iteritems():
529    i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name))
530    params_i_files.append(i_file)
531    env.Command(i_file, Value(name), createSwigParam)
532    env.Depends(i_file, depends)
533    SwigSource('m5.internal', i_file)
534
535# Generate all enum header files
536for name,enum in sorted(all_enums.iteritems()):
537    py_source = PySource.modules[enum.__module__]
538    extra_deps = [ py_source.tnode ]
539
540    cc_file = File('enums/%s.cc' % name)
541    env.Command(cc_file, Value(name), createEnumStrings)
542    env.Depends(cc_file, depends + extra_deps)
543    Source(cc_file)
544
545    hh_file = File('enums/%s.hh' % name)
546    env.Command(hh_file, Value(name), createEnumParam)
547    env.Depends(hh_file, depends + extra_deps)
548
549    i_file = File('python/m5/internal/enum_%s.i' % name)
550    env.Command(i_file, Value(name), createEnumSwig)
551    env.Depends(i_file, depends + extra_deps)
552    SwigSource('m5.internal', i_file)
553
554def buildParam(target, source, env):
555    name = source[0].get_contents()
556    obj = sim_objects[name]
557    class_path = obj.cxx_class.split('::')
558    classname = class_path[-1]
559    namespaces = class_path[:-1]
560    params = obj._params.local.values()
561
562    code = code_formatter()
563
564    code('%module(package="m5.internal") param_$name')
565    code()
566    code('%{')
567    code('#include "params/$obj.hh"')
568    for param in params:
569        param.cxx_predecls(code)
570    code('%}')
571    code()
572
573    for param in params:
574        param.swig_predecls(code)
575
576    code()
577    if obj._base:
578        code('%import "python/m5/internal/param_${{obj._base}}.i"')
579    code()
580    obj.swig_objdecls(code)
581    code()
582
583    code('%include "params/$obj.hh"')
584
585    code.write(target[0].abspath)
586
587for name in sim_objects.iterkeys():
588    params_file = File('python/m5/internal/param_%s.i' % name)
589    env.Command(params_file, Value(name), buildParam)
590    env.Depends(params_file, depends)
591    SwigSource('m5.internal', params_file)
592
593# Generate the main swig init file
594def makeEmbeddedSwigInit(target, source, env):
595    code = code_formatter()
596    module = source[0].get_contents()
597    code('''\
598#include "sim/init.hh"
599
600extern "C" {
601    void init_${module}();
602}
603
604EmbeddedSwig embed_swig_${module}(init_${module});
605''')
606    code.write(str(target[0]))
607    
608# Build all swig modules
609for swig in SwigSource.all:
610    env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
611                '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
612                '-o ${TARGETS[0]} $SOURCES')
613    init_file = 'python/swig/init_%s.cc' % swig.module
614    env.Command(init_file, Value(swig.module), makeEmbeddedSwigInit)
615    Source(init_file)
616    env.Depends(swig.py_source.tnode, swig.tnode)
617    env.Depends(swig.cc_source.tnode, swig.tnode)
618
619def getFlags(source_flags):
620    flagsMap = {}
621    flagsList = []
622    for s in source_flags:
623        val = eval(s.get_contents())
624        name, compound, desc = val
625        flagsList.append(val)
626        flagsMap[name] = bool(compound)
627    
628    for name, compound, desc in flagsList:
629        for flag in compound:
630            if flag not in flagsMap:
631                raise AttributeError, "Trace flag %s not found" % flag
632            if flagsMap[flag]:
633                raise AttributeError, \
634                    "Compound flag can't point to another compound flag"
635
636    flagsList.sort()
637    return flagsList
638
639
640# Generate traceflags.py
641def traceFlagsPy(target, source, env):
642    assert(len(target) == 1)
643    code = code_formatter()
644
645    allFlags = getFlags(source)
646
647    code('basic = [')
648    code.indent()
649    for flag, compound, desc in allFlags:
650        if not compound:
651            code("'$flag',")
652    code(']')
653    code.dedent()
654    code()
655
656    code('compound = [')
657    code.indent()
658    code("'All',")
659    for flag, compound, desc in allFlags:
660        if compound:
661            code("'$flag',")
662    code("]")
663    code.dedent()
664    code()
665
666    code("all = frozenset(basic + compound)")
667    code()
668
669    code('compoundMap = {')
670    code.indent()
671    all = tuple([flag for flag,compound,desc in allFlags if not compound])
672    code("'All' : $all,")
673    for flag, compound, desc in allFlags:
674        if compound:
675            code("'$flag' : $compound,")
676    code('}')
677    code.dedent()
678    code()
679
680    code('descriptions = {')
681    code.indent()
682    code("'All' : 'All flags',")
683    for flag, compound, desc in allFlags:
684        code("'$flag' : '$desc',")
685    code("}")
686    code.dedent()
687
688    code.write(str(target[0]))
689
690def traceFlagsCC(target, source, env):
691    assert(len(target) == 1)
692
693    allFlags = getFlags(source)
694    code = code_formatter()
695
696    # file header
697    code('''
698/*
699 * DO NOT EDIT THIS FILE! Automatically generated
700 */
701
702#include "base/traceflags.hh"
703
704using namespace Trace;
705
706const char *Trace::flagStrings[] =
707{''')
708
709    code.indent()
710    # The string array is used by SimpleEnumParam to map the strings
711    # provided by the user to enum values.
712    for flag, compound, desc in allFlags:
713        if not compound:
714            code('"$flag",')
715
716    code('"All",')
717    for flag, compound, desc in allFlags:
718        if compound:
719            code('"$flag",')
720    code.dedent()
721
722    code('''\
723};
724
725const int Trace::numFlagStrings = ${{len(allFlags) + 1}};
726
727''')
728
729    # Now define the individual compound flag arrays.  There is an array
730    # for each compound flag listing the component base flags.
731    all = tuple([flag for flag,compound,desc in allFlags if not compound])
732    code('static const Flags AllMap[] = {')
733    code.indent()
734    for flag, compound, desc in allFlags:
735        if not compound:
736            code('$flag,')
737    code.dedent()
738    code('};')
739    code()
740
741    for flag, compound, desc in allFlags:
742        if not compound:
743            continue
744        code('static const Flags ${flag}Map[] = {')
745        code.indent()
746        for flag in compound:
747            code('$flag,')
748        code('(Flags)-1')
749        code.dedent()
750        code('};')
751        code()
752
753    # Finally the compoundFlags[] array maps the compound flags
754    # to their individual arrays/
755    code('const Flags *Trace::compoundFlags[] = {')
756    code.indent()
757    code('AllMap,')
758    for flag, compound, desc in allFlags:
759        if compound:
760            code('${flag}Map,')
761    # file trailer
762    code.dedent()
763    code('};')
764
765    code.write(str(target[0]))
766
767def traceFlagsHH(target, source, env):
768    assert(len(target) == 1)
769
770    allFlags = getFlags(source)
771    code = code_formatter()
772
773    # file header boilerplate
774    code('''\
775/*
776 * DO NOT EDIT THIS FILE!
777 *
778 * Automatically generated from traceflags.py
779 */
780
781#ifndef __BASE_TRACE_FLAGS_HH__
782#define __BASE_TRACE_FLAGS_HH__
783
784namespace Trace {
785
786enum Flags {''')
787
788    # Generate the enum.  Base flags come first, then compound flags.
789    idx = 0
790    code.indent()
791    for flag, compound, desc in allFlags:
792        if not compound:
793            code('$flag = $idx,')
794            idx += 1
795
796    numBaseFlags = idx
797    code('NumFlags = $idx,')
798    code.dedent()
799    code()
800
801    # put a comment in here to separate base from compound flags
802    code('''
803// The remaining enum values are *not* valid indices for Trace::flags.
804// They are "compound" flags, which correspond to sets of base
805// flags, and are used by changeFlag.''')
806
807    code.indent()
808    code('All = $idx,')
809    idx += 1
810    for flag, compound, desc in allFlags:
811        if compound:
812            code('$flag = $idx,')
813            idx += 1
814
815    numCompoundFlags = idx - numBaseFlags
816    code('NumCompoundFlags = $numCompoundFlags')
817    code.dedent()
818
819    # trailer boilerplate
820    code('''\
821}; // enum Flags
822
823// Array of strings for SimpleEnumParam
824extern const char *flagStrings[];
825extern const int numFlagStrings;
826
827// Array of arraay pointers: for each compound flag, gives the list of
828// base flags to set.  Inidividual flag arrays are terminated by -1.
829extern const Flags *compoundFlags[];
830
831/* namespace Trace */ }
832
833#endif // __BASE_TRACE_FLAGS_HH__
834''')
835
836    code.write(str(target[0]))
837
838flags = map(Value, trace_flags.values())
839env.Command('base/traceflags.py', flags, traceFlagsPy)
840PySource('m5', 'base/traceflags.py')
841
842env.Command('base/traceflags.hh', flags, traceFlagsHH)
843env.Command('base/traceflags.cc', flags, traceFlagsCC)
844Source('base/traceflags.cc')
845
846# Embed python files.  All .py files that have been indicated by a
847# PySource() call in a SConscript need to be embedded into the M5
848# library.  To do that, we compile the file to byte code, marshal the
849# byte code, compress it, and then generate a c++ file that
850# inserts the result into an array.
851def embedPyFile(target, source, env):
852    def c_str(string):
853        if string is None:
854            return "0"
855        return '"%s"' % string
856
857    '''Action function to compile a .py into a code object, marshal
858    it, compress it, and stick it into an asm file so the code appears
859    as just bytes with a label in the data section'''
860
861    src = file(str(source[0]), 'r').read()
862
863    pysource = PySource.tnodes[source[0]]
864    compiled = compile(src, pysource.abspath, 'exec')
865    marshalled = marshal.dumps(compiled)
866    compressed = zlib.compress(marshalled)
867    data = compressed
868    sym = pysource.symname
869
870    code = code_formatter()
871    code('''\
872#include "sim/init.hh"
873
874namespace {
875
876const char data_${sym}[] = {
877''')
878    code.indent()
879    step = 16
880    for i in xrange(0, len(data), step):
881        x = array.array('B', data[i:i+step])
882        code(''.join('%d,' % d for d in x))
883    code.dedent()
884    
885    code('''};
886
887EmbeddedPython embedded_${sym}(
888    ${{c_str(pysource.arcname)}},
889    ${{c_str(pysource.abspath)}},
890    ${{c_str(pysource.modpath)}},
891    data_${sym},
892    ${{len(data)}},
893    ${{len(marshalled)}});
894
895/* namespace */ }
896''')
897    code.write(str(target[0]))
898
899for source in PySource.all:
900    env.Command(source.cpp, source.tnode, embedPyFile)
901    Source(source.cpp)
902
903########################################################################
904#
905# Define binaries.  Each different build type (debug, opt, etc.) gets
906# a slightly different build environment.
907#
908
909# List of constructed environments to pass back to SConstruct
910envList = []
911
912date_source = Source('base/date.cc', skip_lib=True)
913
914# Function to create a new build environment as clone of current
915# environment 'env' with modified object suffix and optional stripped
916# binary.  Additional keyword arguments are appended to corresponding
917# build environment vars.
918def makeEnv(label, objsfx, strip = False, **kwargs):
919    # SCons doesn't know to append a library suffix when there is a '.' in the
920    # name.  Use '_' instead.
921    libname = 'm5_' + label
922    exename = 'm5.' + label
923
924    new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
925    new_env.Label = label
926    new_env.Append(**kwargs)
927
928    swig_env = new_env.Clone()
929    swig_env.Append(CCFLAGS='-Werror')
930    if env['GCC']:
931        swig_env.Append(CCFLAGS='-Wno-uninitialized')
932        swig_env.Append(CCFLAGS='-Wno-sign-compare')
933        swig_env.Append(CCFLAGS='-Wno-parentheses')
934
935    werror_env = new_env.Clone()
936    werror_env.Append(CCFLAGS='-Werror')
937
938    def make_obj(source, static, extra_deps = None):
939        '''This function adds the specified source to the correct
940        build environment, and returns the corresponding SCons Object
941        nodes'''
942
943        if source.swig:
944            env = swig_env
945        elif source.Werror:
946            env = werror_env
947        else:
948            env = new_env
949
950        if static:
951            obj = env.StaticObject(source.tnode)
952        else:
953            obj = env.SharedObject(source.tnode)
954
955        if extra_deps:
956            env.Depends(obj, extra_deps)
957
958        return obj
959
960    static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)]
961    shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)]
962
963    static_date = make_obj(date_source, static=True, extra_deps=static_objs)
964    static_objs.append(static_date)
965    
966    shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
967    shared_objs.append(shared_date)
968
969    # First make a library of everything but main() so other programs can
970    # link against m5.
971    static_lib = new_env.StaticLibrary(libname, static_objs)
972    shared_lib = new_env.SharedLibrary(libname, shared_objs)
973
974    for target, sources in unit_tests:
975        objs = [ make_obj(s, static=True) for s in sources ]
976        new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs)
977
978    # Now link a stub with main() and the static library.
979    bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ]
980    progname = exename
981    if strip:
982        progname += '.unstripped'
983
984    targets = new_env.Program(progname, bin_objs + static_objs)
985
986    if strip:
987        if sys.platform == 'sunos5':
988            cmd = 'cp $SOURCE $TARGET; strip $TARGET'
989        else:
990            cmd = 'strip $SOURCE -o $TARGET'
991        targets = new_env.Command(exename, progname, cmd)
992            
993    new_env.M5Binary = targets[0]
994    envList.append(new_env)
995
996# Debug binary
997ccflags = {}
998if env['GCC']:
999    if sys.platform == 'sunos5':
1000        ccflags['debug'] = '-gstabs+'
1001    else:
1002        ccflags['debug'] = '-ggdb3'
1003    ccflags['opt'] = '-g -O3'
1004    ccflags['fast'] = '-O3'
1005    ccflags['prof'] = '-O3 -g -pg'
1006elif env['SUNCC']:
1007    ccflags['debug'] = '-g0'
1008    ccflags['opt'] = '-g -O'
1009    ccflags['fast'] = '-fast'
1010    ccflags['prof'] = '-fast -g -pg'
1011elif env['ICC']:
1012    ccflags['debug'] = '-g -O0'
1013    ccflags['opt'] = '-g -O'
1014    ccflags['fast'] = '-fast'
1015    ccflags['prof'] = '-fast -g -pg'
1016else:
1017    print 'Unknown compiler, please fix compiler options'
1018    Exit(1)
1019
1020makeEnv('debug', '.do',
1021        CCFLAGS = Split(ccflags['debug']),
1022        CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1023
1024# Optimized binary
1025makeEnv('opt', '.o',
1026        CCFLAGS = Split(ccflags['opt']),
1027        CPPDEFINES = ['TRACING_ON=1'])
1028
1029# "Fast" binary
1030makeEnv('fast', '.fo', strip = True,
1031        CCFLAGS = Split(ccflags['fast']),
1032        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1033
1034# Profiled binary
1035makeEnv('prof', '.po',
1036        CCFLAGS = Split(ccflags['prof']),
1037        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1038        LINKFLAGS = '-pg')
1039
1040Return('envList')
1041