SConscript revision 12305
112922Sgabeblack@google.com# -*- mode:python -*-
212922Sgabeblack@google.com
312922Sgabeblack@google.com# Copyright (c) 2004-2005 The Regents of The University of Michigan
412922Sgabeblack@google.com# All rights reserved.
512922Sgabeblack@google.com#
612922Sgabeblack@google.com# Redistribution and use in source and binary forms, with or without
712922Sgabeblack@google.com# modification, are permitted provided that the following conditions are
812922Sgabeblack@google.com# met: redistributions of source code must retain the above copyright
912922Sgabeblack@google.com# notice, this list of conditions and the following disclaimer;
1012922Sgabeblack@google.com# redistributions in binary form must reproduce the above copyright
1112922Sgabeblack@google.com# notice, this list of conditions and the following disclaimer in the
1212922Sgabeblack@google.com# documentation and/or other materials provided with the distribution;
1312922Sgabeblack@google.com# neither the name of the copyright holders nor the names of its
1412922Sgabeblack@google.com# contributors may be used to endorse or promote products derived from
1512922Sgabeblack@google.com# this software without specific prior written permission.
1612922Sgabeblack@google.com#
1712922Sgabeblack@google.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1812922Sgabeblack@google.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1912922Sgabeblack@google.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2012922Sgabeblack@google.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2112922Sgabeblack@google.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2212922Sgabeblack@google.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2312922Sgabeblack@google.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2412922Sgabeblack@google.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2512922Sgabeblack@google.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2612922Sgabeblack@google.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2712922Sgabeblack@google.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2812922Sgabeblack@google.com#
2912922Sgabeblack@google.com# Authors: Nathan Binkert
3012922Sgabeblack@google.com
3112922Sgabeblack@google.comimport array
3212922Sgabeblack@google.comimport bisect
3312922Sgabeblack@google.comimport imp
3412922Sgabeblack@google.comimport marshal
3512922Sgabeblack@google.comimport os
3612922Sgabeblack@google.comimport re
3712922Sgabeblack@google.comimport subprocess
3812922Sgabeblack@google.comimport sys
3912922Sgabeblack@google.comimport zlib
4012922Sgabeblack@google.com
4112922Sgabeblack@google.comfrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath
4212922Sgabeblack@google.com
4312922Sgabeblack@google.comimport SCons
4412922Sgabeblack@google.com
4512922Sgabeblack@google.comfrom gem5_scons import Transform
4612922Sgabeblack@google.com
4712922Sgabeblack@google.com# This file defines how to build a particular configuration of gem5
4812922Sgabeblack@google.com# based on variable settings in the 'env' build environment.
4912922Sgabeblack@google.com
5012922Sgabeblack@google.comImport('*')
5112922Sgabeblack@google.com
5212922Sgabeblack@google.com# Children need to see the environment
5312922Sgabeblack@google.comExport('env')
5412922Sgabeblack@google.com
5512922Sgabeblack@google.combuild_env = [(opt, env[opt]) for opt in export_vars]
5612922Sgabeblack@google.com
5712922Sgabeblack@google.comfrom m5.util import code_formatter, compareVersions
5812922Sgabeblack@google.com
5912922Sgabeblack@google.com########################################################################
6012922Sgabeblack@google.com# Code for adding source files of various types
6112922Sgabeblack@google.com#
6212922Sgabeblack@google.com# When specifying a source file of some type, a set of tags can be
6312922Sgabeblack@google.com# specified for that file.
6412922Sgabeblack@google.com
6512922Sgabeblack@google.comclass SourceList(list):
6612922Sgabeblack@google.com    def with_tags_that(self, predicate):
6712922Sgabeblack@google.com        '''Return a list of sources with tags that satisfy a predicate.'''
6812922Sgabeblack@google.com        def match(source):
6912922Sgabeblack@google.com            return predicate(source.tags)
7012922Sgabeblack@google.com        return SourceList(filter(match, self))
7112922Sgabeblack@google.com
7212922Sgabeblack@google.com    def with_any_tags(self, *tags):
7312922Sgabeblack@google.com        '''Return a list of sources with any of the supplied tags.'''
7412922Sgabeblack@google.com        return self.with_tags_that(lambda stags: len(tags & stags) > 0)
7512922Sgabeblack@google.com
7612922Sgabeblack@google.com    def with_all_tags(self, *tags):
7712922Sgabeblack@google.com        '''Return a list of sources with all of the supplied tags.'''
7812922Sgabeblack@google.com        return self.with_tags_that(lambda stags: tags <= stags)
7912922Sgabeblack@google.com
8012922Sgabeblack@google.com    def with_tag(self, tag):
8112922Sgabeblack@google.com        '''Return a list of sources with the supplied tag.'''
8212922Sgabeblack@google.com        return self.with_tags_that(lambda stags: tag in stags)
8312922Sgabeblack@google.com
8412922Sgabeblack@google.com    def without_tags(self, *tags):
8512922Sgabeblack@google.com        '''Return a list of sources without any of the supplied tags.'''
8612922Sgabeblack@google.com        return self.with_tags_that(lambda stags: len(tags & stags) == 0)
8712922Sgabeblack@google.com
8812922Sgabeblack@google.com    def without_tag(self, tag):
8912922Sgabeblack@google.com        '''Return a list of sources with the supplied tag.'''
9012922Sgabeblack@google.com        return self.with_tags_that(lambda stags: tag not in stags)
9112922Sgabeblack@google.com
9212922Sgabeblack@google.comclass SourceMeta(type):
9312922Sgabeblack@google.com    '''Meta class for source files that keeps track of all files of a
9412922Sgabeblack@google.com    particular type.'''
9512922Sgabeblack@google.com    def __init__(cls, name, bases, dict):
9612922Sgabeblack@google.com        super(SourceMeta, cls).__init__(name, bases, dict)
9712922Sgabeblack@google.com        cls.all = SourceList()
9812922Sgabeblack@google.com
9912922Sgabeblack@google.comclass SourceFile(object):
10012922Sgabeblack@google.com    '''Base object that encapsulates the notion of a source file.
10112922Sgabeblack@google.com    This includes, the source node, target node, various manipulations
10212922Sgabeblack@google.com    of those.  A source file also specifies a set of tags which
10312922Sgabeblack@google.com    describing arbitrary properties of the source file.'''
10412922Sgabeblack@google.com    __metaclass__ = SourceMeta
10512922Sgabeblack@google.com    def __init__(self, source, tags=None, add_tags=None):
10612922Sgabeblack@google.com        if tags is None:
10712922Sgabeblack@google.com            tags='gem5 lib'
10812922Sgabeblack@google.com        if isinstance(tags, basestring):
10912922Sgabeblack@google.com            tags = set([tags])
11012922Sgabeblack@google.com        if isinstance(add_tags, basestring):
11112922Sgabeblack@google.com            add_tags = set([add_tags])
11212922Sgabeblack@google.com        if add_tags:
11312922Sgabeblack@google.com            tags = tags | add_tags
11412922Sgabeblack@google.com        self.tags = set(tags)
11512922Sgabeblack@google.com
11612922Sgabeblack@google.com        tnode = source
11712922Sgabeblack@google.com        if not isinstance(source, SCons.Node.FS.File):
11812922Sgabeblack@google.com            tnode = File(source)
11912922Sgabeblack@google.com
12012922Sgabeblack@google.com        self.tnode = tnode
12112922Sgabeblack@google.com        self.snode = tnode.srcnode()
12212922Sgabeblack@google.com
12312922Sgabeblack@google.com        for base in type(self).__mro__:
12412922Sgabeblack@google.com            if issubclass(base, SourceFile):
12512922Sgabeblack@google.com                base.all.append(self)
12612922Sgabeblack@google.com
12712922Sgabeblack@google.com    @property
12812922Sgabeblack@google.com    def filename(self):
12912922Sgabeblack@google.com        return str(self.tnode)
13012922Sgabeblack@google.com
13112922Sgabeblack@google.com    @property
13212922Sgabeblack@google.com    def dirname(self):
13312922Sgabeblack@google.com        return dirname(self.filename)
13412922Sgabeblack@google.com
13512922Sgabeblack@google.com    @property
13612922Sgabeblack@google.com    def basename(self):
13712922Sgabeblack@google.com        return basename(self.filename)
13812922Sgabeblack@google.com
13912922Sgabeblack@google.com    @property
14012922Sgabeblack@google.com    def extname(self):
14112922Sgabeblack@google.com        index = self.basename.rfind('.')
14212922Sgabeblack@google.com        if index <= 0:
14312922Sgabeblack@google.com            # dot files aren't extensions
14412922Sgabeblack@google.com            return self.basename, None
14512922Sgabeblack@google.com
14612922Sgabeblack@google.com        return self.basename[:index], self.basename[index+1:]
14712922Sgabeblack@google.com
14812922Sgabeblack@google.com    def __lt__(self, other): return self.filename < other.filename
14912922Sgabeblack@google.com    def __le__(self, other): return self.filename <= other.filename
15012922Sgabeblack@google.com    def __gt__(self, other): return self.filename > other.filename
15112922Sgabeblack@google.com    def __ge__(self, other): return self.filename >= other.filename
15212922Sgabeblack@google.com    def __eq__(self, other): return self.filename == other.filename
15312922Sgabeblack@google.com    def __ne__(self, other): return self.filename != other.filename
15412922Sgabeblack@google.com
15512922Sgabeblack@google.comclass Source(SourceFile):
15612922Sgabeblack@google.com    ungrouped_tag = 'No link group'
15712922Sgabeblack@google.com    source_groups = set()
15812922Sgabeblack@google.com
15912922Sgabeblack@google.com    _current_group_tag = ungrouped_tag
16012922Sgabeblack@google.com
16112922Sgabeblack@google.com    @staticmethod
16212922Sgabeblack@google.com    def link_group_tag(group):
16312922Sgabeblack@google.com        return 'link group: %s' % group
16412922Sgabeblack@google.com
16512922Sgabeblack@google.com    @classmethod
16612922Sgabeblack@google.com    def set_group(cls, group):
16712922Sgabeblack@google.com        new_tag = Source.link_group_tag(group)
16812922Sgabeblack@google.com        Source._current_group_tag = new_tag
16912922Sgabeblack@google.com        Source.source_groups.add(group)
17012922Sgabeblack@google.com
17112922Sgabeblack@google.com    def _add_link_group_tag(self):
17212922Sgabeblack@google.com        self.tags.add(Source._current_group_tag)
17312922Sgabeblack@google.com
17412922Sgabeblack@google.com    '''Add a c/c++ source file to the build'''
17512922Sgabeblack@google.com    def __init__(self, source, tags=None, add_tags=None):
17612922Sgabeblack@google.com        '''specify the source file, and any tags'''
17712922Sgabeblack@google.com        super(Source, self).__init__(source, tags, add_tags)
17812922Sgabeblack@google.com        self._add_link_group_tag()
17912922Sgabeblack@google.com
18012922Sgabeblack@google.comclass PySource(SourceFile):
18112922Sgabeblack@google.com    '''Add a python source file to the named package'''
18212922Sgabeblack@google.com    invalid_sym_char = re.compile('[^A-z0-9_]')
18312922Sgabeblack@google.com    modules = {}
18412922Sgabeblack@google.com    tnodes = {}
18512922Sgabeblack@google.com    symnames = {}
18612922Sgabeblack@google.com
18712922Sgabeblack@google.com    def __init__(self, package, source, tags=None, add_tags=None):
18812922Sgabeblack@google.com        '''specify the python package, the source file, and any tags'''
18912922Sgabeblack@google.com        super(PySource, self).__init__(source, tags, add_tags)
19012922Sgabeblack@google.com
19112922Sgabeblack@google.com        modname,ext = self.extname
19212922Sgabeblack@google.com        assert ext == 'py'
19312922Sgabeblack@google.com
19412922Sgabeblack@google.com        if package:
19512922Sgabeblack@google.com            path = package.split('.')
19612922Sgabeblack@google.com        else:
19712922Sgabeblack@google.com            path = []
19812922Sgabeblack@google.com
19912922Sgabeblack@google.com        modpath = path[:]
20012922Sgabeblack@google.com        if modname != '__init__':
20112922Sgabeblack@google.com            modpath += [ modname ]
20212922Sgabeblack@google.com        modpath = '.'.join(modpath)
20312922Sgabeblack@google.com
20412922Sgabeblack@google.com        arcpath = path + [ self.basename ]
20512922Sgabeblack@google.com        abspath = self.snode.abspath
20612922Sgabeblack@google.com        if not exists(abspath):
20712922Sgabeblack@google.com            abspath = self.tnode.abspath
20812922Sgabeblack@google.com
20912922Sgabeblack@google.com        self.package = package
21012922Sgabeblack@google.com        self.modname = modname
21112922Sgabeblack@google.com        self.modpath = modpath
21212922Sgabeblack@google.com        self.arcname = joinpath(*arcpath)
21312922Sgabeblack@google.com        self.abspath = abspath
21412922Sgabeblack@google.com        self.compiled = File(self.filename + 'c')
21512922Sgabeblack@google.com        self.cpp = File(self.filename + '.cc')
21612922Sgabeblack@google.com        self.symname = PySource.invalid_sym_char.sub('_', modpath)
21712922Sgabeblack@google.com
21812922Sgabeblack@google.com        PySource.modules[modpath] = self
21912922Sgabeblack@google.com        PySource.tnodes[self.tnode] = self
22012922Sgabeblack@google.com        PySource.symnames[self.symname] = self
22112922Sgabeblack@google.com
22212922Sgabeblack@google.comclass SimObject(PySource):
22312922Sgabeblack@google.com    '''Add a SimObject python file as a python source object and add
22412922Sgabeblack@google.com    it to a list of sim object modules'''
22512922Sgabeblack@google.com
22612922Sgabeblack@google.com    fixed = False
22712922Sgabeblack@google.com    modnames = []
22812922Sgabeblack@google.com
22912922Sgabeblack@google.com    def __init__(self, source, tags=None, add_tags=None):
23012922Sgabeblack@google.com        '''Specify the source file and any tags (automatically in
23112922Sgabeblack@google.com        the m5.objects package)'''
23212922Sgabeblack@google.com        super(SimObject, self).__init__('m5.objects', source, tags, add_tags)
23312922Sgabeblack@google.com        if self.fixed:
23412922Sgabeblack@google.com            raise AttributeError, "Too late to call SimObject now."
23512922Sgabeblack@google.com
23612922Sgabeblack@google.com        bisect.insort_right(SimObject.modnames, self.modname)
23712922Sgabeblack@google.com
23812922Sgabeblack@google.comclass ProtoBuf(SourceFile):
23912922Sgabeblack@google.com    '''Add a Protocol Buffer to build'''
24012922Sgabeblack@google.com
24112922Sgabeblack@google.com    def __init__(self, source, tags=None, add_tags=None):
24212922Sgabeblack@google.com        '''Specify the source file, and any tags'''
24312922Sgabeblack@google.com        super(ProtoBuf, self).__init__(source, tags, add_tags)
24412922Sgabeblack@google.com
24512922Sgabeblack@google.com        # Get the file name and the extension
24612922Sgabeblack@google.com        modname,ext = self.extname
24712922Sgabeblack@google.com        assert ext == 'proto'
24812922Sgabeblack@google.com
24912922Sgabeblack@google.com        # Currently, we stick to generating the C++ headers, so we
25012922Sgabeblack@google.com        # only need to track the source and header.
25112922Sgabeblack@google.com        self.cc_file = File(modname + '.pb.cc')
25212922Sgabeblack@google.com        self.hh_file = File(modname + '.pb.h')
25312922Sgabeblack@google.com
25412922Sgabeblack@google.comclass UnitTest(object):
25512922Sgabeblack@google.com    '''Create a UnitTest'''
25612922Sgabeblack@google.com
25712922Sgabeblack@google.com    all = []
25812922Sgabeblack@google.com    def __init__(self, target, *sources, **kwargs):
25912922Sgabeblack@google.com        '''Specify the target name and any sources.  Sources that are
26012922Sgabeblack@google.com        not SourceFiles are evalued with Source().  All files are
26112922Sgabeblack@google.com        tagged with the name of the UnitTest target.'''
26212922Sgabeblack@google.com
26312922Sgabeblack@google.com        srcs = SourceList()
26412922Sgabeblack@google.com        for src in sources:
26512922Sgabeblack@google.com            if not isinstance(src, SourceFile):
26612922Sgabeblack@google.com                src = Source(src, tags=str(target))
26712922Sgabeblack@google.com            srcs.append(src)
26812922Sgabeblack@google.com
26912922Sgabeblack@google.com        self.sources = srcs
27012922Sgabeblack@google.com        self.target = target
27112922Sgabeblack@google.com        self.main = kwargs.get('main', False)
27212922Sgabeblack@google.com        UnitTest.all.append(self)
27312922Sgabeblack@google.com
27412922Sgabeblack@google.com# Children should have access
27512922Sgabeblack@google.comExport('Source')
27612922Sgabeblack@google.comExport('PySource')
27712922Sgabeblack@google.comExport('SimObject')
27812922Sgabeblack@google.comExport('ProtoBuf')
27912922Sgabeblack@google.comExport('UnitTest')
28012922Sgabeblack@google.com
28112922Sgabeblack@google.com########################################################################
28212922Sgabeblack@google.com#
28312922Sgabeblack@google.com# Debug Flags
28412922Sgabeblack@google.com#
28512922Sgabeblack@google.comdebug_flags = {}
28612922Sgabeblack@google.comdef DebugFlag(name, desc=None):
28712922Sgabeblack@google.com    if name in debug_flags:
28812922Sgabeblack@google.com        raise AttributeError, "Flag %s already specified" % name
28912922Sgabeblack@google.com    debug_flags[name] = (name, (), desc)
29012922Sgabeblack@google.com
29112922Sgabeblack@google.comdef CompoundFlag(name, flags, desc=None):
29212922Sgabeblack@google.com    if name in debug_flags:
29312922Sgabeblack@google.com        raise AttributeError, "Flag %s already specified" % name
29412922Sgabeblack@google.com
29512922Sgabeblack@google.com    compound = tuple(flags)
29612922Sgabeblack@google.com    debug_flags[name] = (name, compound, desc)
29712922Sgabeblack@google.com
29812922Sgabeblack@google.comExport('DebugFlag')
29912922Sgabeblack@google.comExport('CompoundFlag')
300
301########################################################################
302#
303# Set some compiler variables
304#
305
306# Include file paths are rooted in this directory.  SCons will
307# automatically expand '.' to refer to both the source directory and
308# the corresponding build directory to pick up generated include
309# files.
310env.Append(CPPPATH=Dir('.'))
311
312for extra_dir in extras_dir_list:
313    env.Append(CPPPATH=Dir(extra_dir))
314
315# Workaround for bug in SCons version > 0.97d20071212
316# Scons bug id: 2006 gem5 Bug id: 308
317for root, dirs, files in os.walk(base_dir, topdown=True):
318    Dir(root[len(base_dir) + 1:])
319
320########################################################################
321#
322# Walk the tree and execute all SConscripts in subdirectories
323#
324
325here = Dir('.').srcnode().abspath
326for root, dirs, files in os.walk(base_dir, topdown=True):
327    if root == here:
328        # we don't want to recurse back into this SConscript
329        continue
330
331    if 'SConscript' in files:
332        build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
333        Source.set_group(build_dir)
334        SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
335
336for extra_dir in extras_dir_list:
337    prefix_len = len(dirname(extra_dir)) + 1
338
339    # Also add the corresponding build directory to pick up generated
340    # include files.
341    env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:])))
342
343    for root, dirs, files in os.walk(extra_dir, topdown=True):
344        # if build lives in the extras directory, don't walk down it
345        if 'build' in dirs:
346            dirs.remove('build')
347
348        if 'SConscript' in files:
349            build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
350            SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
351
352for opt in export_vars:
353    env.ConfigFile(opt)
354
355def makeTheISA(source, target, env):
356    isas = [ src.get_contents() for src in source ]
357    target_isa = env['TARGET_ISA']
358    def define(isa):
359        return isa.upper() + '_ISA'
360
361    def namespace(isa):
362        return isa[0].upper() + isa[1:].lower() + 'ISA'
363
364
365    code = code_formatter()
366    code('''\
367#ifndef __CONFIG_THE_ISA_HH__
368#define __CONFIG_THE_ISA_HH__
369
370''')
371
372    # create defines for the preprocessing and compile-time determination
373    for i,isa in enumerate(isas):
374        code('#define $0 $1', define(isa), i + 1)
375    code()
376
377    # create an enum for any run-time determination of the ISA, we
378    # reuse the same name as the namespaces
379    code('enum class Arch {')
380    for i,isa in enumerate(isas):
381        if i + 1 == len(isas):
382            code('  $0 = $1', namespace(isa), define(isa))
383        else:
384            code('  $0 = $1,', namespace(isa), define(isa))
385    code('};')
386
387    code('''
388
389#define THE_ISA ${{define(target_isa)}}
390#define TheISA ${{namespace(target_isa)}}
391#define THE_ISA_STR "${{target_isa}}"
392
393#endif // __CONFIG_THE_ISA_HH__''')
394
395    code.write(str(target[0]))
396
397env.Command('config/the_isa.hh', map(Value, all_isa_list),
398            MakeAction(makeTheISA, Transform("CFG ISA", 0)))
399
400def makeTheGPUISA(source, target, env):
401    isas = [ src.get_contents() for src in source ]
402    target_gpu_isa = env['TARGET_GPU_ISA']
403    def define(isa):
404        return isa.upper() + '_ISA'
405
406    def namespace(isa):
407        return isa[0].upper() + isa[1:].lower() + 'ISA'
408
409
410    code = code_formatter()
411    code('''\
412#ifndef __CONFIG_THE_GPU_ISA_HH__
413#define __CONFIG_THE_GPU_ISA_HH__
414
415''')
416
417    # create defines for the preprocessing and compile-time determination
418    for i,isa in enumerate(isas):
419        code('#define $0 $1', define(isa), i + 1)
420    code()
421
422    # create an enum for any run-time determination of the ISA, we
423    # reuse the same name as the namespaces
424    code('enum class GPUArch {')
425    for i,isa in enumerate(isas):
426        if i + 1 == len(isas):
427            code('  $0 = $1', namespace(isa), define(isa))
428        else:
429            code('  $0 = $1,', namespace(isa), define(isa))
430    code('};')
431
432    code('''
433
434#define THE_GPU_ISA ${{define(target_gpu_isa)}}
435#define TheGpuISA ${{namespace(target_gpu_isa)}}
436#define THE_GPU_ISA_STR "${{target_gpu_isa}}"
437
438#endif // __CONFIG_THE_GPU_ISA_HH__''')
439
440    code.write(str(target[0]))
441
442env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list),
443            MakeAction(makeTheGPUISA, Transform("CFG ISA", 0)))
444
445########################################################################
446#
447# Prevent any SimObjects from being added after this point, they
448# should all have been added in the SConscripts above
449#
450SimObject.fixed = True
451
452class DictImporter(object):
453    '''This importer takes a dictionary of arbitrary module names that
454    map to arbitrary filenames.'''
455    def __init__(self, modules):
456        self.modules = modules
457        self.installed = set()
458
459    def __del__(self):
460        self.unload()
461
462    def unload(self):
463        import sys
464        for module in self.installed:
465            del sys.modules[module]
466        self.installed = set()
467
468    def find_module(self, fullname, path):
469        if fullname == 'm5.defines':
470            return self
471
472        if fullname == 'm5.objects':
473            return self
474
475        if fullname.startswith('_m5'):
476            return None
477
478        source = self.modules.get(fullname, None)
479        if source is not None and fullname.startswith('m5.objects'):
480            return self
481
482        return None
483
484    def load_module(self, fullname):
485        mod = imp.new_module(fullname)
486        sys.modules[fullname] = mod
487        self.installed.add(fullname)
488
489        mod.__loader__ = self
490        if fullname == 'm5.objects':
491            mod.__path__ = fullname.split('.')
492            return mod
493
494        if fullname == 'm5.defines':
495            mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
496            return mod
497
498        source = self.modules[fullname]
499        if source.modname == '__init__':
500            mod.__path__ = source.modpath
501        mod.__file__ = source.abspath
502
503        exec file(source.abspath, 'r') in mod.__dict__
504
505        return mod
506
507import m5.SimObject
508import m5.params
509from m5.util import code_formatter
510
511m5.SimObject.clear()
512m5.params.clear()
513
514# install the python importer so we can grab stuff from the source
515# tree itself.  We can't have SimObjects added after this point or
516# else we won't know about them for the rest of the stuff.
517importer = DictImporter(PySource.modules)
518sys.meta_path[0:0] = [ importer ]
519
520# import all sim objects so we can populate the all_objects list
521# make sure that we're working with a list, then let's sort it
522for modname in SimObject.modnames:
523    exec('from m5.objects import %s' % modname)
524
525# we need to unload all of the currently imported modules so that they
526# will be re-imported the next time the sconscript is run
527importer.unload()
528sys.meta_path.remove(importer)
529
530sim_objects = m5.SimObject.allClasses
531all_enums = m5.params.allEnums
532
533for name,obj in sorted(sim_objects.iteritems()):
534    for param in obj._params.local.values():
535        # load the ptype attribute now because it depends on the
536        # current version of SimObject.allClasses, but when scons
537        # actually uses the value, all versions of
538        # SimObject.allClasses will have been loaded
539        param.ptype
540
541########################################################################
542#
543# calculate extra dependencies
544#
545module_depends = ["m5", "m5.SimObject", "m5.params"]
546depends = [ PySource.modules[dep].snode for dep in module_depends ]
547depends.sort(key = lambda x: x.name)
548
549########################################################################
550#
551# Commands for the basic automatically generated python files
552#
553
554# Generate Python file containing a dict specifying the current
555# buildEnv flags.
556def makeDefinesPyFile(target, source, env):
557    build_env = source[0].get_contents()
558
559    code = code_formatter()
560    code("""
561import _m5.core
562import m5.util
563
564buildEnv = m5.util.SmartDict($build_env)
565
566compileDate = _m5.core.compileDate
567_globals = globals()
568for key,val in _m5.core.__dict__.iteritems():
569    if key.startswith('flag_'):
570        flag = key[5:]
571        _globals[flag] = val
572del _globals
573""")
574    code.write(target[0].abspath)
575
576defines_info = Value(build_env)
577# Generate a file with all of the compile options in it
578env.Command('python/m5/defines.py', defines_info,
579            MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
580PySource('m5', 'python/m5/defines.py')
581
582# Generate python file containing info about the M5 source code
583def makeInfoPyFile(target, source, env):
584    code = code_formatter()
585    for src in source:
586        data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
587        code('$src = ${{repr(data)}}')
588    code.write(str(target[0]))
589
590# Generate a file that wraps the basic top level files
591env.Command('python/m5/info.py',
592            [ '#/COPYING', '#/LICENSE', '#/README', ],
593            MakeAction(makeInfoPyFile, Transform("INFO")))
594PySource('m5', 'python/m5/info.py')
595
596########################################################################
597#
598# Create all of the SimObject param headers and enum headers
599#
600
601def createSimObjectParamStruct(target, source, env):
602    assert len(target) == 1 and len(source) == 1
603
604    name = source[0].get_text_contents()
605    obj = sim_objects[name]
606
607    code = code_formatter()
608    obj.cxx_param_decl(code)
609    code.write(target[0].abspath)
610
611def createSimObjectCxxConfig(is_header):
612    def body(target, source, env):
613        assert len(target) == 1 and len(source) == 1
614
615        name = str(source[0].get_contents())
616        obj = sim_objects[name]
617
618        code = code_formatter()
619        obj.cxx_config_param_file(code, is_header)
620        code.write(target[0].abspath)
621    return body
622
623def createEnumStrings(target, source, env):
624    assert len(target) == 1 and len(source) == 2
625
626    name = source[0].get_text_contents()
627    use_python = source[1].read()
628    obj = all_enums[name]
629
630    code = code_formatter()
631    obj.cxx_def(code)
632    if use_python:
633        obj.pybind_def(code)
634    code.write(target[0].abspath)
635
636def createEnumDecls(target, source, env):
637    assert len(target) == 1 and len(source) == 1
638
639    name = source[0].get_text_contents()
640    obj = all_enums[name]
641
642    code = code_formatter()
643    obj.cxx_decl(code)
644    code.write(target[0].abspath)
645
646def createSimObjectPyBindWrapper(target, source, env):
647    name = source[0].get_text_contents()
648    obj = sim_objects[name]
649
650    code = code_formatter()
651    obj.pybind_decl(code)
652    code.write(target[0].abspath)
653
654# Generate all of the SimObject param C++ struct header files
655params_hh_files = []
656for name,simobj in sorted(sim_objects.iteritems()):
657    py_source = PySource.modules[simobj.__module__]
658    extra_deps = [ py_source.tnode ]
659
660    hh_file = File('params/%s.hh' % name)
661    params_hh_files.append(hh_file)
662    env.Command(hh_file, Value(name),
663                MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
664    env.Depends(hh_file, depends + extra_deps)
665
666# C++ parameter description files
667if GetOption('with_cxx_config'):
668    for name,simobj in sorted(sim_objects.iteritems()):
669        py_source = PySource.modules[simobj.__module__]
670        extra_deps = [ py_source.tnode ]
671
672        cxx_config_hh_file = File('cxx_config/%s.hh' % name)
673        cxx_config_cc_file = File('cxx_config/%s.cc' % name)
674        env.Command(cxx_config_hh_file, Value(name),
675                    MakeAction(createSimObjectCxxConfig(True),
676                    Transform("CXXCPRHH")))
677        env.Command(cxx_config_cc_file, Value(name),
678                    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