SConscript revision 12305:b6ebf3d20329
110260SAndrew.Bardsley@arm.com# -*- mode:python -*-
210260SAndrew.Bardsley@arm.com
310260SAndrew.Bardsley@arm.com# Copyright (c) 2004-2005 The Regents of The University of Michigan
410260SAndrew.Bardsley@arm.com# All rights reserved.
510260SAndrew.Bardsley@arm.com#
610260SAndrew.Bardsley@arm.com# Redistribution and use in source and binary forms, with or without
710260SAndrew.Bardsley@arm.com# modification, are permitted provided that the following conditions are
810260SAndrew.Bardsley@arm.com# met: redistributions of source code must retain the above copyright
910260SAndrew.Bardsley@arm.com# notice, this list of conditions and the following disclaimer;
1010260SAndrew.Bardsley@arm.com# redistributions in binary form must reproduce the above copyright
1110260SAndrew.Bardsley@arm.com# notice, this list of conditions and the following disclaimer in the
1210260SAndrew.Bardsley@arm.com# documentation and/or other materials provided with the distribution;
1310260SAndrew.Bardsley@arm.com# neither the name of the copyright holders nor the names of its
1410260SAndrew.Bardsley@arm.com# contributors may be used to endorse or promote products derived from
1510260SAndrew.Bardsley@arm.com# this software without specific prior written permission.
1610260SAndrew.Bardsley@arm.com#
1710260SAndrew.Bardsley@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1810260SAndrew.Bardsley@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1910260SAndrew.Bardsley@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2010260SAndrew.Bardsley@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2110260SAndrew.Bardsley@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2210260SAndrew.Bardsley@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2310260SAndrew.Bardsley@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2410260SAndrew.Bardsley@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2510260SAndrew.Bardsley@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2610260SAndrew.Bardsley@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2710260SAndrew.Bardsley@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2810260SAndrew.Bardsley@arm.com#
2910260SAndrew.Bardsley@arm.com# Authors: Nathan Binkert
3010260SAndrew.Bardsley@arm.com
3110260SAndrew.Bardsley@arm.comimport array
3210260SAndrew.Bardsley@arm.comimport bisect
3310260SAndrew.Bardsley@arm.comimport imp
3410260SAndrew.Bardsley@arm.comimport marshal
3510260SAndrew.Bardsley@arm.comimport os
3610260SAndrew.Bardsley@arm.comimport re
3710260SAndrew.Bardsley@arm.comimport subprocess
3810260SAndrew.Bardsley@arm.comimport sys
3910260SAndrew.Bardsley@arm.comimport zlib
4010260SAndrew.Bardsley@arm.com
4110260SAndrew.Bardsley@arm.comfrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath
4210260SAndrew.Bardsley@arm.com
4310260SAndrew.Bardsley@arm.comimport SCons
4410260SAndrew.Bardsley@arm.com
4510260SAndrew.Bardsley@arm.comfrom gem5_scons import Transform
4610260SAndrew.Bardsley@arm.com
4710260SAndrew.Bardsley@arm.com# This file defines how to build a particular configuration of gem5
4810260SAndrew.Bardsley@arm.com# based on variable settings in the 'env' build environment.
4910260SAndrew.Bardsley@arm.com
5010260SAndrew.Bardsley@arm.comImport('*')
5110260SAndrew.Bardsley@arm.com
5210260SAndrew.Bardsley@arm.com# Children need to see the environment
5310260SAndrew.Bardsley@arm.comExport('env')
5410260SAndrew.Bardsley@arm.com
5510260SAndrew.Bardsley@arm.combuild_env = [(opt, env[opt]) for opt in export_vars]
5610260SAndrew.Bardsley@arm.com
5710260SAndrew.Bardsley@arm.comfrom m5.util import code_formatter, compareVersions
5810260SAndrew.Bardsley@arm.com
5910260SAndrew.Bardsley@arm.com########################################################################
6010260SAndrew.Bardsley@arm.com# Code for adding source files of various types
6110260SAndrew.Bardsley@arm.com#
6210260SAndrew.Bardsley@arm.com# When specifying a source file of some type, a set of tags can be
6310260SAndrew.Bardsley@arm.com# specified for that file.
6410260SAndrew.Bardsley@arm.com
6510260SAndrew.Bardsley@arm.comclass SourceList(list):
6610260SAndrew.Bardsley@arm.com    def with_tags_that(self, predicate):
6710260SAndrew.Bardsley@arm.com        '''Return a list of sources with tags that satisfy a predicate.'''
6810260SAndrew.Bardsley@arm.com        def match(source):
6910260SAndrew.Bardsley@arm.com            return predicate(source.tags)
7010260SAndrew.Bardsley@arm.com        return SourceList(filter(match, self))
7110260SAndrew.Bardsley@arm.com
7210260SAndrew.Bardsley@arm.com    def with_any_tags(self, *tags):
7310260SAndrew.Bardsley@arm.com        '''Return a list of sources with any of the supplied tags.'''
7410260SAndrew.Bardsley@arm.com        return self.with_tags_that(lambda stags: len(tags & stags) > 0)
7510260SAndrew.Bardsley@arm.com
7610260SAndrew.Bardsley@arm.com    def with_all_tags(self, *tags):
7710260SAndrew.Bardsley@arm.com        '''Return a list of sources with all of the supplied tags.'''
7810260SAndrew.Bardsley@arm.com        return self.with_tags_that(lambda stags: tags <= stags)
7910260SAndrew.Bardsley@arm.com
8010260SAndrew.Bardsley@arm.com    def with_tag(self, tag):
8110260SAndrew.Bardsley@arm.com        '''Return a list of sources with the supplied tag.'''
8210260SAndrew.Bardsley@arm.com        return self.with_tags_that(lambda stags: tag in stags)
8310260SAndrew.Bardsley@arm.com
8410260SAndrew.Bardsley@arm.com    def without_tags(self, *tags):
8510260SAndrew.Bardsley@arm.com        '''Return a list of sources without any of the supplied tags.'''
8610260SAndrew.Bardsley@arm.com        return self.with_tags_that(lambda stags: len(tags & stags) == 0)
8710260SAndrew.Bardsley@arm.com
8810260SAndrew.Bardsley@arm.com    def without_tag(self, tag):
8910260SAndrew.Bardsley@arm.com        '''Return a list of sources with the supplied tag.'''
9010260SAndrew.Bardsley@arm.com        return self.with_tags_that(lambda stags: tag not in stags)
9110260SAndrew.Bardsley@arm.com
9210260SAndrew.Bardsley@arm.comclass SourceMeta(type):
9310260SAndrew.Bardsley@arm.com    '''Meta class for source files that keeps track of all files of a
9410260SAndrew.Bardsley@arm.com    particular type.'''
9510260SAndrew.Bardsley@arm.com    def __init__(cls, name, bases, dict):
9610260SAndrew.Bardsley@arm.com        super(SourceMeta, cls).__init__(name, bases, dict)
9710260SAndrew.Bardsley@arm.com        cls.all = SourceList()
9810260SAndrew.Bardsley@arm.com
9910260SAndrew.Bardsley@arm.comclass SourceFile(object):
10010260SAndrew.Bardsley@arm.com    '''Base object that encapsulates the notion of a source file.
10110260SAndrew.Bardsley@arm.com    This includes, the source node, target node, various manipulations
10210260SAndrew.Bardsley@arm.com    of those.  A source file also specifies a set of tags which
10310260SAndrew.Bardsley@arm.com    describing arbitrary properties of the source file.'''
10410260SAndrew.Bardsley@arm.com    __metaclass__ = SourceMeta
10510260SAndrew.Bardsley@arm.com    def __init__(self, source, tags=None, add_tags=None):
10610260SAndrew.Bardsley@arm.com        if tags is None:
10710260SAndrew.Bardsley@arm.com            tags='gem5 lib'
10810260SAndrew.Bardsley@arm.com        if isinstance(tags, basestring):
10910260SAndrew.Bardsley@arm.com            tags = set([tags])
11010260SAndrew.Bardsley@arm.com        if isinstance(add_tags, basestring):
11110260SAndrew.Bardsley@arm.com            add_tags = set([add_tags])
11210260SAndrew.Bardsley@arm.com        if add_tags:
11310260SAndrew.Bardsley@arm.com            tags = tags | add_tags
11410260SAndrew.Bardsley@arm.com        self.tags = set(tags)
11510260SAndrew.Bardsley@arm.com
11610260SAndrew.Bardsley@arm.com        tnode = source
11710260SAndrew.Bardsley@arm.com        if not isinstance(source, SCons.Node.FS.File):
11810260SAndrew.Bardsley@arm.com            tnode = File(source)
11910260SAndrew.Bardsley@arm.com
12010260SAndrew.Bardsley@arm.com        self.tnode = tnode
12110260SAndrew.Bardsley@arm.com        self.snode = tnode.srcnode()
12210260SAndrew.Bardsley@arm.com
12310260SAndrew.Bardsley@arm.com        for base in type(self).__mro__:
12410260SAndrew.Bardsley@arm.com            if issubclass(base, SourceFile):
12510260SAndrew.Bardsley@arm.com                base.all.append(self)
12610260SAndrew.Bardsley@arm.com
12710260SAndrew.Bardsley@arm.com    @property
12810260SAndrew.Bardsley@arm.com    def filename(self):
12910260SAndrew.Bardsley@arm.com        return str(self.tnode)
13010260SAndrew.Bardsley@arm.com
13110260SAndrew.Bardsley@arm.com    @property
13210260SAndrew.Bardsley@arm.com    def dirname(self):
13310260SAndrew.Bardsley@arm.com        return dirname(self.filename)
13410260SAndrew.Bardsley@arm.com
13510260SAndrew.Bardsley@arm.com    @property
13610260SAndrew.Bardsley@arm.com    def basename(self):
13710260SAndrew.Bardsley@arm.com        return basename(self.filename)
13810260SAndrew.Bardsley@arm.com
13910260SAndrew.Bardsley@arm.com    @property
14010260SAndrew.Bardsley@arm.com    def extname(self):
14110260SAndrew.Bardsley@arm.com        index = self.basename.rfind('.')
14210260SAndrew.Bardsley@arm.com        if index <= 0:
14310260SAndrew.Bardsley@arm.com            # dot files aren't extensions
14410260SAndrew.Bardsley@arm.com            return self.basename, None
14510260SAndrew.Bardsley@arm.com
14610260SAndrew.Bardsley@arm.com        return self.basename[:index], self.basename[index+1:]
14710260SAndrew.Bardsley@arm.com
14810260SAndrew.Bardsley@arm.com    def __lt__(self, other): return self.filename < other.filename
14910260SAndrew.Bardsley@arm.com    def __le__(self, other): return self.filename <= other.filename
15010260SAndrew.Bardsley@arm.com    def __gt__(self, other): return self.filename > other.filename
15110260SAndrew.Bardsley@arm.com    def __ge__(self, other): return self.filename >= other.filename
15210260SAndrew.Bardsley@arm.com    def __eq__(self, other): return self.filename == other.filename
15310260SAndrew.Bardsley@arm.com    def __ne__(self, other): return self.filename != other.filename
15410260SAndrew.Bardsley@arm.com
15510260SAndrew.Bardsley@arm.comclass Source(SourceFile):
15610260SAndrew.Bardsley@arm.com    ungrouped_tag = 'No link group'
15710260SAndrew.Bardsley@arm.com    source_groups = set()
15810260SAndrew.Bardsley@arm.com
15910260SAndrew.Bardsley@arm.com    _current_group_tag = ungrouped_tag
16010260SAndrew.Bardsley@arm.com
16110260SAndrew.Bardsley@arm.com    @staticmethod
16210260SAndrew.Bardsley@arm.com    def link_group_tag(group):
16310260SAndrew.Bardsley@arm.com        return 'link group: %s' % group
16410260SAndrew.Bardsley@arm.com
16510260SAndrew.Bardsley@arm.com    @classmethod
16610260SAndrew.Bardsley@arm.com    def set_group(cls, group):
16710260SAndrew.Bardsley@arm.com        new_tag = Source.link_group_tag(group)
16810260SAndrew.Bardsley@arm.com        Source._current_group_tag = new_tag
16910260SAndrew.Bardsley@arm.com        Source.source_groups.add(group)
17010260SAndrew.Bardsley@arm.com
17110260SAndrew.Bardsley@arm.com    def _add_link_group_tag(self):
17210260SAndrew.Bardsley@arm.com        self.tags.add(Source._current_group_tag)
17310260SAndrew.Bardsley@arm.com
17410260SAndrew.Bardsley@arm.com    '''Add a c/c++ source file to the build'''
17510260SAndrew.Bardsley@arm.com    def __init__(self, source, tags=None, add_tags=None):
17610260SAndrew.Bardsley@arm.com        '''specify the source file, and any tags'''
17710260SAndrew.Bardsley@arm.com        super(Source, self).__init__(source, tags, add_tags)
17810260SAndrew.Bardsley@arm.com        self._add_link_group_tag()
17910260SAndrew.Bardsley@arm.com
18010260SAndrew.Bardsley@arm.comclass PySource(SourceFile):
18110260SAndrew.Bardsley@arm.com    '''Add a python source file to the named package'''
18210260SAndrew.Bardsley@arm.com    invalid_sym_char = re.compile('[^A-z0-9_]')
18310260SAndrew.Bardsley@arm.com    modules = {}
18410260SAndrew.Bardsley@arm.com    tnodes = {}
18510260SAndrew.Bardsley@arm.com    symnames = {}
18610260SAndrew.Bardsley@arm.com
18710260SAndrew.Bardsley@arm.com    def __init__(self, package, source, tags=None, add_tags=None):
18810260SAndrew.Bardsley@arm.com        '''specify the python package, the source file, and any tags'''
18910260SAndrew.Bardsley@arm.com        super(PySource, self).__init__(source, tags, add_tags)
19010260SAndrew.Bardsley@arm.com
19110260SAndrew.Bardsley@arm.com        modname,ext = self.extname
19210260SAndrew.Bardsley@arm.com        assert ext == 'py'
19310260SAndrew.Bardsley@arm.com
19410260SAndrew.Bardsley@arm.com        if package:
19510260SAndrew.Bardsley@arm.com            path = package.split('.')
19610260SAndrew.Bardsley@arm.com        else:
19710260SAndrew.Bardsley@arm.com            path = []
19810260SAndrew.Bardsley@arm.com
19910260SAndrew.Bardsley@arm.com        modpath = path[:]
20010260SAndrew.Bardsley@arm.com        if modname != '__init__':
20110260SAndrew.Bardsley@arm.com            modpath += [ modname ]
20210260SAndrew.Bardsley@arm.com        modpath = '.'.join(modpath)
20310260SAndrew.Bardsley@arm.com
20410260SAndrew.Bardsley@arm.com        arcpath = path + [ self.basename ]
20510260SAndrew.Bardsley@arm.com        abspath = self.snode.abspath
20610260SAndrew.Bardsley@arm.com        if not exists(abspath):
20710260SAndrew.Bardsley@arm.com            abspath = self.tnode.abspath
20810260SAndrew.Bardsley@arm.com
20910260SAndrew.Bardsley@arm.com        self.package = package
21010260SAndrew.Bardsley@arm.com        self.modname = modname
21110260SAndrew.Bardsley@arm.com        self.modpath = modpath
21210260SAndrew.Bardsley@arm.com        self.arcname = joinpath(*arcpath)
21310260SAndrew.Bardsley@arm.com        self.abspath = abspath
21410260SAndrew.Bardsley@arm.com        self.compiled = File(self.filename + 'c')
21510260SAndrew.Bardsley@arm.com        self.cpp = File(self.filename + '.cc')
21610260SAndrew.Bardsley@arm.com        self.symname = PySource.invalid_sym_char.sub('_', modpath)
21710260SAndrew.Bardsley@arm.com
21810260SAndrew.Bardsley@arm.com        PySource.modules[modpath] = self
21910260SAndrew.Bardsley@arm.com        PySource.tnodes[self.tnode] = self
22010260SAndrew.Bardsley@arm.com        PySource.symnames[self.symname] = self
22110260SAndrew.Bardsley@arm.com
22210260SAndrew.Bardsley@arm.comclass SimObject(PySource):
22310260SAndrew.Bardsley@arm.com    '''Add a SimObject python file as a python source object and add
22410260SAndrew.Bardsley@arm.com    it to a list of sim object modules'''
22510260SAndrew.Bardsley@arm.com
22610260SAndrew.Bardsley@arm.com    fixed = False
22710260SAndrew.Bardsley@arm.com    modnames = []
22810260SAndrew.Bardsley@arm.com
22910260SAndrew.Bardsley@arm.com    def __init__(self, source, tags=None, add_tags=None):
23010260SAndrew.Bardsley@arm.com        '''Specify the source file and any tags (automatically in
23110260SAndrew.Bardsley@arm.com        the m5.objects package)'''
23210260SAndrew.Bardsley@arm.com        super(SimObject, self).__init__('m5.objects', source, tags, add_tags)
23310260SAndrew.Bardsley@arm.com        if self.fixed:
23410260SAndrew.Bardsley@arm.com            raise AttributeError, "Too late to call SimObject now."
23510260SAndrew.Bardsley@arm.com
23610260SAndrew.Bardsley@arm.com        bisect.insort_right(SimObject.modnames, self.modname)
23710260SAndrew.Bardsley@arm.com
23810260SAndrew.Bardsley@arm.comclass ProtoBuf(SourceFile):
23910260SAndrew.Bardsley@arm.com    '''Add a Protocol Buffer to build'''
24010260SAndrew.Bardsley@arm.com
24110260SAndrew.Bardsley@arm.com    def __init__(self, source, tags=None, add_tags=None):
24210260SAndrew.Bardsley@arm.com        '''Specify the source file, and any tags'''
24310260SAndrew.Bardsley@arm.com        super(ProtoBuf, self).__init__(source, tags, add_tags)
24410260SAndrew.Bardsley@arm.com
24510260SAndrew.Bardsley@arm.com        # Get the file name and the extension
24610260SAndrew.Bardsley@arm.com        modname,ext = self.extname
24710260SAndrew.Bardsley@arm.com        assert ext == 'proto'
24810260SAndrew.Bardsley@arm.com
24910260SAndrew.Bardsley@arm.com        # Currently, we stick to generating the C++ headers, so we
25010260SAndrew.Bardsley@arm.com        # only need to track the source and header.
25110260SAndrew.Bardsley@arm.com        self.cc_file = File(modname + '.pb.cc')
25210260SAndrew.Bardsley@arm.com        self.hh_file = File(modname + '.pb.h')
25310260SAndrew.Bardsley@arm.com
25410260SAndrew.Bardsley@arm.comclass UnitTest(object):
25510260SAndrew.Bardsley@arm.com    '''Create a UnitTest'''
25610260SAndrew.Bardsley@arm.com
25710260SAndrew.Bardsley@arm.com    all = []
25810260SAndrew.Bardsley@arm.com    def __init__(self, target, *sources, **kwargs):
25910260SAndrew.Bardsley@arm.com        '''Specify the target name and any sources.  Sources that are
26010260SAndrew.Bardsley@arm.com        not SourceFiles are evalued with Source().  All files are
26110260SAndrew.Bardsley@arm.com        tagged with the name of the UnitTest target.'''
26210260SAndrew.Bardsley@arm.com
26310260SAndrew.Bardsley@arm.com        srcs = SourceList()
26410260SAndrew.Bardsley@arm.com        for src in sources:
26510260SAndrew.Bardsley@arm.com            if not isinstance(src, SourceFile):
26610260SAndrew.Bardsley@arm.com                src = Source(src, tags=str(target))
26710260SAndrew.Bardsley@arm.com            srcs.append(src)
26810260SAndrew.Bardsley@arm.com
26910260SAndrew.Bardsley@arm.com        self.sources = srcs
27010260SAndrew.Bardsley@arm.com        self.target = target
27110260SAndrew.Bardsley@arm.com        self.main = kwargs.get('main', False)
27210260SAndrew.Bardsley@arm.com        UnitTest.all.append(self)
27310260SAndrew.Bardsley@arm.com
27410260SAndrew.Bardsley@arm.com# Children should have access
27510260SAndrew.Bardsley@arm.comExport('Source')
27610260SAndrew.Bardsley@arm.comExport('PySource')
27710260SAndrew.Bardsley@arm.comExport('SimObject')
27810260SAndrew.Bardsley@arm.comExport('ProtoBuf')
27910260SAndrew.Bardsley@arm.comExport('UnitTest')
28010260SAndrew.Bardsley@arm.com
28110260SAndrew.Bardsley@arm.com########################################################################
28210260SAndrew.Bardsley@arm.com#
28310260SAndrew.Bardsley@arm.com# Debug Flags
28410260SAndrew.Bardsley@arm.com#
28510260SAndrew.Bardsley@arm.comdebug_flags = {}
28610260SAndrew.Bardsley@arm.comdef DebugFlag(name, desc=None):
28710260SAndrew.Bardsley@arm.com    if name in debug_flags:
28810260SAndrew.Bardsley@arm.com        raise AttributeError, "Flag %s already specified" % name
28910260SAndrew.Bardsley@arm.com    debug_flags[name] = (name, (), desc)
29010260SAndrew.Bardsley@arm.com
29110260SAndrew.Bardsley@arm.comdef CompoundFlag(name, flags, desc=None):
29210260SAndrew.Bardsley@arm.com    if name in debug_flags:
29310260SAndrew.Bardsley@arm.com        raise AttributeError, "Flag %s already specified" % name
29410260SAndrew.Bardsley@arm.com
29510260SAndrew.Bardsley@arm.com    compound = tuple(flags)
29610260SAndrew.Bardsley@arm.com    debug_flags[name] = (name, compound, desc)
29710260SAndrew.Bardsley@arm.com
29810260SAndrew.Bardsley@arm.comExport('DebugFlag')
29910260SAndrew.Bardsley@arm.comExport('CompoundFlag')
30010260SAndrew.Bardsley@arm.com
30110260SAndrew.Bardsley@arm.com########################################################################
30210260SAndrew.Bardsley@arm.com#
30310260SAndrew.Bardsley@arm.com# Set some compiler variables
30410260SAndrew.Bardsley@arm.com#
30510260SAndrew.Bardsley@arm.com
30610260SAndrew.Bardsley@arm.com# Include file paths are rooted in this directory.  SCons will
30710260SAndrew.Bardsley@arm.com# automatically expand '.' to refer to both the source directory and
30810260SAndrew.Bardsley@arm.com# the corresponding build directory to pick up generated include
30910260SAndrew.Bardsley@arm.com# files.
31010260SAndrew.Bardsley@arm.comenv.Append(CPPPATH=Dir('.'))
31110260SAndrew.Bardsley@arm.com
31210260SAndrew.Bardsley@arm.comfor extra_dir in extras_dir_list:
31310260SAndrew.Bardsley@arm.com    env.Append(CPPPATH=Dir(extra_dir))
31410260SAndrew.Bardsley@arm.com
31510260SAndrew.Bardsley@arm.com# Workaround for bug in SCons version > 0.97d20071212
31610260SAndrew.Bardsley@arm.com# Scons bug id: 2006 gem5 Bug id: 308
31710260SAndrew.Bardsley@arm.comfor root, dirs, files in os.walk(base_dir, topdown=True):
31810260SAndrew.Bardsley@arm.com    Dir(root[len(base_dir) + 1:])
31910260SAndrew.Bardsley@arm.com
32010260SAndrew.Bardsley@arm.com########################################################################
32110260SAndrew.Bardsley@arm.com#
32210260SAndrew.Bardsley@arm.com# Walk the tree and execute all SConscripts in subdirectories
32310260SAndrew.Bardsley@arm.com#
32410260SAndrew.Bardsley@arm.com
32510260SAndrew.Bardsley@arm.comhere = Dir('.').srcnode().abspath
32610260SAndrew.Bardsley@arm.comfor root, dirs, files in os.walk(base_dir, topdown=True):
32710260SAndrew.Bardsley@arm.com    if root == here:
32810260SAndrew.Bardsley@arm.com        # we don't want to recurse back into this SConscript
32910260SAndrew.Bardsley@arm.com        continue
33010260SAndrew.Bardsley@arm.com
33110260SAndrew.Bardsley@arm.com    if 'SConscript' in files:
33210260SAndrew.Bardsley@arm.com        build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
33310260SAndrew.Bardsley@arm.com        Source.set_group(build_dir)
33410260SAndrew.Bardsley@arm.com        SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
33510260SAndrew.Bardsley@arm.com
33610260SAndrew.Bardsley@arm.comfor extra_dir in extras_dir_list:
33710260SAndrew.Bardsley@arm.com    prefix_len = len(dirname(extra_dir)) + 1
33810260SAndrew.Bardsley@arm.com
33910260SAndrew.Bardsley@arm.com    # Also add the corresponding build directory to pick up generated
34010260SAndrew.Bardsley@arm.com    # include files.
34110260SAndrew.Bardsley@arm.com    env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:])))
34210260SAndrew.Bardsley@arm.com
34310260SAndrew.Bardsley@arm.com    for root, dirs, files in os.walk(extra_dir, topdown=True):
34410260SAndrew.Bardsley@arm.com        # if build lives in the extras directory, don't walk down it
34510260SAndrew.Bardsley@arm.com        if 'build' in dirs:
34610260SAndrew.Bardsley@arm.com            dirs.remove('build')
34710260SAndrew.Bardsley@arm.com
34810260SAndrew.Bardsley@arm.com        if 'SConscript' in files:
34910260SAndrew.Bardsley@arm.com            build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
35010260SAndrew.Bardsley@arm.com            SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
35110260SAndrew.Bardsley@arm.com
35210260SAndrew.Bardsley@arm.comfor opt in export_vars:
35310260SAndrew.Bardsley@arm.com    env.ConfigFile(opt)
35410260SAndrew.Bardsley@arm.com
35510260SAndrew.Bardsley@arm.comdef makeTheISA(source, target, env):
35610260SAndrew.Bardsley@arm.com    isas = [ src.get_contents() for src in source ]
35710260SAndrew.Bardsley@arm.com    target_isa = env['TARGET_ISA']
35810260SAndrew.Bardsley@arm.com    def define(isa):
35910260SAndrew.Bardsley@arm.com        return isa.upper() + '_ISA'
36010260SAndrew.Bardsley@arm.com
36110260SAndrew.Bardsley@arm.com    def namespace(isa):
36210260SAndrew.Bardsley@arm.com        return isa[0].upper() + isa[1:].lower() + 'ISA'
36310260SAndrew.Bardsley@arm.com
36410260SAndrew.Bardsley@arm.com
36510260SAndrew.Bardsley@arm.com    code = code_formatter()
36610260SAndrew.Bardsley@arm.com    code('''\
36710260SAndrew.Bardsley@arm.com#ifndef __CONFIG_THE_ISA_HH__
36810260SAndrew.Bardsley@arm.com#define __CONFIG_THE_ISA_HH__
36910260SAndrew.Bardsley@arm.com
37010260SAndrew.Bardsley@arm.com''')
37110260SAndrew.Bardsley@arm.com
37210260SAndrew.Bardsley@arm.com    # create defines for the preprocessing and compile-time determination
37310260SAndrew.Bardsley@arm.com    for i,isa in enumerate(isas):
37410260SAndrew.Bardsley@arm.com        code('#define $0 $1', define(isa), i + 1)
37510260SAndrew.Bardsley@arm.com    code()
37610260SAndrew.Bardsley@arm.com
37710260SAndrew.Bardsley@arm.com    # create an enum for any run-time determination of the ISA, we
37810260SAndrew.Bardsley@arm.com    # reuse the same name as the namespaces
37910260SAndrew.Bardsley@arm.com    code('enum class Arch {')
38010260SAndrew.Bardsley@arm.com    for i,isa in enumerate(isas):
38110260SAndrew.Bardsley@arm.com        if i + 1 == len(isas):
38210260SAndrew.Bardsley@arm.com            code('  $0 = $1', namespace(isa), define(isa))
38310260SAndrew.Bardsley@arm.com        else:
38410260SAndrew.Bardsley@arm.com            code('  $0 = $1,', namespace(isa), define(isa))
38510260SAndrew.Bardsley@arm.com    code('};')
38610260SAndrew.Bardsley@arm.com
38710260SAndrew.Bardsley@arm.com    code('''
38810260SAndrew.Bardsley@arm.com
38910260SAndrew.Bardsley@arm.com#define THE_ISA ${{define(target_isa)}}
39010260SAndrew.Bardsley@arm.com#define TheISA ${{namespace(target_isa)}}
39110260SAndrew.Bardsley@arm.com#define THE_ISA_STR "${{target_isa}}"
39210260SAndrew.Bardsley@arm.com
39310260SAndrew.Bardsley@arm.com#endif // __CONFIG_THE_ISA_HH__''')
39410260SAndrew.Bardsley@arm.com
39510260SAndrew.Bardsley@arm.com    code.write(str(target[0]))
39610260SAndrew.Bardsley@arm.com
39710260SAndrew.Bardsley@arm.comenv.Command('config/the_isa.hh', map(Value, all_isa_list),
39810260SAndrew.Bardsley@arm.com            MakeAction(makeTheISA, Transform("CFG ISA", 0)))
39910260SAndrew.Bardsley@arm.com
40010260SAndrew.Bardsley@arm.comdef makeTheGPUISA(source, target, env):
40110260SAndrew.Bardsley@arm.com    isas = [ src.get_contents() for src in source ]
40210260SAndrew.Bardsley@arm.com    target_gpu_isa = env['TARGET_GPU_ISA']
40310260SAndrew.Bardsley@arm.com    def define(isa):
40410260SAndrew.Bardsley@arm.com        return isa.upper() + '_ISA'
40510260SAndrew.Bardsley@arm.com
40610260SAndrew.Bardsley@arm.com    def namespace(isa):
40710260SAndrew.Bardsley@arm.com        return isa[0].upper() + isa[1:].lower() + 'ISA'
40810260SAndrew.Bardsley@arm.com
40910260SAndrew.Bardsley@arm.com
41010260SAndrew.Bardsley@arm.com    code = code_formatter()
41110260SAndrew.Bardsley@arm.com    code('''\
41210260SAndrew.Bardsley@arm.com#ifndef __CONFIG_THE_GPU_ISA_HH__
41310260SAndrew.Bardsley@arm.com#define __CONFIG_THE_GPU_ISA_HH__
41410260SAndrew.Bardsley@arm.com
41510260SAndrew.Bardsley@arm.com''')
41610260SAndrew.Bardsley@arm.com
41710260SAndrew.Bardsley@arm.com    # create defines for the preprocessing and compile-time determination
41810260SAndrew.Bardsley@arm.com    for i,isa in enumerate(isas):
41910260SAndrew.Bardsley@arm.com        code('#define $0 $1', define(isa), i + 1)
42010260SAndrew.Bardsley@arm.com    code()
42110260SAndrew.Bardsley@arm.com
42210260SAndrew.Bardsley@arm.com    # create an enum for any run-time determination of the ISA, we
42310260SAndrew.Bardsley@arm.com    # reuse the same name as the namespaces
42410260SAndrew.Bardsley@arm.com    code('enum class GPUArch {')
42510260SAndrew.Bardsley@arm.com    for i,isa in enumerate(isas):
42610260SAndrew.Bardsley@arm.com        if i + 1 == len(isas):
42710260SAndrew.Bardsley@arm.com            code('  $0 = $1', namespace(isa), define(isa))
42810260SAndrew.Bardsley@arm.com        else:
42910260SAndrew.Bardsley@arm.com            code('  $0 = $1,', namespace(isa), define(isa))
43010260SAndrew.Bardsley@arm.com    code('};')
43110260SAndrew.Bardsley@arm.com
43210260SAndrew.Bardsley@arm.com    code('''
43310260SAndrew.Bardsley@arm.com
43410260SAndrew.Bardsley@arm.com#define THE_GPU_ISA ${{define(target_gpu_isa)}}
43510260SAndrew.Bardsley@arm.com#define TheGpuISA ${{namespace(target_gpu_isa)}}
43610260SAndrew.Bardsley@arm.com#define THE_GPU_ISA_STR "${{target_gpu_isa}}"
43710260SAndrew.Bardsley@arm.com
43810260SAndrew.Bardsley@arm.com#endif // __CONFIG_THE_GPU_ISA_HH__''')
43910260SAndrew.Bardsley@arm.com
44010260SAndrew.Bardsley@arm.com    code.write(str(target[0]))
44110260SAndrew.Bardsley@arm.com
44210260SAndrew.Bardsley@arm.comenv.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list),
44310260SAndrew.Bardsley@arm.com            MakeAction(makeTheGPUISA, Transform("CFG ISA", 0)))
44410260SAndrew.Bardsley@arm.com
44510260SAndrew.Bardsley@arm.com########################################################################
44610260SAndrew.Bardsley@arm.com#
44710260SAndrew.Bardsley@arm.com# Prevent any SimObjects from being added after this point, they
44810260SAndrew.Bardsley@arm.com# should all have been added in the SConscripts above
44910260SAndrew.Bardsley@arm.com#
45010260SAndrew.Bardsley@arm.comSimObject.fixed = True
45110260SAndrew.Bardsley@arm.com
45210260SAndrew.Bardsley@arm.comclass DictImporter(object):
45310260SAndrew.Bardsley@arm.com    '''This importer takes a dictionary of arbitrary module names that
45410260SAndrew.Bardsley@arm.com    map to arbitrary filenames.'''
45510260SAndrew.Bardsley@arm.com    def __init__(self, modules):
45610260SAndrew.Bardsley@arm.com        self.modules = modules
45710260SAndrew.Bardsley@arm.com        self.installed = set()
45810260SAndrew.Bardsley@arm.com
45910260SAndrew.Bardsley@arm.com    def __del__(self):
46010260SAndrew.Bardsley@arm.com        self.unload()
46110260SAndrew.Bardsley@arm.com
46210260SAndrew.Bardsley@arm.com    def unload(self):
46310260SAndrew.Bardsley@arm.com        import sys
46410260SAndrew.Bardsley@arm.com        for module in self.installed:
46510260SAndrew.Bardsley@arm.com            del sys.modules[module]
46610260SAndrew.Bardsley@arm.com        self.installed = set()
46710260SAndrew.Bardsley@arm.com
46810260SAndrew.Bardsley@arm.com    def find_module(self, fullname, path):
46910260SAndrew.Bardsley@arm.com        if fullname == 'm5.defines':
47010260SAndrew.Bardsley@arm.com            return self
47110260SAndrew.Bardsley@arm.com
47210260SAndrew.Bardsley@arm.com        if fullname == 'm5.objects':
47310260SAndrew.Bardsley@arm.com            return self
47410260SAndrew.Bardsley@arm.com
47510260SAndrew.Bardsley@arm.com        if fullname.startswith('_m5'):
47610260SAndrew.Bardsley@arm.com            return None
47710260SAndrew.Bardsley@arm.com
47810260SAndrew.Bardsley@arm.com        source = self.modules.get(fullname, None)
47910260SAndrew.Bardsley@arm.com        if source is not None and fullname.startswith('m5.objects'):
48010260SAndrew.Bardsley@arm.com            return self
48110260SAndrew.Bardsley@arm.com
48210260SAndrew.Bardsley@arm.com        return None
48310260SAndrew.Bardsley@arm.com
48410260SAndrew.Bardsley@arm.com    def load_module(self, fullname):
48510260SAndrew.Bardsley@arm.com        mod = imp.new_module(fullname)
48610260SAndrew.Bardsley@arm.com        sys.modules[fullname] = mod
48710260SAndrew.Bardsley@arm.com        self.installed.add(fullname)
48810260SAndrew.Bardsley@arm.com
48910260SAndrew.Bardsley@arm.com        mod.__loader__ = self
49010260SAndrew.Bardsley@arm.com        if fullname == 'm5.objects':
49110260SAndrew.Bardsley@arm.com            mod.__path__ = fullname.split('.')
49210260SAndrew.Bardsley@arm.com            return mod
49310260SAndrew.Bardsley@arm.com
49410260SAndrew.Bardsley@arm.com        if fullname == 'm5.defines':
49510260SAndrew.Bardsley@arm.com            mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
49610260SAndrew.Bardsley@arm.com            return mod
49710260SAndrew.Bardsley@arm.com
49810260SAndrew.Bardsley@arm.com        source = self.modules[fullname]
49910260SAndrew.Bardsley@arm.com        if source.modname == '__init__':
50010260SAndrew.Bardsley@arm.com            mod.__path__ = source.modpath
50110260SAndrew.Bardsley@arm.com        mod.__file__ = source.abspath
50210260SAndrew.Bardsley@arm.com
50310260SAndrew.Bardsley@arm.com        exec file(source.abspath, 'r') in mod.__dict__
50410260SAndrew.Bardsley@arm.com
50510260SAndrew.Bardsley@arm.com        return mod
50610260SAndrew.Bardsley@arm.com
50710260SAndrew.Bardsley@arm.comimport m5.SimObject
50810260SAndrew.Bardsley@arm.comimport m5.params
50910260SAndrew.Bardsley@arm.comfrom m5.util import code_formatter
51010260SAndrew.Bardsley@arm.com
51110260SAndrew.Bardsley@arm.comm5.SimObject.clear()
51210260SAndrew.Bardsley@arm.comm5.params.clear()
51310260SAndrew.Bardsley@arm.com
51410260SAndrew.Bardsley@arm.com# install the python importer so we can grab stuff from the source
51510260SAndrew.Bardsley@arm.com# tree itself.  We can't have SimObjects added after this point or
51610260SAndrew.Bardsley@arm.com# else we won't know about them for the rest of the stuff.
51710260SAndrew.Bardsley@arm.comimporter = DictImporter(PySource.modules)
51810260SAndrew.Bardsley@arm.comsys.meta_path[0:0] = [ importer ]
51910260SAndrew.Bardsley@arm.com
52010260SAndrew.Bardsley@arm.com# import all sim objects so we can populate the all_objects list
52110260SAndrew.Bardsley@arm.com# make sure that we're working with a list, then let's sort it
52210260SAndrew.Bardsley@arm.comfor modname in SimObject.modnames:
52310260SAndrew.Bardsley@arm.com    exec('from m5.objects import %s' % modname)
52410260SAndrew.Bardsley@arm.com
52510260SAndrew.Bardsley@arm.com# we need to unload all of the currently imported modules so that they
52610260SAndrew.Bardsley@arm.com# will be re-imported the next time the sconscript is run
52710260SAndrew.Bardsley@arm.comimporter.unload()
52810260SAndrew.Bardsley@arm.comsys.meta_path.remove(importer)
52910260SAndrew.Bardsley@arm.com
53010260SAndrew.Bardsley@arm.comsim_objects = m5.SimObject.allClasses
53110260SAndrew.Bardsley@arm.comall_enums = m5.params.allEnums
53210260SAndrew.Bardsley@arm.com
53310260SAndrew.Bardsley@arm.comfor name,obj in sorted(sim_objects.iteritems()):
53410260SAndrew.Bardsley@arm.com    for param in obj._params.local.values():
53510260SAndrew.Bardsley@arm.com        # load the ptype attribute now because it depends on the
53610260SAndrew.Bardsley@arm.com        # current version of SimObject.allClasses, but when scons
53710260SAndrew.Bardsley@arm.com        # actually uses the value, all versions of
53810260SAndrew.Bardsley@arm.com        # SimObject.allClasses will have been loaded
53910260SAndrew.Bardsley@arm.com        param.ptype
54010260SAndrew.Bardsley@arm.com
54110260SAndrew.Bardsley@arm.com########################################################################
54210260SAndrew.Bardsley@arm.com#
54310260SAndrew.Bardsley@arm.com# calculate extra dependencies
54410260SAndrew.Bardsley@arm.com#
54510260SAndrew.Bardsley@arm.commodule_depends = ["m5", "m5.SimObject", "m5.params"]
54610260SAndrew.Bardsley@arm.comdepends = [ PySource.modules[dep].snode for dep in module_depends ]
54710260SAndrew.Bardsley@arm.comdepends.sort(key = lambda x: x.name)
54810260SAndrew.Bardsley@arm.com
54910260SAndrew.Bardsley@arm.com########################################################################
55010260SAndrew.Bardsley@arm.com#
55110260SAndrew.Bardsley@arm.com# Commands for the basic automatically generated python files
55210260SAndrew.Bardsley@arm.com#
55310260SAndrew.Bardsley@arm.com
55410260SAndrew.Bardsley@arm.com# Generate Python file containing a dict specifying the current
55510260SAndrew.Bardsley@arm.com# buildEnv flags.
55610260SAndrew.Bardsley@arm.comdef makeDefinesPyFile(target, source, env):
55710260SAndrew.Bardsley@arm.com    build_env = source[0].get_contents()
55810260SAndrew.Bardsley@arm.com
55910260SAndrew.Bardsley@arm.com    code = code_formatter()
56010260SAndrew.Bardsley@arm.com    code("""
56110260SAndrew.Bardsley@arm.comimport _m5.core
56210260SAndrew.Bardsley@arm.comimport m5.util
56310260SAndrew.Bardsley@arm.com
56410260SAndrew.Bardsley@arm.combuildEnv = m5.util.SmartDict($build_env)
56510260SAndrew.Bardsley@arm.com
56610260SAndrew.Bardsley@arm.comcompileDate = _m5.core.compileDate
56710260SAndrew.Bardsley@arm.com_globals = globals()
56810260SAndrew.Bardsley@arm.comfor key,val in _m5.core.__dict__.iteritems():
56910260SAndrew.Bardsley@arm.com    if key.startswith('flag_'):
57010260SAndrew.Bardsley@arm.com        flag = key[5:]
57110260SAndrew.Bardsley@arm.com        _globals[flag] = val
57210260SAndrew.Bardsley@arm.comdel _globals
57310260SAndrew.Bardsley@arm.com""")
57410260SAndrew.Bardsley@arm.com    code.write(target[0].abspath)
57510260SAndrew.Bardsley@arm.com
57610260SAndrew.Bardsley@arm.comdefines_info = Value(build_env)
57710260SAndrew.Bardsley@arm.com# Generate a file with all of the compile options in it
57810260SAndrew.Bardsley@arm.comenv.Command('python/m5/defines.py', defines_info,
57910260SAndrew.Bardsley@arm.com            MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
58010260SAndrew.Bardsley@arm.comPySource('m5', 'python/m5/defines.py')
58110260SAndrew.Bardsley@arm.com
58210260SAndrew.Bardsley@arm.com# Generate python file containing info about the M5 source code
58310260SAndrew.Bardsley@arm.comdef makeInfoPyFile(target, source, env):
58410260SAndrew.Bardsley@arm.com    code = code_formatter()
58510260SAndrew.Bardsley@arm.com    for src in source:
58610260SAndrew.Bardsley@arm.com        data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
58710260SAndrew.Bardsley@arm.com        code('$src = ${{repr(data)}}')
58810260SAndrew.Bardsley@arm.com    code.write(str(target[0]))
58910260SAndrew.Bardsley@arm.com
59010260SAndrew.Bardsley@arm.com# Generate a file that wraps the basic top level files
59110260SAndrew.Bardsley@arm.comenv.Command('python/m5/info.py',
59210260SAndrew.Bardsley@arm.com            [ '#/COPYING', '#/LICENSE', '#/README', ],
59310260SAndrew.Bardsley@arm.com            MakeAction(makeInfoPyFile, Transform("INFO")))
59410260SAndrew.Bardsley@arm.comPySource('m5', 'python/m5/info.py')
59510260SAndrew.Bardsley@arm.com
59610260SAndrew.Bardsley@arm.com########################################################################
59710260SAndrew.Bardsley@arm.com#
59810260SAndrew.Bardsley@arm.com# Create all of the SimObject param headers and enum headers
59910260SAndrew.Bardsley@arm.com#
60010260SAndrew.Bardsley@arm.com
60110260SAndrew.Bardsley@arm.comdef createSimObjectParamStruct(target, source, env):
60210260SAndrew.Bardsley@arm.com    assert len(target) == 1 and len(source) == 1
60310260SAndrew.Bardsley@arm.com
60410260SAndrew.Bardsley@arm.com    name = source[0].get_text_contents()
60510260SAndrew.Bardsley@arm.com    obj = sim_objects[name]
60610260SAndrew.Bardsley@arm.com
60710260SAndrew.Bardsley@arm.com    code = code_formatter()
60810260SAndrew.Bardsley@arm.com    obj.cxx_param_decl(code)
60910260SAndrew.Bardsley@arm.com    code.write(target[0].abspath)
61010260SAndrew.Bardsley@arm.com
61110260SAndrew.Bardsley@arm.comdef createSimObjectCxxConfig(is_header):
61210260SAndrew.Bardsley@arm.com    def body(target, source, env):
61310260SAndrew.Bardsley@arm.com        assert len(target) == 1 and len(source) == 1
61410260SAndrew.Bardsley@arm.com
61510260SAndrew.Bardsley@arm.com        name = str(source[0].get_contents())
61610260SAndrew.Bardsley@arm.com        obj = sim_objects[name]
61710260SAndrew.Bardsley@arm.com
61810260SAndrew.Bardsley@arm.com        code = code_formatter()
61910260SAndrew.Bardsley@arm.com        obj.cxx_config_param_file(code, is_header)
62010260SAndrew.Bardsley@arm.com        code.write(target[0].abspath)
62110260SAndrew.Bardsley@arm.com    return body
62210260SAndrew.Bardsley@arm.com
62310260SAndrew.Bardsley@arm.comdef createEnumStrings(target, source, env):
62410260SAndrew.Bardsley@arm.com    assert len(target) == 1 and len(source) == 2
62510260SAndrew.Bardsley@arm.com
62610260SAndrew.Bardsley@arm.com    name = source[0].get_text_contents()
62710260SAndrew.Bardsley@arm.com    use_python = source[1].read()
62810260SAndrew.Bardsley@arm.com    obj = all_enums[name]
62910260SAndrew.Bardsley@arm.com
63010260SAndrew.Bardsley@arm.com    code = code_formatter()
63110260SAndrew.Bardsley@arm.com    obj.cxx_def(code)
63210260SAndrew.Bardsley@arm.com    if use_python:
63310260SAndrew.Bardsley@arm.com        obj.pybind_def(code)
63410260SAndrew.Bardsley@arm.com    code.write(target[0].abspath)
63510260SAndrew.Bardsley@arm.com
63610260SAndrew.Bardsley@arm.comdef createEnumDecls(target, source, env):
63710260SAndrew.Bardsley@arm.com    assert len(target) == 1 and len(source) == 1
63810260SAndrew.Bardsley@arm.com
63910260SAndrew.Bardsley@arm.com    name = source[0].get_text_contents()
64010260SAndrew.Bardsley@arm.com    obj = all_enums[name]
64110260SAndrew.Bardsley@arm.com
64210260SAndrew.Bardsley@arm.com    code = code_formatter()
64310260SAndrew.Bardsley@arm.com    obj.cxx_decl(code)
64410260SAndrew.Bardsley@arm.com    code.write(target[0].abspath)
64510260SAndrew.Bardsley@arm.com
64610260SAndrew.Bardsley@arm.comdef createSimObjectPyBindWrapper(target, source, env):
64710260SAndrew.Bardsley@arm.com    name = source[0].get_text_contents()
64810260SAndrew.Bardsley@arm.com    obj = sim_objects[name]
64910260SAndrew.Bardsley@arm.com
65010260SAndrew.Bardsley@arm.com    code = code_formatter()
65110260SAndrew.Bardsley@arm.com    obj.pybind_decl(code)
65210260SAndrew.Bardsley@arm.com    code.write(target[0].abspath)
65310260SAndrew.Bardsley@arm.com
65410260SAndrew.Bardsley@arm.com# Generate all of the SimObject param C++ struct header files
65510260SAndrew.Bardsley@arm.comparams_hh_files = []
65610260SAndrew.Bardsley@arm.comfor name,simobj in sorted(sim_objects.iteritems()):
65710260SAndrew.Bardsley@arm.com    py_source = PySource.modules[simobj.__module__]
65810260SAndrew.Bardsley@arm.com    extra_deps = [ py_source.tnode ]
65910260SAndrew.Bardsley@arm.com
66010260SAndrew.Bardsley@arm.com    hh_file = File('params/%s.hh' % name)
66110260SAndrew.Bardsley@arm.com    params_hh_files.append(hh_file)
66210260SAndrew.Bardsley@arm.com    env.Command(hh_file, Value(name),
66310260SAndrew.Bardsley@arm.com                MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
66410260SAndrew.Bardsley@arm.com    env.Depends(hh_file, depends + extra_deps)
66510260SAndrew.Bardsley@arm.com
66610260SAndrew.Bardsley@arm.com# C++ parameter description files
66710260SAndrew.Bardsley@arm.comif GetOption('with_cxx_config'):
66810260SAndrew.Bardsley@arm.com    for name,simobj in sorted(sim_objects.iteritems()):
66910260SAndrew.Bardsley@arm.com        py_source = PySource.modules[simobj.__module__]
67010260SAndrew.Bardsley@arm.com        extra_deps = [ py_source.tnode ]
67110260SAndrew.Bardsley@arm.com
67210260SAndrew.Bardsley@arm.com        cxx_config_hh_file = File('cxx_config/%s.hh' % name)
67310260SAndrew.Bardsley@arm.com        cxx_config_cc_file = File('cxx_config/%s.cc' % name)
67410260SAndrew.Bardsley@arm.com        env.Command(cxx_config_hh_file, Value(name),
67510260SAndrew.Bardsley@arm.com                    MakeAction(createSimObjectCxxConfig(True),
67610260SAndrew.Bardsley@arm.com                    Transform("CXXCPRHH")))
67710260SAndrew.Bardsley@arm.com        env.Command(cxx_config_cc_file, Value(name),
67810260SAndrew.Bardsley@arm.com                    MakeAction(createSimObjectCxxConfig(False),
679                    Transform("CXXCPRCC")))
680        env.Depends(cxx_config_hh_file, depends + extra_deps +
681                    [File('params/%s.hh' % name), File('sim/cxx_config.hh')])
682        env.Depends(cxx_config_cc_file, depends + extra_deps +
683                    [cxx_config_hh_file])
684        Source(cxx_config_cc_file)
685
686    cxx_config_init_cc_file = File('cxx_config/init.cc')
687
688    def createCxxConfigInitCC(target, source, env):
689        assert len(target) == 1 and len(source) == 1
690
691        code = code_formatter()
692
693        for name,simobj in sorted(sim_objects.iteritems()):
694            if not hasattr(simobj, 'abstract') or not simobj.abstract:
695                code('#include "cxx_config/${name}.hh"')
696        code()
697        code('void cxxConfigInit()')
698        code('{')
699        code.indent()
700        for name,simobj in sorted(sim_objects.iteritems()):
701            not_abstract = not hasattr(simobj, 'abstract') or \
702                not simobj.abstract
703            if not_abstract and 'type' in simobj.__dict__:
704                code('cxx_config_directory["${name}"] = '
705                     '${name}CxxConfigParams::makeDirectoryEntry();')
706        code.dedent()
707        code('}')
708        code.write(target[0].abspath)
709
710    py_source = PySource.modules[simobj.__module__]
711    extra_deps = [ py_source.tnode ]
712    env.Command(cxx_config_init_cc_file, Value(name),
713        MakeAction(createCxxConfigInitCC, Transform("CXXCINIT")))
714    cxx_param_hh_files = ["cxx_config/%s.hh" % simobj
715        for name,simobj in sorted(sim_objects.iteritems())
716        if not hasattr(simobj, 'abstract') or not simobj.abstract]
717    Depends(cxx_config_init_cc_file, cxx_param_hh_files +
718            [File('sim/cxx_config.hh')])
719    Source(cxx_config_init_cc_file)
720
721# Generate all enum header files
722for name,enum in sorted(all_enums.iteritems()):
723    py_source = PySource.modules[enum.__module__]
724    extra_deps = [ py_source.tnode ]
725
726    cc_file = File('enums/%s.cc' % name)
727    env.Command(cc_file, [Value(name), Value(env['USE_PYTHON'])],
728                MakeAction(createEnumStrings, Transform("ENUM STR")))
729    env.Depends(cc_file, depends + extra_deps)
730    Source(cc_file)
731
732    hh_file = File('enums/%s.hh' % name)
733    env.Command(hh_file, Value(name),
734                MakeAction(createEnumDecls, Transform("ENUMDECL")))
735    env.Depends(hh_file, depends + extra_deps)
736
737# Generate SimObject Python bindings wrapper files
738if env['USE_PYTHON']:
739    for name,simobj in sorted(sim_objects.iteritems()):
740        py_source = PySource.modules[simobj.__module__]
741        extra_deps = [ py_source.tnode ]
742        cc_file = File('python/_m5/param_%s.cc' % name)
743        env.Command(cc_file, Value(name),
744                    MakeAction(createSimObjectPyBindWrapper,
745                               Transform("SO PyBind")))
746        env.Depends(cc_file, depends + extra_deps)
747        Source(cc_file)
748
749# Build all protocol buffers if we have got protoc and protobuf available
750if env['HAVE_PROTOBUF']:
751    for proto in ProtoBuf.all:
752        # Use both the source and header as the target, and the .proto
753        # file as the source. When executing the protoc compiler, also
754        # specify the proto_path to avoid having the generated files
755        # include the path.
756        env.Command([proto.cc_file, proto.hh_file], proto.tnode,
757                    MakeAction('$PROTOC --cpp_out ${TARGET.dir} '
758                               '--proto_path ${SOURCE.dir} $SOURCE',
759                               Transform("PROTOC")))
760
761        # Add the C++ source file
762        Source(proto.cc_file, tags=proto.tags)
763elif ProtoBuf.all:
764    print 'Got protobuf to build, but lacks support!'
765    Exit(1)
766
767#
768# Handle debug flags
769#
770def makeDebugFlagCC(target, source, env):
771    assert(len(target) == 1 and len(source) == 1)
772
773    code = code_formatter()
774
775    # delay definition of CompoundFlags until after all the definition
776    # of all constituent SimpleFlags
777    comp_code = code_formatter()
778
779    # file header
780    code('''
781/*
782 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
783 */
784
785#include "base/debug.hh"
786
787namespace Debug {
788
789''')
790
791    for name, flag in sorted(source[0].read().iteritems()):
792        n, compound, desc = flag
793        assert n == name
794
795        if not compound:
796            code('SimpleFlag $name("$name", "$desc");')
797        else:
798            comp_code('CompoundFlag $name("$name", "$desc",')
799            comp_code.indent()
800            last = len(compound) - 1
801            for i,flag in enumerate(compound):
802                if i != last:
803                    comp_code('&$flag,')
804                else:
805                    comp_code('&$flag);')
806            comp_code.dedent()
807
808    code.append(comp_code)
809    code()
810    code('} // namespace Debug')
811
812    code.write(str(target[0]))
813
814def makeDebugFlagHH(target, source, env):
815    assert(len(target) == 1 and len(source) == 1)
816
817    val = eval(source[0].get_contents())
818    name, compound, desc = val
819
820    code = code_formatter()
821
822    # file header boilerplate
823    code('''\
824/*
825 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
826 */
827
828#ifndef __DEBUG_${name}_HH__
829#define __DEBUG_${name}_HH__
830
831namespace Debug {
832''')
833
834    if compound:
835        code('class CompoundFlag;')
836    code('class SimpleFlag;')
837
838    if compound:
839        code('extern CompoundFlag $name;')
840        for flag in compound:
841            code('extern SimpleFlag $flag;')
842    else:
843        code('extern SimpleFlag $name;')
844
845    code('''
846}
847
848#endif // __DEBUG_${name}_HH__
849''')
850
851    code.write(str(target[0]))
852
853for name,flag in sorted(debug_flags.iteritems()):
854    n, compound, desc = flag
855    assert n == name
856
857    hh_file = 'debug/%s.hh' % name
858    env.Command(hh_file, Value(flag),
859                MakeAction(makeDebugFlagHH, Transform("TRACING", 0)))
860
861env.Command('debug/flags.cc', Value(debug_flags),
862            MakeAction(makeDebugFlagCC, Transform("TRACING", 0)))
863Source('debug/flags.cc')
864
865# version tags
866tags = \
867env.Command('sim/tags.cc', None,
868            MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET',
869                       Transform("VER TAGS")))
870env.AlwaysBuild(tags)
871
872# Embed python files.  All .py files that have been indicated by a
873# PySource() call in a SConscript need to be embedded into the M5
874# library.  To do that, we compile the file to byte code, marshal the
875# byte code, compress it, and then generate a c++ file that
876# inserts the result into an array.
877def embedPyFile(target, source, env):
878    def c_str(string):
879        if string is None:
880            return "0"
881        return '"%s"' % string
882
883    '''Action function to compile a .py into a code object, marshal
884    it, compress it, and stick it into an asm file so the code appears
885    as just bytes with a label in the data section'''
886
887    src = file(str(source[0]), 'r').read()
888
889    pysource = PySource.tnodes[source[0]]
890    compiled = compile(src, pysource.abspath, 'exec')
891    marshalled = marshal.dumps(compiled)
892    compressed = zlib.compress(marshalled)
893    data = compressed
894    sym = pysource.symname
895
896    code = code_formatter()
897    code('''\
898#include "sim/init.hh"
899
900namespace {
901
902const uint8_t data_${sym}[] = {
903''')
904    code.indent()
905    step = 16
906    for i in xrange(0, len(data), step):
907        x = array.array('B', data[i:i+step])
908        code(''.join('%d,' % d for d in x))
909    code.dedent()
910
911    code('''};
912
913EmbeddedPython embedded_${sym}(
914    ${{c_str(pysource.arcname)}},
915    ${{c_str(pysource.abspath)}},
916    ${{c_str(pysource.modpath)}},
917    data_${sym},
918    ${{len(data)}},
919    ${{len(marshalled)}});
920
921} // anonymous namespace
922''')
923    code.write(str(target[0]))
924
925for source in PySource.all:
926    env.Command(source.cpp, source.tnode,
927                MakeAction(embedPyFile, Transform("EMBED PY")))
928    Source(source.cpp, tags=source.tags, add_tags='python')
929
930########################################################################
931#
932# Define binaries.  Each different build type (debug, opt, etc.) gets
933# a slightly different build environment.
934#
935
936# List of constructed environments to pass back to SConstruct
937date_source = Source('base/date.cc', tags=[])
938
939# Function to create a new build environment as clone of current
940# environment 'env' with modified object suffix and optional stripped
941# binary.  Additional keyword arguments are appended to corresponding
942# build environment vars.
943def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs):
944    # SCons doesn't know to append a library suffix when there is a '.' in the
945    # name.  Use '_' instead.
946    libname = 'gem5_' + label
947    exename = 'gem5.' + label
948    secondary_exename = 'm5.' + label
949
950    new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
951    new_env.Label = label
952    new_env.Append(**kwargs)
953
954    def make_obj(source, static, extra_deps=None):
955        '''This function creates a scons node of the requested type, and sets
956        up any additional dependencies.'''
957
958        if static:
959            obj = new_env.StaticObject(source.tnode)
960        else:
961            obj = new_env.SharedObject(source.tnode)
962
963        if extra_deps:
964            new_env.Depends(obj, extra_deps)
965
966        return obj
967
968    lib_sources = Source.all.with_tag('gem5 lib')
969
970    # Without Python, leave out all Python content from the library
971    # builds.  The option doesn't affect gem5 built as a program
972    if GetOption('without_python'):
973        lib_sources = lib_sources.without_tag('python')
974
975    static_objs = []
976    shared_objs = []
977
978    for s in lib_sources.with_tag(Source.ungrouped_tag):
979        static_objs.append(make_obj(s, True))
980        shared_objs.append(make_obj(s, False))
981
982    partial_objs = []
983
984    for group in Source.source_groups:
985        srcs = lib_sources.with_tag(Source.link_group_tag(group))
986        if not srcs:
987            continue
988
989        # If partial linking is disabled, add these sources to the build
990        # directly, and short circuit this loop.
991        if disable_partial:
992            for s in srcs:
993                static_objs.append(make_obj(s, True))
994                shared_objs.append(make_obj(s, False))
995            continue
996
997        # Set up the static partially linked objects.
998        source_objs = [ make_obj(s, True) for s in srcs ]
999        file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial")
1000        target = File(joinpath(group, file_name))
1001        partial = env.PartialStatic(target=target, source=source_objs)
1002        static_objs.append(partial)
1003
1004        # Set up the shared partially linked objects.
1005        source_objs = [ make_obj(s, False) for s in srcs ]
1006        file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial")
1007        target = File(joinpath(group, file_name))
1008        partial = env.PartialShared(target=target, source=source_objs)
1009        shared_objs.append(partial)
1010
1011    static_date = make_obj(date_source, static=True, extra_deps=static_objs)
1012    static_objs.append(static_date)
1013
1014    shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
1015    shared_objs.append(shared_date)
1016
1017    # First make a library of everything but main() so other programs can
1018    # link against m5.
1019    static_lib = new_env.StaticLibrary(libname, static_objs)
1020    shared_lib = new_env.SharedLibrary(libname, shared_objs)
1021
1022    # Now link a stub with main() and the static library.
1023    main_objs = [ make_obj(s, True) for s in Source.all.with_tag('main') ]
1024
1025    for test in UnitTest.all:
1026        test_sources = Source.all.with_tag(str(test.target))
1027        test_objs = [ make_obj(s, static=True) for s in test_sources ]
1028        if test.main:
1029            test_objs += main_objs
1030        path = 'unittest/%s.%s' % (test.target, label)
1031        new_env.Program(path, test_objs + static_objs)
1032
1033    progname = exename
1034    if strip:
1035        progname += '.unstripped'
1036
1037    targets = new_env.Program(progname, main_objs + static_objs)
1038
1039    if strip:
1040        if sys.platform == 'sunos5':
1041            cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1042        else:
1043            cmd = 'strip $SOURCE -o $TARGET'
1044        targets = new_env.Command(exename, progname,
1045                    MakeAction(cmd, Transform("STRIP")))
1046
1047    new_env.Command(secondary_exename, exename,
1048            MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK")))
1049
1050    new_env.M5Binary = targets[0]
1051
1052    # Set up regression tests.
1053    SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'),
1054               variant_dir=Dir('tests').Dir(new_env.Label),
1055               exports={ 'env' : new_env }, duplicate=False)
1056
1057# Start out with the compiler flags common to all compilers,
1058# i.e. they all use -g for opt and -g -pg for prof
1059ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'],
1060           'perf' : ['-g']}
1061
1062# Start out with the linker flags common to all linkers, i.e. -pg for
1063# prof, and -lprofiler for perf. The -lprofile flag is surrounded by
1064# no-as-needed and as-needed as the binutils linker is too clever and
1065# simply doesn't link to the library otherwise.
1066ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'],
1067           'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']}
1068
1069# For Link Time Optimization, the optimisation flags used to compile
1070# individual files are decoupled from those used at link time
1071# (i.e. you can compile with -O3 and perform LTO with -O0), so we need
1072# to also update the linker flags based on the target.
1073if env['GCC']:
1074    if sys.platform == 'sunos5':
1075        ccflags['debug'] += ['-gstabs+']
1076    else:
1077        ccflags['debug'] += ['-ggdb3']
1078    ldflags['debug'] += ['-O0']
1079    # opt, fast, prof and perf all share the same cc flags, also add
1080    # the optimization to the ldflags as LTO defers the optimization
1081    # to link time
1082    for target in ['opt', 'fast', 'prof', 'perf']:
1083        ccflags[target] += ['-O3']
1084        ldflags[target] += ['-O3']
1085
1086    ccflags['fast'] += env['LTO_CCFLAGS']
1087    ldflags['fast'] += env['LTO_LDFLAGS']
1088elif env['CLANG']:
1089    ccflags['debug'] += ['-g', '-O0']
1090    # opt, fast, prof and perf all share the same cc flags
1091    for target in ['opt', 'fast', 'prof', 'perf']:
1092        ccflags[target] += ['-O3']
1093else:
1094    print 'Unknown compiler, please fix compiler options'
1095    Exit(1)
1096
1097
1098# To speed things up, we only instantiate the build environments we
1099# need.  We try to identify the needed environment for each target; if
1100# we can't, we fall back on instantiating all the environments just to
1101# be safe.
1102target_types = ['debug', 'opt', 'fast', 'prof', 'perf']
1103obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof',
1104              'gpo' : 'perf'}
1105
1106def identifyTarget(t):
1107    ext = t.split('.')[-1]
1108    if ext in target_types:
1109        return ext
1110    if obj2target.has_key(ext):
1111        return obj2target[ext]
1112    match = re.search(r'/tests/([^/]+)/', t)
1113    if match and match.group(1) in target_types:
1114        return match.group(1)
1115    return 'all'
1116
1117needed_envs = [identifyTarget(target) for target in BUILD_TARGETS]
1118if 'all' in needed_envs:
1119    needed_envs += target_types
1120
1121# Debug binary
1122if 'debug' in needed_envs:
1123    makeEnv(env, 'debug', '.do',
1124            CCFLAGS = Split(ccflags['debug']),
1125            CPPDEFINES = ['DEBUG', 'TRACING_ON=1'],
1126            LINKFLAGS = Split(ldflags['debug']))
1127
1128# Optimized binary
1129if 'opt' in needed_envs:
1130    makeEnv(env, 'opt', '.o',
1131            CCFLAGS = Split(ccflags['opt']),
1132            CPPDEFINES = ['TRACING_ON=1'],
1133            LINKFLAGS = Split(ldflags['opt']))
1134
1135# "Fast" binary
1136if 'fast' in needed_envs:
1137    disable_partial = \
1138            env.get('BROKEN_INCREMENTAL_LTO', False) and \
1139            GetOption('force_lto')
1140    makeEnv(env, 'fast', '.fo', strip = True,
1141            CCFLAGS = Split(ccflags['fast']),
1142            CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1143            LINKFLAGS = Split(ldflags['fast']),
1144            disable_partial=disable_partial)
1145
1146# Profiled binary using gprof
1147if 'prof' in needed_envs:
1148    makeEnv(env, 'prof', '.po',
1149            CCFLAGS = Split(ccflags['prof']),
1150            CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1151            LINKFLAGS = Split(ldflags['prof']))
1152
1153# Profiled binary using google-pprof
1154if 'perf' in needed_envs:
1155    makeEnv(env, 'perf', '.gpo',
1156            CCFLAGS = Split(ccflags['perf']),
1157            CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1158            LINKFLAGS = Split(ldflags['perf']))
1159