SConscript revision 12531
19651SAndreas.Sandberg@ARM.com# -*- mode:python -*-
29651SAndreas.Sandberg@ARM.com
39651SAndreas.Sandberg@ARM.com# Copyright (c) 2004-2005 The Regents of The University of Michigan
49651SAndreas.Sandberg@ARM.com# All rights reserved.
59651SAndreas.Sandberg@ARM.com#
69651SAndreas.Sandberg@ARM.com# Redistribution and use in source and binary forms, with or without
79651SAndreas.Sandberg@ARM.com# modification, are permitted provided that the following conditions are
89651SAndreas.Sandberg@ARM.com# met: redistributions of source code must retain the above copyright
99651SAndreas.Sandberg@ARM.com# notice, this list of conditions and the following disclaimer;
109651SAndreas.Sandberg@ARM.com# redistributions in binary form must reproduce the above copyright
119651SAndreas.Sandberg@ARM.com# notice, this list of conditions and the following disclaimer in the
129651SAndreas.Sandberg@ARM.com# documentation and/or other materials provided with the distribution;
139651SAndreas.Sandberg@ARM.com# neither the name of the copyright holders nor the names of its
149651SAndreas.Sandberg@ARM.com# contributors may be used to endorse or promote products derived from
159651SAndreas.Sandberg@ARM.com# this software without specific prior written permission.
169651SAndreas.Sandberg@ARM.com#
179651SAndreas.Sandberg@ARM.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
189651SAndreas.Sandberg@ARM.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
199651SAndreas.Sandberg@ARM.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
209651SAndreas.Sandberg@ARM.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
219651SAndreas.Sandberg@ARM.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
229651SAndreas.Sandberg@ARM.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
239651SAndreas.Sandberg@ARM.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
249651SAndreas.Sandberg@ARM.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
259651SAndreas.Sandberg@ARM.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
269651SAndreas.Sandberg@ARM.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
279651SAndreas.Sandberg@ARM.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289651SAndreas.Sandberg@ARM.com#
299651SAndreas.Sandberg@ARM.com# Authors: Nathan Binkert
309651SAndreas.Sandberg@ARM.com
319651SAndreas.Sandberg@ARM.comimport array
329651SAndreas.Sandberg@ARM.comimport bisect
339651SAndreas.Sandberg@ARM.comimport functools
349651SAndreas.Sandberg@ARM.comimport imp
359651SAndreas.Sandberg@ARM.comimport marshal
369651SAndreas.Sandberg@ARM.comimport os
379651SAndreas.Sandberg@ARM.comimport re
389651SAndreas.Sandberg@ARM.comimport subprocess
399651SAndreas.Sandberg@ARM.comimport sys
409651SAndreas.Sandberg@ARM.comimport zlib
419651SAndreas.Sandberg@ARM.com
429651SAndreas.Sandberg@ARM.comfrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath
4310114Sandreas@sandberg.pp.se
4410114Sandreas@sandberg.pp.seimport SCons
4510114Sandreas@sandberg.pp.se
469651SAndreas.Sandberg@ARM.comfrom gem5_scons import Transform
4711629Smichael.lebeane@amd.com
489651SAndreas.Sandberg@ARM.com# This file defines how to build a particular configuration of gem5
499651SAndreas.Sandberg@ARM.com# based on variable settings in the 'env' build environment.
509651SAndreas.Sandberg@ARM.com
519651SAndreas.Sandberg@ARM.comImport('*')
529651SAndreas.Sandberg@ARM.com
539651SAndreas.Sandberg@ARM.com# Children need to see the environment
549651SAndreas.Sandberg@ARM.comExport('env')
559651SAndreas.Sandberg@ARM.com
5610114Sandreas@sandberg.pp.sebuild_env = [(opt, env[opt]) for opt in export_vars]
5710114Sandreas@sandberg.pp.se
589892Sandreas@sandberg.pp.sefrom m5.util import code_formatter, compareVersions
599651SAndreas.Sandberg@ARM.com
609651SAndreas.Sandberg@ARM.com########################################################################
619651SAndreas.Sandberg@ARM.com# Code for adding source files of various types
629651SAndreas.Sandberg@ARM.com#
639651SAndreas.Sandberg@ARM.com# When specifying a source file of some type, a set of tags can be
649651SAndreas.Sandberg@ARM.com# specified for that file.
659651SAndreas.Sandberg@ARM.com
669651SAndreas.Sandberg@ARM.comclass SourceFilter(object):
679651SAndreas.Sandberg@ARM.com    def __init__(self, predicate):
689651SAndreas.Sandberg@ARM.com        self.predicate = predicate
699651SAndreas.Sandberg@ARM.com
709651SAndreas.Sandberg@ARM.com    def __or__(self, other):
719651SAndreas.Sandberg@ARM.com        return SourceFilter(lambda tags: self.predicate(tags) or
729651SAndreas.Sandberg@ARM.com                                         other.predicate(tags))
739651SAndreas.Sandberg@ARM.com
749651SAndreas.Sandberg@ARM.com    def __and__(self, other):
759651SAndreas.Sandberg@ARM.com        return SourceFilter(lambda tags: self.predicate(tags) and
769651SAndreas.Sandberg@ARM.com                                         other.predicate(tags))
779651SAndreas.Sandberg@ARM.com
789651SAndreas.Sandberg@ARM.comdef with_tags_that(predicate):
799651SAndreas.Sandberg@ARM.com    '''Return a list of sources with tags that satisfy a predicate.'''
809651SAndreas.Sandberg@ARM.com    return SourceFilter(predicate)
819651SAndreas.Sandberg@ARM.com
829651SAndreas.Sandberg@ARM.comdef with_any_tags(*tags):
839651SAndreas.Sandberg@ARM.com    '''Return a list of sources with any of the supplied tags.'''
8411341Sandreas.hansson@arm.com    return SourceFilter(lambda stags: len(set(tags) & stags) > 0)
8511341Sandreas.hansson@arm.com
8611341Sandreas.hansson@arm.comdef with_all_tags(*tags):
879651SAndreas.Sandberg@ARM.com    '''Return a list of sources with all of the supplied tags.'''
8811168Sandreas.hansson@arm.com    return SourceFilter(lambda stags: set(tags) <= stags)
8911168Sandreas.hansson@arm.com
909651SAndreas.Sandberg@ARM.comdef with_tag(tag):
9111168Sandreas.hansson@arm.com    '''Return a list of sources with the supplied tag.'''
9211168Sandreas.hansson@arm.com    return SourceFilter(lambda stags: tag in stags)
9311363Sandreas@sandberg.pp.se
949651SAndreas.Sandberg@ARM.comdef without_tags(*tags):
9511341Sandreas.hansson@arm.com    '''Return a list of sources without any of the supplied tags.'''
9611341Sandreas.hansson@arm.com    return SourceFilter(lambda stags: len(set(tags) & stags) == 0)
979651SAndreas.Sandberg@ARM.com
9811341Sandreas.hansson@arm.comdef without_tag(tag):
999651SAndreas.Sandberg@ARM.com    '''Return a list of sources with the supplied tag.'''
10011341Sandreas.hansson@arm.com    return SourceFilter(lambda stags: tag not in stags)
10111341Sandreas.hansson@arm.com
1029651SAndreas.Sandberg@ARM.comsource_filter_factories = {
10311168Sandreas.hansson@arm.com    'with_tags_that': with_tags_that,
10411341Sandreas.hansson@arm.com    'with_any_tags': with_any_tags,
10511341Sandreas.hansson@arm.com    'with_all_tags': with_all_tags,
1069651SAndreas.Sandberg@ARM.com    'with_tag': with_tag,
10711341Sandreas.hansson@arm.com    'without_tags': without_tags,
1089651SAndreas.Sandberg@ARM.com    'without_tag': without_tag,
10911943SCurtis.Dunham@arm.com}
11011341Sandreas.hansson@arm.com
1119652SAndreas.Sandberg@ARM.comExport(source_filter_factories)
11211341Sandreas.hansson@arm.com
11311341Sandreas.hansson@arm.comclass SourceList(list):
1149651SAndreas.Sandberg@ARM.com    def apply_filter(self, f):
11511629Smichael.lebeane@amd.com        def match(source):
11611629Smichael.lebeane@amd.com            return f.predicate(source.tags)
11711629Smichael.lebeane@amd.com        return SourceList(filter(match, self))
11811629Smichael.lebeane@amd.com
11911629Smichael.lebeane@amd.com    def __getattr__(self, name):
12011629Smichael.lebeane@amd.com        func = source_filter_factories.get(name, None)
1219651SAndreas.Sandberg@ARM.com        if not func:
12210905Sandreas.sandberg@arm.com            raise AttributeError
1239651SAndreas.Sandberg@ARM.com
1249652SAndreas.Sandberg@ARM.com        @functools.wraps(func)
12510114Sandreas@sandberg.pp.se        def wrapper(*args, **kwargs):
12610114Sandreas@sandberg.pp.se            return self.apply_filter(func(*args, **kwargs))
12710114Sandreas@sandberg.pp.se        return wrapper
12810114Sandreas@sandberg.pp.se
12910114Sandreas@sandberg.pp.seclass SourceMeta(type):
13010114Sandreas@sandberg.pp.se    '''Meta class for source files that keeps track of all files of a
13110114Sandreas@sandberg.pp.se    particular type.'''
13210114Sandreas@sandberg.pp.se    def __init__(cls, name, bases, dict):
1339652SAndreas.Sandberg@ARM.com        super(SourceMeta, cls).__init__(name, bases, dict)
1349652SAndreas.Sandberg@ARM.com        cls.all = SourceList()
1359652SAndreas.Sandberg@ARM.com
1369652SAndreas.Sandberg@ARM.comclass SourceFile(object):
1379652SAndreas.Sandberg@ARM.com    '''Base object that encapsulates the notion of a source file.
1389652SAndreas.Sandberg@ARM.com    This includes, the source node, target node, various manipulations
1399652SAndreas.Sandberg@ARM.com    of those.  A source file also specifies a set of tags which
1409652SAndreas.Sandberg@ARM.com    describing arbitrary properties of the source file.'''
1419652SAndreas.Sandberg@ARM.com    __metaclass__ = SourceMeta
1429652SAndreas.Sandberg@ARM.com
1439652SAndreas.Sandberg@ARM.com    static_objs = {}
1449652SAndreas.Sandberg@ARM.com    shared_objs = {}
1459651SAndreas.Sandberg@ARM.com
1469651SAndreas.Sandberg@ARM.com    def __init__(self, source, tags=None, add_tags=None):
1479651SAndreas.Sandberg@ARM.com        if tags is None:
1489651SAndreas.Sandberg@ARM.com            tags='gem5 lib'
1499651SAndreas.Sandberg@ARM.com        if isinstance(tags, basestring):
1509651SAndreas.Sandberg@ARM.com            tags = set([tags])
1519651SAndreas.Sandberg@ARM.com        if not isinstance(tags, set):
1529651SAndreas.Sandberg@ARM.com            tags = set(tags)
1539651SAndreas.Sandberg@ARM.com        self.tags = tags
1549651SAndreas.Sandberg@ARM.com
1559753Sandreas@sandberg.pp.se        if add_tags:
1569753Sandreas@sandberg.pp.se            if isinstance(add_tags, basestring):
1579753Sandreas@sandberg.pp.se                add_tags = set([add_tags])
1589753Sandreas@sandberg.pp.se            if not isinstance(add_tags, set):
1599753Sandreas@sandberg.pp.se                add_tags = set(add_tags)
1609753Sandreas@sandberg.pp.se            self.tags |= add_tags
1619753Sandreas@sandberg.pp.se
1629753Sandreas@sandberg.pp.se        tnode = source
16311629Smichael.lebeane@amd.com        if not isinstance(source, SCons.Node.FS.File):
1649753Sandreas@sandberg.pp.se            tnode = File(source)
1659753Sandreas@sandberg.pp.se
1669753Sandreas@sandberg.pp.se        self.tnode = tnode
1679753Sandreas@sandberg.pp.se        self.snode = tnode.srcnode()
1689753Sandreas@sandberg.pp.se
1699753Sandreas@sandberg.pp.se        for base in type(self).__mro__:
1709753Sandreas@sandberg.pp.se            if issubclass(base, SourceFile):
1719753Sandreas@sandberg.pp.se                base.all.append(self)
1729753Sandreas@sandberg.pp.se
17311629Smichael.lebeane@amd.com    def static(self, env):
17411629Smichael.lebeane@amd.com        key = (self.tnode, env['OBJSUFFIX'])
1759753Sandreas@sandberg.pp.se        if not key in self.static_objs:
1769753Sandreas@sandberg.pp.se            self.static_objs[key] = env.StaticObject(self.tnode)
1779753Sandreas@sandberg.pp.se        return self.static_objs[key]
1789753Sandreas@sandberg.pp.se
1799753Sandreas@sandberg.pp.se    def shared(self, env):
1809651SAndreas.Sandberg@ARM.com        key = (self.tnode, env['OBJSUFFIX'])
1819753Sandreas@sandberg.pp.se        if not key in self.shared_objs:
1829753Sandreas@sandberg.pp.se            self.shared_objs[key] = env.SharedObject(self.tnode)
1839753Sandreas@sandberg.pp.se        return self.shared_objs[key]
1849753Sandreas@sandberg.pp.se
1859753Sandreas@sandberg.pp.se    @property
1869753Sandreas@sandberg.pp.se    def filename(self):
1879753Sandreas@sandberg.pp.se        return str(self.tnode)
1889753Sandreas@sandberg.pp.se
1899753Sandreas@sandberg.pp.se    @property
1909651SAndreas.Sandberg@ARM.com    def dirname(self):
1919753Sandreas@sandberg.pp.se        return dirname(self.filename)
1929753Sandreas@sandberg.pp.se
1939753Sandreas@sandberg.pp.se    @property
1949753Sandreas@sandberg.pp.se    def basename(self):
1959753Sandreas@sandberg.pp.se        return basename(self.filename)
1969651SAndreas.Sandberg@ARM.com
1979753Sandreas@sandberg.pp.se    @property
1989753Sandreas@sandberg.pp.se    def extname(self):
1999753Sandreas@sandberg.pp.se        index = self.basename.rfind('.')
2009753Sandreas@sandberg.pp.se        if index <= 0:
2019753Sandreas@sandberg.pp.se            # dot files aren't extensions
2029753Sandreas@sandberg.pp.se            return self.basename, None
2039753Sandreas@sandberg.pp.se
20411629Smichael.lebeane@amd.com        return self.basename[:index], self.basename[index+1:]
20511629Smichael.lebeane@amd.com
2069753Sandreas@sandberg.pp.se    def __lt__(self, other): return self.filename < other.filename
2079753Sandreas@sandberg.pp.se    def __le__(self, other): return self.filename <= other.filename
2089753Sandreas@sandberg.pp.se    def __gt__(self, other): return self.filename > other.filename
2099753Sandreas@sandberg.pp.se    def __ge__(self, other): return self.filename >= other.filename
2109753Sandreas@sandberg.pp.se    def __eq__(self, other): return self.filename == other.filename
21111629Smichael.lebeane@amd.com    def __ne__(self, other): return self.filename != other.filename
21211629Smichael.lebeane@amd.com
21311629Smichael.lebeane@amd.comclass Source(SourceFile):
21411629Smichael.lebeane@amd.com    ungrouped_tag = 'No link group'
21511629Smichael.lebeane@amd.com    source_groups = set()
21611629Smichael.lebeane@amd.com
21711629Smichael.lebeane@amd.com    _current_group_tag = ungrouped_tag
21811629Smichael.lebeane@amd.com
2199753Sandreas@sandberg.pp.se    @staticmethod
2209753Sandreas@sandberg.pp.se    def link_group_tag(group):
2219753Sandreas@sandberg.pp.se        return 'link group: %s' % group
2229753Sandreas@sandberg.pp.se
2239753Sandreas@sandberg.pp.se    @classmethod
2249753Sandreas@sandberg.pp.se    def set_group(cls, group):
2259753Sandreas@sandberg.pp.se        new_tag = Source.link_group_tag(group)
2269753Sandreas@sandberg.pp.se        Source._current_group_tag = new_tag
2279753Sandreas@sandberg.pp.se        Source.source_groups.add(group)
2289651SAndreas.Sandberg@ARM.com
2299651SAndreas.Sandberg@ARM.com    def _add_link_group_tag(self):
2309651SAndreas.Sandberg@ARM.com        self.tags.add(Source._current_group_tag)
2319651SAndreas.Sandberg@ARM.com
2329651SAndreas.Sandberg@ARM.com    '''Add a c/c++ source file to the build'''
2339651SAndreas.Sandberg@ARM.com    def __init__(self, source, tags=None, add_tags=None):
2349651SAndreas.Sandberg@ARM.com        '''specify the source file, and any tags'''
2359651SAndreas.Sandberg@ARM.com        super(Source, self).__init__(source, tags, add_tags)
2369651SAndreas.Sandberg@ARM.com        self._add_link_group_tag()
2379753Sandreas@sandberg.pp.se
2389651SAndreas.Sandberg@ARM.comclass PySource(SourceFile):
2399651SAndreas.Sandberg@ARM.com    '''Add a python source file to the named package'''
2409735Sandreas@sandberg.pp.se    invalid_sym_char = re.compile('[^A-z0-9_]')
2419735Sandreas@sandberg.pp.se    modules = {}
2429735Sandreas@sandberg.pp.se    tnodes = {}
2439735Sandreas@sandberg.pp.se    symnames = {}
2449735Sandreas@sandberg.pp.se
2459735Sandreas@sandberg.pp.se    def __init__(self, package, source, tags=None, add_tags=None):
2469735Sandreas@sandberg.pp.se        '''specify the python package, the source file, and any tags'''
2479735Sandreas@sandberg.pp.se        super(PySource, self).__init__(source, tags, add_tags)
2489735Sandreas@sandberg.pp.se
2499735Sandreas@sandberg.pp.se        modname,ext = self.extname
2509735Sandreas@sandberg.pp.se        assert ext == 'py'
2519735Sandreas@sandberg.pp.se
2529735Sandreas@sandberg.pp.se        if package:
2539735Sandreas@sandberg.pp.se            path = package.split('.')
2549735Sandreas@sandberg.pp.se        else:
2559651SAndreas.Sandberg@ARM.com            path = []
2569651SAndreas.Sandberg@ARM.com
2579651SAndreas.Sandberg@ARM.com        modpath = path[:]
2589651SAndreas.Sandberg@ARM.com        if modname != '__init__':
2599651SAndreas.Sandberg@ARM.com            modpath += [ modname ]
2609651SAndreas.Sandberg@ARM.com        modpath = '.'.join(modpath)
2619651SAndreas.Sandberg@ARM.com
2629651SAndreas.Sandberg@ARM.com        arcpath = path + [ self.basename ]
2639753Sandreas@sandberg.pp.se        abspath = self.snode.abspath
2649753Sandreas@sandberg.pp.se        if not exists(abspath):
2659753Sandreas@sandberg.pp.se            abspath = self.tnode.abspath
2669753Sandreas@sandberg.pp.se
2679753Sandreas@sandberg.pp.se        self.package = package
2689753Sandreas@sandberg.pp.se        self.modname = modname
2699753Sandreas@sandberg.pp.se        self.modpath = modpath
2709753Sandreas@sandberg.pp.se        self.arcname = joinpath(*arcpath)
27110112Sandreas@sandberg.pp.se        self.abspath = abspath
27210112Sandreas@sandberg.pp.se        self.compiled = File(self.filename + 'c')
27310112Sandreas@sandberg.pp.se        self.cpp = File(self.filename + '.cc')
27410112Sandreas@sandberg.pp.se        self.symname = PySource.invalid_sym_char.sub('_', modpath)
27510112Sandreas@sandberg.pp.se
2769753Sandreas@sandberg.pp.se        PySource.modules[modpath] = self
2779753Sandreas@sandberg.pp.se        PySource.tnodes[self.tnode] = self
2789651SAndreas.Sandberg@ARM.com        PySource.symnames[self.symname] = self
2799651SAndreas.Sandberg@ARM.com
2809753Sandreas@sandberg.pp.seclass SimObject(PySource):
2819753Sandreas@sandberg.pp.se    '''Add a SimObject python file as a python source object and add
2829753Sandreas@sandberg.pp.se    it to a list of sim object modules'''
2839753Sandreas@sandberg.pp.se
2849753Sandreas@sandberg.pp.se    fixed = False
2859753Sandreas@sandberg.pp.se    modnames = []
2869753Sandreas@sandberg.pp.se
2879753Sandreas@sandberg.pp.se    def __init__(self, source, tags=None, add_tags=None):
2889753Sandreas@sandberg.pp.se        '''Specify the source file and any tags (automatically in
2899753Sandreas@sandberg.pp.se        the m5.objects package)'''
2909753Sandreas@sandberg.pp.se        super(SimObject, self).__init__('m5.objects', source, tags, add_tags)
2919753Sandreas@sandberg.pp.se        if self.fixed:
2929753Sandreas@sandberg.pp.se            raise AttributeError, "Too late to call SimObject now."
2939753Sandreas@sandberg.pp.se
2949651SAndreas.Sandberg@ARM.com        bisect.insort_right(SimObject.modnames, self.modname)
2959651SAndreas.Sandberg@ARM.com
2969651SAndreas.Sandberg@ARM.comclass ProtoBuf(SourceFile):
2979651SAndreas.Sandberg@ARM.com    '''Add a Protocol Buffer to build'''
2989651SAndreas.Sandberg@ARM.com
2999651SAndreas.Sandberg@ARM.com    def __init__(self, source, tags=None, add_tags=None):
3009651SAndreas.Sandberg@ARM.com        '''Specify the source file, and any tags'''
3019651SAndreas.Sandberg@ARM.com        super(ProtoBuf, self).__init__(source, tags, add_tags)
3029651SAndreas.Sandberg@ARM.com
3039651SAndreas.Sandberg@ARM.com        # Get the file name and the extension
3049651SAndreas.Sandberg@ARM.com        modname,ext = self.extname
3059651SAndreas.Sandberg@ARM.com        assert ext == 'proto'
3069651SAndreas.Sandberg@ARM.com
3079651SAndreas.Sandberg@ARM.com        # Currently, we stick to generating the C++ headers, so we
3089651SAndreas.Sandberg@ARM.com        # only need to track the source and header.
3099651SAndreas.Sandberg@ARM.com        self.cc_file = File(modname + '.pb.cc')
3109651SAndreas.Sandberg@ARM.com        self.hh_file = File(modname + '.pb.h')
3119651SAndreas.Sandberg@ARM.com
3129651SAndreas.Sandberg@ARM.comclass UnitTest(object):
3139651SAndreas.Sandberg@ARM.com    '''Create a UnitTest'''
3149651SAndreas.Sandberg@ARM.com
3159651SAndreas.Sandberg@ARM.com    all = []
3169651SAndreas.Sandberg@ARM.com    def __init__(self, target, *sources, **kwargs):
3179651SAndreas.Sandberg@ARM.com        '''Specify the target name and any sources.  Sources that are
3189651SAndreas.Sandberg@ARM.com        not SourceFiles are evalued with Source().  All files are
3199651SAndreas.Sandberg@ARM.com        tagged with the name of the UnitTest target.'''
3209651SAndreas.Sandberg@ARM.com
3219651SAndreas.Sandberg@ARM.com        srcs = SourceList()
3229651SAndreas.Sandberg@ARM.com        for src in sources:
3239651SAndreas.Sandberg@ARM.com            if not isinstance(src, SourceFile):
3249651SAndreas.Sandberg@ARM.com                src = Source(src, tags=str(target))
3259651SAndreas.Sandberg@ARM.com            srcs.append(src)
3269651SAndreas.Sandberg@ARM.com
3279651SAndreas.Sandberg@ARM.com        self.sources = srcs
3289651SAndreas.Sandberg@ARM.com        self.target = target
3299651SAndreas.Sandberg@ARM.com        self.main = kwargs.get('main', False)
3309651SAndreas.Sandberg@ARM.com        self.all.append(self)
3319651SAndreas.Sandberg@ARM.com
3329651SAndreas.Sandberg@ARM.comclass GTest(UnitTest):
3339651SAndreas.Sandberg@ARM.com    '''Create a unit test based on the google test framework.'''
3349651SAndreas.Sandberg@ARM.com    all = []
3359651SAndreas.Sandberg@ARM.com    def __init__(self, *args, **kwargs):
3369651SAndreas.Sandberg@ARM.com        isFilter = lambda arg: isinstance(arg, SourceFilter)
3379651SAndreas.Sandberg@ARM.com        self.filters = filter(isFilter, args)
3389651SAndreas.Sandberg@ARM.com        args = filter(lambda a: not isFilter(a), args)
3399651SAndreas.Sandberg@ARM.com        super(GTest, self).__init__(*args, **kwargs)
3409651SAndreas.Sandberg@ARM.com        self.dir = Dir('.')
3419651SAndreas.Sandberg@ARM.com        self.skip_lib = kwargs.pop('skip_lib', False)
3429651SAndreas.Sandberg@ARM.com
3439651SAndreas.Sandberg@ARM.com# Children should have access
3449651SAndreas.Sandberg@ARM.comExport('Source')
3459651SAndreas.Sandberg@ARM.comExport('PySource')
3469651SAndreas.Sandberg@ARM.comExport('SimObject')
3479651SAndreas.Sandberg@ARM.comExport('ProtoBuf')
3489651SAndreas.Sandberg@ARM.comExport('UnitTest')
3499651SAndreas.Sandberg@ARM.comExport('GTest')
3509651SAndreas.Sandberg@ARM.com
3519651SAndreas.Sandberg@ARM.com########################################################################
3529651SAndreas.Sandberg@ARM.com#
3539651SAndreas.Sandberg@ARM.com# Debug Flags
3549651SAndreas.Sandberg@ARM.com#
3559651SAndreas.Sandberg@ARM.comdebug_flags = {}
3569651SAndreas.Sandberg@ARM.comdef DebugFlag(name, desc=None):
3579651SAndreas.Sandberg@ARM.com    if name in debug_flags:
3589651SAndreas.Sandberg@ARM.com        raise AttributeError, "Flag %s already specified" % name
3599651SAndreas.Sandberg@ARM.com    debug_flags[name] = (name, (), desc)
3609651SAndreas.Sandberg@ARM.com
3619651SAndreas.Sandberg@ARM.comdef CompoundFlag(name, flags, desc=None):
3629651SAndreas.Sandberg@ARM.com    if name in debug_flags:
3639651SAndreas.Sandberg@ARM.com        raise AttributeError, "Flag %s already specified" % name
3649651SAndreas.Sandberg@ARM.com
3659651SAndreas.Sandberg@ARM.com    compound = tuple(flags)
3669651SAndreas.Sandberg@ARM.com    debug_flags[name] = (name, compound, desc)
3679651SAndreas.Sandberg@ARM.com
3689651SAndreas.Sandberg@ARM.comExport('DebugFlag')
3699651SAndreas.Sandberg@ARM.comExport('CompoundFlag')
3709651SAndreas.Sandberg@ARM.com
3719651SAndreas.Sandberg@ARM.com########################################################################
3729651SAndreas.Sandberg@ARM.com#
3739651SAndreas.Sandberg@ARM.com# Set some compiler variables
3749651SAndreas.Sandberg@ARM.com#
3759651SAndreas.Sandberg@ARM.com
3769651SAndreas.Sandberg@ARM.com# Include file paths are rooted in this directory.  SCons will
3779651SAndreas.Sandberg@ARM.com# automatically expand '.' to refer to both the source directory and
3789651SAndreas.Sandberg@ARM.com# the corresponding build directory to pick up generated include
3799651SAndreas.Sandberg@ARM.com# files.
3809651SAndreas.Sandberg@ARM.comenv.Append(CPPPATH=Dir('.'))
3819651SAndreas.Sandberg@ARM.com
3829651SAndreas.Sandberg@ARM.comfor extra_dir in extras_dir_list:
3839651SAndreas.Sandberg@ARM.com    env.Append(CPPPATH=Dir(extra_dir))
3849651SAndreas.Sandberg@ARM.com
3859651SAndreas.Sandberg@ARM.com# Workaround for bug in SCons version > 0.97d20071212
3869651SAndreas.Sandberg@ARM.com# Scons bug id: 2006 gem5 Bug id: 308
3879651SAndreas.Sandberg@ARM.comfor root, dirs, files in os.walk(base_dir, topdown=True):
3889651SAndreas.Sandberg@ARM.com    Dir(root[len(base_dir) + 1:])
3899651SAndreas.Sandberg@ARM.com
3909651SAndreas.Sandberg@ARM.com########################################################################
3919651SAndreas.Sandberg@ARM.com#
3929651SAndreas.Sandberg@ARM.com# Walk the tree and execute all SConscripts in subdirectories
3939651SAndreas.Sandberg@ARM.com#
3949651SAndreas.Sandberg@ARM.com
3959651SAndreas.Sandberg@ARM.comhere = Dir('.').srcnode().abspath
3969651SAndreas.Sandberg@ARM.comfor root, dirs, files in os.walk(base_dir, topdown=True):
3979651SAndreas.Sandberg@ARM.com    if root == here:
3989651SAndreas.Sandberg@ARM.com        # we don't want to recurse back into this SConscript
3999651SAndreas.Sandberg@ARM.com        continue
4009651SAndreas.Sandberg@ARM.com
4019651SAndreas.Sandberg@ARM.com    if 'SConscript' in files:
4029651SAndreas.Sandberg@ARM.com        build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
4039651SAndreas.Sandberg@ARM.com        Source.set_group(build_dir)
4049651SAndreas.Sandberg@ARM.com        SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
4059651SAndreas.Sandberg@ARM.com
4069651SAndreas.Sandberg@ARM.comfor extra_dir in extras_dir_list:
4079651SAndreas.Sandberg@ARM.com    prefix_len = len(dirname(extra_dir)) + 1
4089651SAndreas.Sandberg@ARM.com
4099651SAndreas.Sandberg@ARM.com    # Also add the corresponding build directory to pick up generated
4109651SAndreas.Sandberg@ARM.com    # include files.
4119651SAndreas.Sandberg@ARM.com    env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:])))
4129651SAndreas.Sandberg@ARM.com
4139651SAndreas.Sandberg@ARM.com    for root, dirs, files in os.walk(extra_dir, topdown=True):
4149652SAndreas.Sandberg@ARM.com        # if build lives in the extras directory, don't walk down it
4159652SAndreas.Sandberg@ARM.com        if 'build' in dirs:
4169652SAndreas.Sandberg@ARM.com            dirs.remove('build')
4179652SAndreas.Sandberg@ARM.com
4189652SAndreas.Sandberg@ARM.com        if 'SConscript' in files:
4199652SAndreas.Sandberg@ARM.com            build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
4209652SAndreas.Sandberg@ARM.com            SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
4219652SAndreas.Sandberg@ARM.com
4229652SAndreas.Sandberg@ARM.comfor opt in export_vars:
4239652SAndreas.Sandberg@ARM.com    env.ConfigFile(opt)
4249652SAndreas.Sandberg@ARM.com
4259651SAndreas.Sandberg@ARM.comdef makeTheISA(source, target, env):
4269651SAndreas.Sandberg@ARM.com    isas = [ src.get_contents() for src in source ]
4279651SAndreas.Sandberg@ARM.com    target_isa = env['TARGET_ISA']
4289651SAndreas.Sandberg@ARM.com    def define(isa):
4299651SAndreas.Sandberg@ARM.com        return isa.upper() + '_ISA'
4309651SAndreas.Sandberg@ARM.com
4319651SAndreas.Sandberg@ARM.com    def namespace(isa):
4329651SAndreas.Sandberg@ARM.com        return isa[0].upper() + isa[1:].lower() + 'ISA'
4339651SAndreas.Sandberg@ARM.com
4349651SAndreas.Sandberg@ARM.com
4359651SAndreas.Sandberg@ARM.com    code = code_formatter()
4369651SAndreas.Sandberg@ARM.com    code('''\
4379651SAndreas.Sandberg@ARM.com#ifndef __CONFIG_THE_ISA_HH__
4389651SAndreas.Sandberg@ARM.com#define __CONFIG_THE_ISA_HH__
4399651SAndreas.Sandberg@ARM.com
4409651SAndreas.Sandberg@ARM.com''')
4419651SAndreas.Sandberg@ARM.com
4429651SAndreas.Sandberg@ARM.com    # create defines for the preprocessing and compile-time determination
4439651SAndreas.Sandberg@ARM.com    for i,isa in enumerate(isas):
4449651SAndreas.Sandberg@ARM.com        code('#define $0 $1', define(isa), i + 1)
4459651SAndreas.Sandberg@ARM.com    code()
4469651SAndreas.Sandberg@ARM.com
4479651SAndreas.Sandberg@ARM.com    # create an enum for any run-time determination of the ISA, we
4489651SAndreas.Sandberg@ARM.com    # reuse the same name as the namespaces
4499651SAndreas.Sandberg@ARM.com    code('enum class Arch {')
4509651SAndreas.Sandberg@ARM.com    for i,isa in enumerate(isas):
4519651SAndreas.Sandberg@ARM.com        if i + 1 == len(isas):
4529651SAndreas.Sandberg@ARM.com            code('  $0 = $1', namespace(isa), define(isa))
4539651SAndreas.Sandberg@ARM.com        else:
4549651SAndreas.Sandberg@ARM.com            code('  $0 = $1,', namespace(isa), define(isa))
4559651SAndreas.Sandberg@ARM.com    code('};')
4569651SAndreas.Sandberg@ARM.com
4579651SAndreas.Sandberg@ARM.com    code('''
4589651SAndreas.Sandberg@ARM.com
4599651SAndreas.Sandberg@ARM.com#define THE_ISA ${{define(target_isa)}}
4609651SAndreas.Sandberg@ARM.com#define TheISA ${{namespace(target_isa)}}
4619651SAndreas.Sandberg@ARM.com#define THE_ISA_STR "${{target_isa}}"
4629651SAndreas.Sandberg@ARM.com
4639651SAndreas.Sandberg@ARM.com#endif // __CONFIG_THE_ISA_HH__''')
4649651SAndreas.Sandberg@ARM.com
4659651SAndreas.Sandberg@ARM.com    code.write(str(target[0]))
4669651SAndreas.Sandberg@ARM.com
4679651SAndreas.Sandberg@ARM.comenv.Command('config/the_isa.hh', map(Value, all_isa_list),
4689651SAndreas.Sandberg@ARM.com            MakeAction(makeTheISA, Transform("CFG ISA", 0)))
4699651SAndreas.Sandberg@ARM.com
4709651SAndreas.Sandberg@ARM.comdef makeTheGPUISA(source, target, env):
4719651SAndreas.Sandberg@ARM.com    isas = [ src.get_contents() for src in source ]
4729651SAndreas.Sandberg@ARM.com    target_gpu_isa = env['TARGET_GPU_ISA']
4739651SAndreas.Sandberg@ARM.com    def define(isa):
4749651SAndreas.Sandberg@ARM.com        return isa.upper() + '_ISA'
4759651SAndreas.Sandberg@ARM.com
4769651SAndreas.Sandberg@ARM.com    def namespace(isa):
4779651SAndreas.Sandberg@ARM.com        return isa[0].upper() + isa[1:].lower() + 'ISA'
4789651SAndreas.Sandberg@ARM.com
4799651SAndreas.Sandberg@ARM.com
4809651SAndreas.Sandberg@ARM.com    code = code_formatter()
4819651SAndreas.Sandberg@ARM.com    code('''\
4829651SAndreas.Sandberg@ARM.com#ifndef __CONFIG_THE_GPU_ISA_HH__
4839651SAndreas.Sandberg@ARM.com#define __CONFIG_THE_GPU_ISA_HH__
4849651SAndreas.Sandberg@ARM.com
4859651SAndreas.Sandberg@ARM.com''')
4869651SAndreas.Sandberg@ARM.com
4879651SAndreas.Sandberg@ARM.com    # create defines for the preprocessing and compile-time determination
4889651SAndreas.Sandberg@ARM.com    for i,isa in enumerate(isas):
4899651SAndreas.Sandberg@ARM.com        code('#define $0 $1', define(isa), i + 1)
4909651SAndreas.Sandberg@ARM.com    code()
4919651SAndreas.Sandberg@ARM.com
4929651SAndreas.Sandberg@ARM.com    # create an enum for any run-time determination of the ISA, we
4939651SAndreas.Sandberg@ARM.com    # reuse the same name as the namespaces
4949651SAndreas.Sandberg@ARM.com    code('enum class GPUArch {')
4959651SAndreas.Sandberg@ARM.com    for i,isa in enumerate(isas):
4969651SAndreas.Sandberg@ARM.com        if i + 1 == len(isas):
4979651SAndreas.Sandberg@ARM.com            code('  $0 = $1', namespace(isa), define(isa))
4989753Sandreas@sandberg.pp.se        else:
4999753Sandreas@sandberg.pp.se            code('  $0 = $1,', namespace(isa), define(isa))
5009753Sandreas@sandberg.pp.se    code('};')
5019753Sandreas@sandberg.pp.se
5029753Sandreas@sandberg.pp.se    code('''
5039753Sandreas@sandberg.pp.se
5049753Sandreas@sandberg.pp.se#define THE_GPU_ISA ${{define(target_gpu_isa)}}
5059753Sandreas@sandberg.pp.se#define TheGpuISA ${{namespace(target_gpu_isa)}}
5069753Sandreas@sandberg.pp.se#define THE_GPU_ISA_STR "${{target_gpu_isa}}"
5079753Sandreas@sandberg.pp.se
5089753Sandreas@sandberg.pp.se#endif // __CONFIG_THE_GPU_ISA_HH__''')
5099753Sandreas@sandberg.pp.se
5109753Sandreas@sandberg.pp.se    code.write(str(target[0]))
5119753Sandreas@sandberg.pp.se
5129753Sandreas@sandberg.pp.seenv.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list),
5139753Sandreas@sandberg.pp.se            MakeAction(makeTheGPUISA, Transform("CFG ISA", 0)))
5149753Sandreas@sandberg.pp.se
5159753Sandreas@sandberg.pp.se########################################################################
5169651SAndreas.Sandberg@ARM.com#
5179651SAndreas.Sandberg@ARM.com# Prevent any SimObjects from being added after this point, they
5189651SAndreas.Sandberg@ARM.com# should all have been added in the SConscripts above
5199651SAndreas.Sandberg@ARM.com#
5209651SAndreas.Sandberg@ARM.comSimObject.fixed = True
5219651SAndreas.Sandberg@ARM.com
5229651SAndreas.Sandberg@ARM.comclass DictImporter(object):
5239651SAndreas.Sandberg@ARM.com    '''This importer takes a dictionary of arbitrary module names that
5249651SAndreas.Sandberg@ARM.com    map to arbitrary filenames.'''
5259651SAndreas.Sandberg@ARM.com    def __init__(self, modules):
5269753Sandreas@sandberg.pp.se        self.modules = modules
5279753Sandreas@sandberg.pp.se        self.installed = set()
5289753Sandreas@sandberg.pp.se
5299753Sandreas@sandberg.pp.se    def __del__(self):
5309753Sandreas@sandberg.pp.se        self.unload()
5319753Sandreas@sandberg.pp.se
5329753Sandreas@sandberg.pp.se    def unload(self):
5339753Sandreas@sandberg.pp.se        import sys
5349753Sandreas@sandberg.pp.se        for module in self.installed:
5359753Sandreas@sandberg.pp.se            del sys.modules[module]
5369753Sandreas@sandberg.pp.se        self.installed = set()
5379753Sandreas@sandberg.pp.se
5389753Sandreas@sandberg.pp.se    def find_module(self, fullname, path):
5399753Sandreas@sandberg.pp.se        if fullname == 'm5.defines':
5409753Sandreas@sandberg.pp.se            return self
5419651SAndreas.Sandberg@ARM.com
5429651SAndreas.Sandberg@ARM.com        if fullname == 'm5.objects':
5439651SAndreas.Sandberg@ARM.com            return self
5449651SAndreas.Sandberg@ARM.com
5459651SAndreas.Sandberg@ARM.com        if fullname.startswith('_m5'):
5469651SAndreas.Sandberg@ARM.com            return None
5479651SAndreas.Sandberg@ARM.com
5489651SAndreas.Sandberg@ARM.com        source = self.modules.get(fullname, None)
5499651SAndreas.Sandberg@ARM.com        if source is not None and fullname.startswith('m5.objects'):
5509651SAndreas.Sandberg@ARM.com            return self
5519651SAndreas.Sandberg@ARM.com
5529651SAndreas.Sandberg@ARM.com        return None
5539651SAndreas.Sandberg@ARM.com
5549651SAndreas.Sandberg@ARM.com    def load_module(self, fullname):
5559651SAndreas.Sandberg@ARM.com        mod = imp.new_module(fullname)
5569651SAndreas.Sandberg@ARM.com        sys.modules[fullname] = mod
5579651SAndreas.Sandberg@ARM.com        self.installed.add(fullname)
5589651SAndreas.Sandberg@ARM.com
5599651SAndreas.Sandberg@ARM.com        mod.__loader__ = self
5609651SAndreas.Sandberg@ARM.com        if fullname == 'm5.objects':
5619651SAndreas.Sandberg@ARM.com            mod.__path__ = fullname.split('.')
5629651SAndreas.Sandberg@ARM.com            return mod
5639651SAndreas.Sandberg@ARM.com
5649688Sandreas@sandberg.pp.se        if fullname == 'm5.defines':
5659688Sandreas@sandberg.pp.se            mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
56611629Smichael.lebeane@amd.com            return mod
56711629Smichael.lebeane@amd.com
5689688Sandreas@sandberg.pp.se        source = self.modules[fullname]
5699688Sandreas@sandberg.pp.se        if source.modname == '__init__':
5709688Sandreas@sandberg.pp.se            mod.__path__ = source.modpath
5719688Sandreas@sandberg.pp.se        mod.__file__ = source.abspath
5729688Sandreas@sandberg.pp.se
5739688Sandreas@sandberg.pp.se        exec file(source.abspath, 'r') in mod.__dict__
57411629Smichael.lebeane@amd.com
5759688Sandreas@sandberg.pp.se        return mod
57611629Smichael.lebeane@amd.com
57711629Smichael.lebeane@amd.comimport m5.SimObject
57811629Smichael.lebeane@amd.comimport m5.params
57911629Smichael.lebeane@amd.comfrom m5.util import code_formatter
58011629Smichael.lebeane@amd.com
58111629Smichael.lebeane@amd.comm5.SimObject.clear()
58211629Smichael.lebeane@amd.comm5.params.clear()
58311629Smichael.lebeane@amd.com
58411629Smichael.lebeane@amd.com# install the python importer so we can grab stuff from the source
5859688Sandreas@sandberg.pp.se# tree itself.  We can't have SimObjects added after this point or
5869688Sandreas@sandberg.pp.se# else we won't know about them for the rest of the stuff.
58711629Smichael.lebeane@amd.comimporter = DictImporter(PySource.modules)
58811629Smichael.lebeane@amd.comsys.meta_path[0:0] = [ importer ]
5899688Sandreas@sandberg.pp.se
59011629Smichael.lebeane@amd.com# import all sim objects so we can populate the all_objects list
59111629Smichael.lebeane@amd.com# make sure that we're working with a list, then let's sort it
59211629Smichael.lebeane@amd.comfor modname in SimObject.modnames:
59311629Smichael.lebeane@amd.com    exec('from m5.objects import %s' % modname)
59411629Smichael.lebeane@amd.com
59511629Smichael.lebeane@amd.com# we need to unload all of the currently imported modules so that they
59611629Smichael.lebeane@amd.com# will be re-imported the next time the sconscript is run
59711629Smichael.lebeane@amd.comimporter.unload()
59811629Smichael.lebeane@amd.comsys.meta_path.remove(importer)
5999688Sandreas@sandberg.pp.se
6009688Sandreas@sandberg.pp.sesim_objects = m5.SimObject.allClasses
6019688Sandreas@sandberg.pp.seall_enums = m5.params.allEnums
6029651SAndreas.Sandberg@ARM.com
6039688Sandreas@sandberg.pp.sefor name,obj in sorted(sim_objects.iteritems()):
6049651SAndreas.Sandberg@ARM.com    for param in obj._params.local.values():
6059651SAndreas.Sandberg@ARM.com        # load the ptype attribute now because it depends on the
6069688Sandreas@sandberg.pp.se        # current version of SimObject.allClasses, but when scons
6079651SAndreas.Sandberg@ARM.com        # actually uses the value, all versions of
6089651SAndreas.Sandberg@ARM.com        # SimObject.allClasses will have been loaded
60911399Sandreas.sandberg@arm.com        param.ptype
61011399Sandreas.sandberg@arm.com
61111399Sandreas.sandberg@arm.com########################################################################
61211399Sandreas.sandberg@arm.com#
61311399Sandreas.sandberg@arm.com# calculate extra dependencies
61411399Sandreas.sandberg@arm.com#
6159651SAndreas.Sandberg@ARM.commodule_depends = ["m5", "m5.SimObject", "m5.params"]
6169651SAndreas.Sandberg@ARM.comdepends = [ PySource.modules[dep].snode for dep in module_depends ]
6179651SAndreas.Sandberg@ARM.comdepends.sort(key = lambda x: x.name)
6189652SAndreas.Sandberg@ARM.com
6199652SAndreas.Sandberg@ARM.com########################################################################
6209652SAndreas.Sandberg@ARM.com#
6219652SAndreas.Sandberg@ARM.com# Commands for the basic automatically generated python files
6229652SAndreas.Sandberg@ARM.com#
6239652SAndreas.Sandberg@ARM.com
6249652SAndreas.Sandberg@ARM.com# Generate Python file containing a dict specifying the current
6259651SAndreas.Sandberg@ARM.com# buildEnv flags.
6269651SAndreas.Sandberg@ARM.comdef makeDefinesPyFile(target, source, env):
6279651SAndreas.Sandberg@ARM.com    build_env = source[0].get_contents()
6289651SAndreas.Sandberg@ARM.com
62910114Sandreas@sandberg.pp.se    code = code_formatter()
63010114Sandreas@sandberg.pp.se    code("""
63110114Sandreas@sandberg.pp.seimport _m5.core
6329651SAndreas.Sandberg@ARM.comimport m5.util
6339651SAndreas.Sandberg@ARM.com
6349651SAndreas.Sandberg@ARM.combuildEnv = m5.util.SmartDict($build_env)
6359651SAndreas.Sandberg@ARM.com
6369651SAndreas.Sandberg@ARM.comcompileDate = _m5.core.compileDate
6379651SAndreas.Sandberg@ARM.com_globals = globals()
6389651SAndreas.Sandberg@ARM.comfor key,val in _m5.core.__dict__.iteritems():
6399651SAndreas.Sandberg@ARM.com    if key.startswith('flag_'):
6409651SAndreas.Sandberg@ARM.com        flag = key[5:]
6419651SAndreas.Sandberg@ARM.com        _globals[flag] = val
6429651SAndreas.Sandberg@ARM.comdel _globals
6439651SAndreas.Sandberg@ARM.com""")
6449651SAndreas.Sandberg@ARM.com    code.write(target[0].abspath)
6459651SAndreas.Sandberg@ARM.com
6469651SAndreas.Sandberg@ARM.comdefines_info = Value(build_env)
6479651SAndreas.Sandberg@ARM.com# Generate a file with all of the compile options in it
6489651SAndreas.Sandberg@ARM.comenv.Command('python/m5/defines.py', defines_info,
6499651SAndreas.Sandberg@ARM.com            MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
6509651SAndreas.Sandberg@ARM.comPySource('m5', 'python/m5/defines.py')
6519651SAndreas.Sandberg@ARM.com
6529651SAndreas.Sandberg@ARM.com# Generate python file containing info about the M5 source code
6539651SAndreas.Sandberg@ARM.comdef makeInfoPyFile(target, source, env):
6549651SAndreas.Sandberg@ARM.com    code = code_formatter()
6559651SAndreas.Sandberg@ARM.com    for src in source:
6569651SAndreas.Sandberg@ARM.com        data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
6579651SAndreas.Sandberg@ARM.com        code('$src = ${{repr(data)}}')
6589651SAndreas.Sandberg@ARM.com    code.write(str(target[0]))
6599651SAndreas.Sandberg@ARM.com
6609651SAndreas.Sandberg@ARM.com# Generate a file that wraps the basic top level files
6619651SAndreas.Sandberg@ARM.comenv.Command('python/m5/info.py',
6629753Sandreas@sandberg.pp.se            [ '#/COPYING', '#/LICENSE', '#/README', ],
6639753Sandreas@sandberg.pp.se            MakeAction(makeInfoPyFile, Transform("INFO")))
6649753Sandreas@sandberg.pp.sePySource('m5', 'python/m5/info.py')
6659753Sandreas@sandberg.pp.se
6669753Sandreas@sandberg.pp.se########################################################################
6679753Sandreas@sandberg.pp.se#
6689753Sandreas@sandberg.pp.se# Create all of the SimObject param headers and enum headers
6699753Sandreas@sandberg.pp.se#
67010073Sandreas@sandberg.pp.se
67110073Sandreas@sandberg.pp.sedef createSimObjectParamStruct(target, source, env):
67210073Sandreas@sandberg.pp.se    assert len(target) == 1 and len(source) == 1
67310073Sandreas@sandberg.pp.se
67410073Sandreas@sandberg.pp.se    name = source[0].get_text_contents()
67510073Sandreas@sandberg.pp.se    obj = sim_objects[name]
67610073Sandreas@sandberg.pp.se
67710073Sandreas@sandberg.pp.se    code = code_formatter()
67810073Sandreas@sandberg.pp.se    obj.cxx_param_decl(code)
67910073Sandreas@sandberg.pp.se    code.write(target[0].abspath)
68010073Sandreas@sandberg.pp.se
68110073Sandreas@sandberg.pp.sedef createSimObjectCxxConfig(is_header):
68210073Sandreas@sandberg.pp.se    def body(target, source, env):
68310073Sandreas@sandberg.pp.se        assert len(target) == 1 and len(source) == 1
6849753Sandreas@sandberg.pp.se
6859753Sandreas@sandberg.pp.se        name = str(source[0].get_contents())
6869753Sandreas@sandberg.pp.se        obj = sim_objects[name]
6879753Sandreas@sandberg.pp.se
6889753Sandreas@sandberg.pp.se        code = code_formatter()
6899753Sandreas@sandberg.pp.se        obj.cxx_config_param_file(code, is_header)
6909651SAndreas.Sandberg@ARM.com        code.write(target[0].abspath)
6919651SAndreas.Sandberg@ARM.com    return body
6929651SAndreas.Sandberg@ARM.com
6939651SAndreas.Sandberg@ARM.comdef createEnumStrings(target, source, env):
6949651SAndreas.Sandberg@ARM.com    assert len(target) == 1 and len(source) == 2
6959651SAndreas.Sandberg@ARM.com
6969651SAndreas.Sandberg@ARM.com    name = source[0].get_text_contents()
6979651SAndreas.Sandberg@ARM.com    use_python = source[1].read()
6989651SAndreas.Sandberg@ARM.com    obj = all_enums[name]
6999651SAndreas.Sandberg@ARM.com
7009651SAndreas.Sandberg@ARM.com    code = code_formatter()
7019651SAndreas.Sandberg@ARM.com    obj.cxx_def(code)
7029651SAndreas.Sandberg@ARM.com    if use_python:
7039651SAndreas.Sandberg@ARM.com        obj.pybind_def(code)
7049651SAndreas.Sandberg@ARM.com    code.write(target[0].abspath)
7059651SAndreas.Sandberg@ARM.com
7069651SAndreas.Sandberg@ARM.comdef createEnumDecls(target, source, env):
7079651SAndreas.Sandberg@ARM.com    assert len(target) == 1 and len(source) == 1
7089651SAndreas.Sandberg@ARM.com
7099651SAndreas.Sandberg@ARM.com    name = source[0].get_text_contents()
7109651SAndreas.Sandberg@ARM.com    obj = all_enums[name]
7119651SAndreas.Sandberg@ARM.com
7129651SAndreas.Sandberg@ARM.com    code = code_formatter()
7139892Sandreas@sandberg.pp.se    obj.cxx_decl(code)
7149892Sandreas@sandberg.pp.se    code.write(target[0].abspath)
7159892Sandreas@sandberg.pp.se
7169892Sandreas@sandberg.pp.sedef createSimObjectPyBindWrapper(target, source, env):
7179892Sandreas@sandberg.pp.se    name = source[0].get_text_contents()
7189892Sandreas@sandberg.pp.se    obj = sim_objects[name]
7199892Sandreas@sandberg.pp.se
7209892Sandreas@sandberg.pp.se    code = code_formatter()
7219892Sandreas@sandberg.pp.se    obj.pybind_decl(code)
7229892Sandreas@sandberg.pp.se    code.write(target[0].abspath)
7239892Sandreas@sandberg.pp.se
7249892Sandreas@sandberg.pp.se# Generate all of the SimObject param C++ struct header files
7259651SAndreas.Sandberg@ARM.comparams_hh_files = []
7269892Sandreas@sandberg.pp.sefor name,simobj in sorted(sim_objects.iteritems()):
7279892Sandreas@sandberg.pp.se    py_source = PySource.modules[simobj.__module__]
7289892Sandreas@sandberg.pp.se    extra_deps = [ py_source.tnode ]
7299892Sandreas@sandberg.pp.se
7309892Sandreas@sandberg.pp.se    hh_file = File('params/%s.hh' % name)
7319892Sandreas@sandberg.pp.se    params_hh_files.append(hh_file)
7329892Sandreas@sandberg.pp.se    env.Command(hh_file, Value(name),
7339892Sandreas@sandberg.pp.se                MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
7349892Sandreas@sandberg.pp.se    env.Depends(hh_file, depends + extra_deps)
7359892Sandreas@sandberg.pp.se
7369892Sandreas@sandberg.pp.se# C++ parameter description files
7379892Sandreas@sandberg.pp.seif GetOption('with_cxx_config'):
7389892Sandreas@sandberg.pp.se    for name,simobj in sorted(sim_objects.iteritems()):
7399892Sandreas@sandberg.pp.se        py_source = PySource.modules[simobj.__module__]
7409892Sandreas@sandberg.pp.se        extra_deps = [ py_source.tnode ]
7419892Sandreas@sandberg.pp.se
7429892Sandreas@sandberg.pp.se        cxx_config_hh_file = File('cxx_config/%s.hh' % name)
7439892Sandreas@sandberg.pp.se        cxx_config_cc_file = File('cxx_config/%s.cc' % name)
7449892Sandreas@sandberg.pp.se        env.Command(cxx_config_hh_file, Value(name),
7459892Sandreas@sandberg.pp.se                    MakeAction(createSimObjectCxxConfig(True),
7469892Sandreas@sandberg.pp.se                    Transform("CXXCPRHH")))
7479892Sandreas@sandberg.pp.se        env.Command(cxx_config_cc_file, Value(name),
7489892Sandreas@sandberg.pp.se                    MakeAction(createSimObjectCxxConfig(False),
7499892Sandreas@sandberg.pp.se                    Transform("CXXCPRCC")))
7509892Sandreas@sandberg.pp.se        env.Depends(cxx_config_hh_file, depends + extra_deps +
7519892Sandreas@sandberg.pp.se                    [File('params/%s.hh' % name), File('sim/cxx_config.hh')])
7529651SAndreas.Sandberg@ARM.com        env.Depends(cxx_config_cc_file, depends + extra_deps +
7539892Sandreas@sandberg.pp.se                    [cxx_config_hh_file])
7549892Sandreas@sandberg.pp.se        Source(cxx_config_cc_file)
7559892Sandreas@sandberg.pp.se
7569892Sandreas@sandberg.pp.se    cxx_config_init_cc_file = File('cxx_config/init.cc')
7579892Sandreas@sandberg.pp.se
7589892Sandreas@sandberg.pp.se    def createCxxConfigInitCC(target, source, env):
7599892Sandreas@sandberg.pp.se        assert len(target) == 1 and len(source) == 1
7609892Sandreas@sandberg.pp.se
7619892Sandreas@sandberg.pp.se        code = code_formatter()
7629892Sandreas@sandberg.pp.se
7639892Sandreas@sandberg.pp.se        for name,simobj in sorted(sim_objects.iteritems()):
7649892Sandreas@sandberg.pp.se            if not hasattr(simobj, 'abstract') or not simobj.abstract:
7659651SAndreas.Sandberg@ARM.com                code('#include "cxx_config/${name}.hh"')
7669651SAndreas.Sandberg@ARM.com        code()
7679651SAndreas.Sandberg@ARM.com        code('void cxxConfigInit()')
7689655SAndreas.Sandberg@ARM.com        code('{')
7699655SAndreas.Sandberg@ARM.com        code.indent()
7709655SAndreas.Sandberg@ARM.com        for name,simobj in sorted(sim_objects.iteritems()):
7719655SAndreas.Sandberg@ARM.com            not_abstract = not hasattr(simobj, 'abstract') or \
7729655SAndreas.Sandberg@ARM.com                not simobj.abstract
7739655SAndreas.Sandberg@ARM.com            if not_abstract and 'type' in simobj.__dict__:
7749655SAndreas.Sandberg@ARM.com                code('cxx_config_directory["${name}"] = '
7759892Sandreas@sandberg.pp.se                     '${name}CxxConfigParams::makeDirectoryEntry();')
7769655SAndreas.Sandberg@ARM.com        code.dedent()
7779655SAndreas.Sandberg@ARM.com        code('}')
7789651SAndreas.Sandberg@ARM.com        code.write(target[0].abspath)
7799651SAndreas.Sandberg@ARM.com
7809651SAndreas.Sandberg@ARM.com    py_source = PySource.modules[simobj.__module__]
7819651SAndreas.Sandberg@ARM.com    extra_deps = [ py_source.tnode ]
7829651SAndreas.Sandberg@ARM.com    env.Command(cxx_config_init_cc_file, Value(name),
7839651SAndreas.Sandberg@ARM.com        MakeAction(createCxxConfigInitCC, Transform("CXXCINIT")))
7849651SAndreas.Sandberg@ARM.com    cxx_param_hh_files = ["cxx_config/%s.hh" % simobj
7859754Sandreas@sandberg.pp.se        for name,simobj in sorted(sim_objects.iteritems())
7869651SAndreas.Sandberg@ARM.com        if not hasattr(simobj, 'abstract') or not simobj.abstract]
7879651SAndreas.Sandberg@ARM.com    Depends(cxx_config_init_cc_file, cxx_param_hh_files +
7889651SAndreas.Sandberg@ARM.com            [File('sim/cxx_config.hh')])
7899651SAndreas.Sandberg@ARM.com    Source(cxx_config_init_cc_file)
7909684Sandreas@sandberg.pp.se
7919651SAndreas.Sandberg@ARM.com# Generate all enum header files
7929755Sandreas@sandberg.pp.sefor name,enum in sorted(all_enums.iteritems()):
7939755Sandreas@sandberg.pp.se    py_source = PySource.modules[enum.__module__]
7949651SAndreas.Sandberg@ARM.com    extra_deps = [ py_source.tnode ]
7959651SAndreas.Sandberg@ARM.com
7969651SAndreas.Sandberg@ARM.com    cc_file = File('enums/%s.cc' % name)
7979651SAndreas.Sandberg@ARM.com    env.Command(cc_file, [Value(name), Value(env['USE_PYTHON'])],
7989651SAndreas.Sandberg@ARM.com                MakeAction(createEnumStrings, Transform("ENUM STR")))
7999651SAndreas.Sandberg@ARM.com    env.Depends(cc_file, depends + extra_deps)
8009651SAndreas.Sandberg@ARM.com    Source(cc_file)
8019752Sandreas@sandberg.pp.se
8029752Sandreas@sandberg.pp.se    hh_file = File('enums/%s.hh' % name)
8039752Sandreas@sandberg.pp.se    env.Command(hh_file, Value(name),
8049651SAndreas.Sandberg@ARM.com                MakeAction(createEnumDecls, Transform("ENUMDECL")))
8059651SAndreas.Sandberg@ARM.com    env.Depends(hh_file, depends + extra_deps)
8069651SAndreas.Sandberg@ARM.com
807# Generate SimObject Python bindings wrapper files
808if env['USE_PYTHON']:
809    for name,simobj in sorted(sim_objects.iteritems()):
810        py_source = PySource.modules[simobj.__module__]
811        extra_deps = [ py_source.tnode ]
812        cc_file = File('python/_m5/param_%s.cc' % name)
813        env.Command(cc_file, Value(name),
814                    MakeAction(createSimObjectPyBindWrapper,
815                               Transform("SO PyBind")))
816        env.Depends(cc_file, depends + extra_deps)
817        Source(cc_file)
818
819# Build all protocol buffers if we have got protoc and protobuf available
820if env['HAVE_PROTOBUF']:
821    for proto in ProtoBuf.all:
822        # Use both the source and header as the target, and the .proto
823        # file as the source. When executing the protoc compiler, also
824        # specify the proto_path to avoid having the generated files
825        # include the path.
826        env.Command([proto.cc_file, proto.hh_file], proto.tnode,
827                    MakeAction('$PROTOC --cpp_out ${TARGET.dir} '
828                               '--proto_path ${SOURCE.dir} $SOURCE',
829                               Transform("PROTOC")))
830
831        # Add the C++ source file
832        Source(proto.cc_file, tags=proto.tags)
833elif ProtoBuf.all:
834    print 'Got protobuf to build, but lacks support!'
835    Exit(1)
836
837#
838# Handle debug flags
839#
840def makeDebugFlagCC(target, source, env):
841    assert(len(target) == 1 and len(source) == 1)
842
843    code = code_formatter()
844
845    # delay definition of CompoundFlags until after all the definition
846    # of all constituent SimpleFlags
847    comp_code = code_formatter()
848
849    # file header
850    code('''
851/*
852 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
853 */
854
855#include "base/debug.hh"
856
857namespace Debug {
858
859''')
860
861    for name, flag in sorted(source[0].read().iteritems()):
862        n, compound, desc = flag
863        assert n == name
864
865        if not compound:
866            code('SimpleFlag $name("$name", "$desc");')
867        else:
868            comp_code('CompoundFlag $name("$name", "$desc",')
869            comp_code.indent()
870            last = len(compound) - 1
871            for i,flag in enumerate(compound):
872                if i != last:
873                    comp_code('&$flag,')
874                else:
875                    comp_code('&$flag);')
876            comp_code.dedent()
877
878    code.append(comp_code)
879    code()
880    code('} // namespace Debug')
881
882    code.write(str(target[0]))
883
884def makeDebugFlagHH(target, source, env):
885    assert(len(target) == 1 and len(source) == 1)
886
887    val = eval(source[0].get_contents())
888    name, compound, desc = val
889
890    code = code_formatter()
891
892    # file header boilerplate
893    code('''\
894/*
895 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
896 */
897
898#ifndef __DEBUG_${name}_HH__
899#define __DEBUG_${name}_HH__
900
901namespace Debug {
902''')
903
904    if compound:
905        code('class CompoundFlag;')
906    code('class SimpleFlag;')
907
908    if compound:
909        code('extern CompoundFlag $name;')
910        for flag in compound:
911            code('extern SimpleFlag $flag;')
912    else:
913        code('extern SimpleFlag $name;')
914
915    code('''
916}
917
918#endif // __DEBUG_${name}_HH__
919''')
920
921    code.write(str(target[0]))
922
923for name,flag in sorted(debug_flags.iteritems()):
924    n, compound, desc = flag
925    assert n == name
926
927    hh_file = 'debug/%s.hh' % name
928    env.Command(hh_file, Value(flag),
929                MakeAction(makeDebugFlagHH, Transform("TRACING", 0)))
930
931env.Command('debug/flags.cc', Value(debug_flags),
932            MakeAction(makeDebugFlagCC, Transform("TRACING", 0)))
933Source('debug/flags.cc')
934
935# version tags
936tags = \
937env.Command('sim/tags.cc', None,
938            MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET',
939                       Transform("VER TAGS")))
940env.AlwaysBuild(tags)
941
942# Embed python files.  All .py files that have been indicated by a
943# PySource() call in a SConscript need to be embedded into the M5
944# library.  To do that, we compile the file to byte code, marshal the
945# byte code, compress it, and then generate a c++ file that
946# inserts the result into an array.
947def embedPyFile(target, source, env):
948    def c_str(string):
949        if string is None:
950            return "0"
951        return '"%s"' % string
952
953    '''Action function to compile a .py into a code object, marshal
954    it, compress it, and stick it into an asm file so the code appears
955    as just bytes with a label in the data section'''
956
957    src = file(str(source[0]), 'r').read()
958
959    pysource = PySource.tnodes[source[0]]
960    compiled = compile(src, pysource.abspath, 'exec')
961    marshalled = marshal.dumps(compiled)
962    compressed = zlib.compress(marshalled)
963    data = compressed
964    sym = pysource.symname
965
966    code = code_formatter()
967    code('''\
968#include "sim/init.hh"
969
970namespace {
971
972const uint8_t data_${sym}[] = {
973''')
974    code.indent()
975    step = 16
976    for i in xrange(0, len(data), step):
977        x = array.array('B', data[i:i+step])
978        code(''.join('%d,' % d for d in x))
979    code.dedent()
980
981    code('''};
982
983EmbeddedPython embedded_${sym}(
984    ${{c_str(pysource.arcname)}},
985    ${{c_str(pysource.abspath)}},
986    ${{c_str(pysource.modpath)}},
987    data_${sym},
988    ${{len(data)}},
989    ${{len(marshalled)}});
990
991} // anonymous namespace
992''')
993    code.write(str(target[0]))
994
995for source in PySource.all:
996    env.Command(source.cpp, source.tnode,
997                MakeAction(embedPyFile, Transform("EMBED PY")))
998    Source(source.cpp, tags=source.tags, add_tags='python')
999
1000########################################################################
1001#
1002# Define binaries.  Each different build type (debug, opt, etc.) gets
1003# a slightly different build environment.
1004#
1005
1006# List of constructed environments to pass back to SConstruct
1007date_source = Source('base/date.cc', tags=[])
1008
1009# Function to create a new build environment as clone of current
1010# environment 'env' with modified object suffix and optional stripped
1011# binary.  Additional keyword arguments are appended to corresponding
1012# build environment vars.
1013def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs):
1014    # SCons doesn't know to append a library suffix when there is a '.' in the
1015    # name.  Use '_' instead.
1016    libname = 'gem5_' + label
1017    exename = 'gem5.' + label
1018    secondary_exename = 'm5.' + label
1019
1020    new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
1021    new_env.Label = label
1022    new_env.Append(**kwargs)
1023
1024    lib_sources = Source.all.with_tag('gem5 lib')
1025
1026    # Without Python, leave out all Python content from the library
1027    # builds.  The option doesn't affect gem5 built as a program
1028    if GetOption('without_python'):
1029        lib_sources = lib_sources.without_tag('python')
1030
1031    static_objs = []
1032    shared_objs = []
1033
1034    for s in lib_sources.with_tag(Source.ungrouped_tag):
1035        static_objs.append(s.static(new_env))
1036        shared_objs.append(s.shared(new_env))
1037
1038    for group in Source.source_groups:
1039        srcs = lib_sources.with_tag(Source.link_group_tag(group))
1040        if not srcs:
1041            continue
1042
1043        group_static = [ s.static(new_env) for s in srcs ]
1044        group_shared = [ s.shared(new_env) for s in srcs ]
1045
1046        # If partial linking is disabled, add these sources to the build
1047        # directly, and short circuit this loop.
1048        if disable_partial:
1049            static_objs.extend(group_static)
1050            shared_objs.extend(group_shared)
1051            continue
1052
1053        # Set up the static partially linked objects.
1054        file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial")
1055        target = File(joinpath(group, file_name))
1056        partial = env.PartialStatic(target=target, source=group_static)
1057        static_objs.extend(partial)
1058
1059        # Set up the shared partially linked objects.
1060        file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial")
1061        target = File(joinpath(group, file_name))
1062        partial = env.PartialShared(target=target, source=group_shared)
1063        shared_objs.extend(partial)
1064
1065    static_date = date_source.static(new_env)
1066    new_env.Depends(static_date, static_objs)
1067    static_objs.extend(static_date)
1068
1069    shared_date = date_source.shared(new_env)
1070    new_env.Depends(shared_date, shared_objs)
1071    shared_objs.extend(shared_date)
1072
1073    # First make a library of everything but main() so other programs can
1074    # link against m5.
1075    static_lib = new_env.StaticLibrary(libname, static_objs)
1076    shared_lib = new_env.SharedLibrary(libname, shared_objs)
1077
1078    # Now link a stub with main() and the static library.
1079    main_objs = [ s.static(new_env) for s in Source.all.with_tag('main') ]
1080
1081    for test in UnitTest.all:
1082        test_sources = Source.all.with_tag(str(test.target))
1083        test_objs = [ s.static(new_env) for s in test_sources ]
1084        if test.main:
1085            test_objs += main_objs
1086        path = 'unittest/%s.%s' % (test.target, label)
1087        new_env.Program(path, test_objs + static_objs)
1088
1089    gtest_env = new_env.Clone()
1090    gtest_env.Append(LIBS=gtest_env['GTEST_LIBS'])
1091    gtest_env.Append(CPPFLAGS=gtest_env['GTEST_CPPFLAGS'])
1092    gtestlib_sources = Source.all.with_tag('gtest lib')
1093    gtest_out_dir = Dir(new_env['BUILDDIR']).Dir('unittests.%s' % label)
1094    for test in GTest.all:
1095        test_sources = list(test.sources)
1096        if not test.skip_lib:
1097            test_sources += gtestlib_sources
1098        for f in test.filters:
1099            test_sources += Source.all.apply_filter(f)
1100        test_objs = [ s.static(gtest_env) for s in test_sources ]
1101        test_binary = gtest_env.Program(
1102            test.dir.File('%s.%s' % (test.target, label)), test_objs)
1103
1104        AlwaysBuild(gtest_env.Command(
1105            gtest_out_dir.File("%s/%s.xml" % (test.dir, test.target)),
1106            test_binary, "${SOURCES[0]} --gtest_output=xml:${TARGETS[0]}"))
1107
1108    progname = exename
1109    if strip:
1110        progname += '.unstripped'
1111
1112    targets = new_env.Program(progname, main_objs + static_objs)
1113
1114    if strip:
1115        if sys.platform == 'sunos5':
1116            cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1117        else:
1118            cmd = 'strip $SOURCE -o $TARGET'
1119        targets = new_env.Command(exename, progname,
1120                    MakeAction(cmd, Transform("STRIP")))
1121
1122    new_env.Command(secondary_exename, exename,
1123            MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK")))
1124
1125    new_env.M5Binary = targets[0]
1126
1127    # Set up regression tests.
1128    SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'),
1129               variant_dir=Dir('tests').Dir(new_env.Label),
1130               exports={ 'env' : new_env }, duplicate=False)
1131
1132# Start out with the compiler flags common to all compilers,
1133# i.e. they all use -g for opt and -g -pg for prof
1134ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'],
1135           'perf' : ['-g']}
1136
1137# Start out with the linker flags common to all linkers, i.e. -pg for
1138# prof, and -lprofiler for perf. The -lprofile flag is surrounded by
1139# no-as-needed and as-needed as the binutils linker is too clever and
1140# simply doesn't link to the library otherwise.
1141ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'],
1142           'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']}
1143
1144# For Link Time Optimization, the optimisation flags used to compile
1145# individual files are decoupled from those used at link time
1146# (i.e. you can compile with -O3 and perform LTO with -O0), so we need
1147# to also update the linker flags based on the target.
1148if env['GCC']:
1149    if sys.platform == 'sunos5':
1150        ccflags['debug'] += ['-gstabs+']
1151    else:
1152        ccflags['debug'] += ['-ggdb3']
1153    ldflags['debug'] += ['-O0']
1154    # opt, fast, prof and perf all share the same cc flags, also add
1155    # the optimization to the ldflags as LTO defers the optimization
1156    # to link time
1157    for target in ['opt', 'fast', 'prof', 'perf']:
1158        ccflags[target] += ['-O3']
1159        ldflags[target] += ['-O3']
1160
1161    ccflags['fast'] += env['LTO_CCFLAGS']
1162    ldflags['fast'] += env['LTO_LDFLAGS']
1163elif env['CLANG']:
1164    ccflags['debug'] += ['-g', '-O0']
1165    # opt, fast, prof and perf all share the same cc flags
1166    for target in ['opt', 'fast', 'prof', 'perf']:
1167        ccflags[target] += ['-O3']
1168else:
1169    print 'Unknown compiler, please fix compiler options'
1170    Exit(1)
1171
1172
1173# To speed things up, we only instantiate the build environments we
1174# need.  We try to identify the needed environment for each target; if
1175# we can't, we fall back on instantiating all the environments just to
1176# be safe.
1177target_types = ['debug', 'opt', 'fast', 'prof', 'perf']
1178obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof',
1179              'gpo' : 'perf'}
1180
1181def identifyTarget(t):
1182    ext = t.split('.')[-1]
1183    if ext in target_types:
1184        return ext
1185    if obj2target.has_key(ext):
1186        return obj2target[ext]
1187    match = re.search(r'/tests/([^/]+)/', t)
1188    if match and match.group(1) in target_types:
1189        return match.group(1)
1190    return 'all'
1191
1192needed_envs = [identifyTarget(target) for target in BUILD_TARGETS]
1193if 'all' in needed_envs:
1194    needed_envs += target_types
1195
1196# Debug binary
1197if 'debug' in needed_envs:
1198    makeEnv(env, 'debug', '.do',
1199            CCFLAGS = Split(ccflags['debug']),
1200            CPPDEFINES = ['DEBUG', 'TRACING_ON=1'],
1201            LINKFLAGS = Split(ldflags['debug']))
1202
1203# Optimized binary
1204if 'opt' in needed_envs:
1205    makeEnv(env, 'opt', '.o',
1206            CCFLAGS = Split(ccflags['opt']),
1207            CPPDEFINES = ['TRACING_ON=1'],
1208            LINKFLAGS = Split(ldflags['opt']))
1209
1210# "Fast" binary
1211if 'fast' in needed_envs:
1212    disable_partial = \
1213            env.get('BROKEN_INCREMENTAL_LTO', False) and \
1214            GetOption('force_lto')
1215    makeEnv(env, 'fast', '.fo', strip = True,
1216            CCFLAGS = Split(ccflags['fast']),
1217            CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1218            LINKFLAGS = Split(ldflags['fast']),
1219            disable_partial=disable_partial)
1220
1221# Profiled binary using gprof
1222if 'prof' in needed_envs:
1223    makeEnv(env, 'prof', '.po',
1224            CCFLAGS = Split(ccflags['prof']),
1225            CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1226            LINKFLAGS = Split(ldflags['prof']))
1227
1228# Profiled binary using google-pprof
1229if 'perf' in needed_envs:
1230    makeEnv(env, 'perf', '.gpo',
1231            CCFLAGS = Split(ccflags['perf']),
1232            CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1233            LINKFLAGS = Split(ldflags['perf']))
1234