SConscript revision 7677:c6e283904437
111104Spower.jg@gmail.com# -*- mode:python -*-
211104Spower.jg@gmail.com
311104Spower.jg@gmail.com# Copyright (c) 2004-2005 The Regents of The University of Michigan
411104Spower.jg@gmail.com# All rights reserved.
511104Spower.jg@gmail.com#
611104Spower.jg@gmail.com# Redistribution and use in source and binary forms, with or without
711104Spower.jg@gmail.com# modification, are permitted provided that the following conditions are
812579Sjason@lowepower.com# met: redistributions of source code must retain the above copyright
912579Sjason@lowepower.com# notice, this list of conditions and the following disclaimer;
1011104Spower.jg@gmail.com# redistributions in binary form must reproduce the above copyright
1112579Sjason@lowepower.com# notice, this list of conditions and the following disclaimer in the
1211104Spower.jg@gmail.com# documentation and/or other materials provided with the distribution;
1311104Spower.jg@gmail.com# neither the name of the copyright holders nor the names of its
1411104Spower.jg@gmail.com# contributors may be used to endorse or promote products derived from
1512579Sjason@lowepower.com# this software without specific prior written permission.
1612579Sjason@lowepower.com#
1712579Sjason@lowepower.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1812579Sjason@lowepower.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1912579Sjason@lowepower.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2011104Spower.jg@gmail.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2111104Spower.jg@gmail.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2212579Sjason@lowepower.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2311104Spower.jg@gmail.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2411104Spower.jg@gmail.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2511104Spower.jg@gmail.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2611104Spower.jg@gmail.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2711104Spower.jg@gmail.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2811104Spower.jg@gmail.com#
2911104Spower.jg@gmail.com# Authors: Nathan Binkert
3011104Spower.jg@gmail.com
3111104Spower.jg@gmail.comimport array
3211104Spower.jg@gmail.comimport bisect
3312579Sjason@lowepower.comimport imp
34import marshal
35import os
36import re
37import sys
38import zlib
39
40from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
41
42import SCons
43
44# This file defines how to build a particular configuration of M5
45# based on variable settings in the 'env' build environment.
46
47Import('*')
48
49# Children need to see the environment
50Export('env')
51
52build_env = [(opt, env[opt]) for opt in export_vars]
53
54from m5.util import code_formatter
55
56########################################################################
57# Code for adding source files of various types
58#
59class SourceMeta(type):
60    def __init__(cls, name, bases, dict):
61        super(SourceMeta, cls).__init__(name, bases, dict)
62        cls.all = []
63        
64    def get(cls, **kwargs):
65        for src in cls.all:
66            for attr,value in kwargs.iteritems():
67                if getattr(src, attr) != value:
68                    break
69            else:
70                yield src
71
72class SourceFile(object):
73    __metaclass__ = SourceMeta
74    def __init__(self, source):
75        tnode = source
76        if not isinstance(source, SCons.Node.FS.File):
77            tnode = File(source)
78
79        self.tnode = tnode
80        self.snode = tnode.srcnode()
81        self.filename = str(tnode)
82        self.dirname = dirname(self.filename)
83        self.basename = basename(self.filename)
84        index = self.basename.rfind('.')
85        if index <= 0:
86            # dot files aren't extensions
87            self.extname = self.basename, None
88        else:
89            self.extname = self.basename[:index], self.basename[index+1:]
90
91        for base in type(self).__mro__:
92            if issubclass(base, SourceFile):
93                base.all.append(self)
94
95    def __lt__(self, other): return self.filename < other.filename
96    def __le__(self, other): return self.filename <= other.filename
97    def __gt__(self, other): return self.filename > other.filename
98    def __ge__(self, other): return self.filename >= other.filename
99    def __eq__(self, other): return self.filename == other.filename
100    def __ne__(self, other): return self.filename != other.filename
101        
102class Source(SourceFile):
103    '''Add a c/c++ source file to the build'''
104    def __init__(self, source, Werror=True, swig=False, bin_only=False,
105                 skip_lib=False):
106        super(Source, self).__init__(source)
107
108        self.Werror = Werror
109        self.swig = swig
110        self.bin_only = bin_only
111        self.skip_lib = bin_only or skip_lib
112
113class PySource(SourceFile):
114    '''Add a python source file to the named package'''
115    invalid_sym_char = re.compile('[^A-z0-9_]')
116    modules = {}
117    tnodes = {}
118    symnames = {}
119    
120    def __init__(self, package, source):
121        super(PySource, self).__init__(source)
122
123        modname,ext = self.extname
124        assert ext == 'py'
125
126        if package:
127            path = package.split('.')
128        else:
129            path = []
130
131        modpath = path[:]
132        if modname != '__init__':
133            modpath += [ modname ]
134        modpath = '.'.join(modpath)
135
136        arcpath = path + [ self.basename ]
137        abspath = self.snode.abspath
138        if not exists(abspath):
139            abspath = self.tnode.abspath
140
141        self.package = package
142        self.modname = modname
143        self.modpath = modpath
144        self.arcname = joinpath(*arcpath)
145        self.abspath = abspath
146        self.compiled = File(self.filename + 'c')
147        self.cpp = File(self.filename + '.cc')
148        self.symname = PySource.invalid_sym_char.sub('_', modpath)
149
150        PySource.modules[modpath] = self
151        PySource.tnodes[self.tnode] = self
152        PySource.symnames[self.symname] = self
153
154class SimObject(PySource):
155    '''Add a SimObject python file as a python source object and add
156    it to a list of sim object modules'''
157
158    fixed = False
159    modnames = []
160
161    def __init__(self, source):
162        super(SimObject, self).__init__('m5.objects', source)
163        if self.fixed:
164            raise AttributeError, "Too late to call SimObject now."
165
166        bisect.insort_right(SimObject.modnames, self.modname)
167
168class SwigSource(SourceFile):
169    '''Add a swig file to build'''
170
171    def __init__(self, package, source):
172        super(SwigSource, self).__init__(source)
173
174        modname,ext = self.extname
175        assert ext == 'i'
176
177        self.module = modname
178        cc_file = joinpath(self.dirname, modname + '_wrap.cc')
179        py_file = joinpath(self.dirname, modname + '.py')
180
181        self.cc_source = Source(cc_file, swig=True)
182        self.py_source = PySource(package, py_file)
183
184unit_tests = []
185def UnitTest(target, sources):
186    if not isinstance(sources, (list, tuple)):
187        sources = [ sources ]
188
189    sources = [ Source(src, skip_lib=True) for src in sources ]
190    unit_tests.append((target, sources))
191
192# Children should have access
193Export('Source')
194Export('PySource')
195Export('SimObject')
196Export('SwigSource')
197Export('UnitTest')
198
199########################################################################
200#
201# Trace Flags
202#
203trace_flags = {}
204def TraceFlag(name, desc=None):
205    if name in trace_flags:
206        raise AttributeError, "Flag %s already specified" % name
207    trace_flags[name] = (name, (), desc)
208
209def CompoundFlag(name, flags, desc=None):
210    if name in trace_flags:
211        raise AttributeError, "Flag %s already specified" % name
212
213    compound = tuple(flags)
214    trace_flags[name] = (name, compound, desc)
215
216Export('TraceFlag')
217Export('CompoundFlag')
218
219########################################################################
220#
221# Set some compiler variables
222#
223
224# Include file paths are rooted in this directory.  SCons will
225# automatically expand '.' to refer to both the source directory and
226# the corresponding build directory to pick up generated include
227# files.
228env.Append(CPPPATH=Dir('.'))
229
230for extra_dir in extras_dir_list:
231    env.Append(CPPPATH=Dir(extra_dir))
232
233# Workaround for bug in SCons version > 0.97d20071212
234# Scons bug id: 2006 M5 Bug id: 308 
235for root, dirs, files in os.walk(base_dir, topdown=True):
236    Dir(root[len(base_dir) + 1:])
237
238########################################################################
239#
240# Walk the tree and execute all SConscripts in subdirectories
241#
242
243here = Dir('.').srcnode().abspath
244for root, dirs, files in os.walk(base_dir, topdown=True):
245    if root == here:
246        # we don't want to recurse back into this SConscript
247        continue
248
249    if 'SConscript' in files:
250        build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
251        SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
252
253for extra_dir in extras_dir_list:
254    prefix_len = len(dirname(extra_dir)) + 1
255    for root, dirs, files in os.walk(extra_dir, topdown=True):
256        if 'SConscript' in files:
257            build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
258            SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
259
260for opt in export_vars:
261    env.ConfigFile(opt)
262
263def makeTheISA(source, target, env):
264    isas = [ src.get_contents() for src in source ]
265    target_isa = env['TARGET_ISA']
266    def define(isa):
267        return isa.upper() + '_ISA'
268    
269    def namespace(isa):
270        return isa[0].upper() + isa[1:].lower() + 'ISA' 
271
272
273    code = code_formatter()
274    code('''\
275#ifndef __CONFIG_THE_ISA_HH__
276#define __CONFIG_THE_ISA_HH__
277
278''')
279
280    for i,isa in enumerate(isas):
281        code('#define $0 $1', define(isa), i + 1)
282
283    code('''
284
285#define THE_ISA ${{define(target_isa)}}
286#define TheISA ${{namespace(target_isa)}}
287
288#endif // __CONFIG_THE_ISA_HH__''')
289
290    code.write(str(target[0]))
291
292env.Command('config/the_isa.hh', map(Value, all_isa_list), makeTheISA)
293
294########################################################################
295#
296# Prevent any SimObjects from being added after this point, they
297# should all have been added in the SConscripts above
298#
299SimObject.fixed = True
300
301class DictImporter(object):
302    '''This importer takes a dictionary of arbitrary module names that
303    map to arbitrary filenames.'''
304    def __init__(self, modules):
305        self.modules = modules
306        self.installed = set()
307
308    def __del__(self):
309        self.unload()
310
311    def unload(self):
312        import sys
313        for module in self.installed:
314            del sys.modules[module]
315        self.installed = set()
316
317    def find_module(self, fullname, path):
318        if fullname == 'm5.defines':
319            return self
320
321        if fullname == 'm5.objects':
322            return self
323
324        if fullname.startswith('m5.internal'):
325            return None
326
327        source = self.modules.get(fullname, None)
328        if source is not None and fullname.startswith('m5.objects'):
329            return self
330
331        return None
332
333    def load_module(self, fullname):
334        mod = imp.new_module(fullname)
335        sys.modules[fullname] = mod
336        self.installed.add(fullname)
337
338        mod.__loader__ = self
339        if fullname == 'm5.objects':
340            mod.__path__ = fullname.split('.')
341            return mod
342
343        if fullname == 'm5.defines':
344            mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
345            return mod
346
347        source = self.modules[fullname]
348        if source.modname == '__init__':
349            mod.__path__ = source.modpath
350        mod.__file__ = source.abspath
351
352        exec file(source.abspath, 'r') in mod.__dict__
353
354        return mod
355
356import m5.SimObject
357import m5.params
358from m5.util import code_formatter
359
360m5.SimObject.clear()
361m5.params.clear()
362
363# install the python importer so we can grab stuff from the source
364# tree itself.  We can't have SimObjects added after this point or
365# else we won't know about them for the rest of the stuff.
366importer = DictImporter(PySource.modules)
367sys.meta_path[0:0] = [ importer ]
368
369# import all sim objects so we can populate the all_objects list
370# make sure that we're working with a list, then let's sort it
371for modname in SimObject.modnames:
372    exec('from m5.objects import %s' % modname)
373
374# we need to unload all of the currently imported modules so that they
375# will be re-imported the next time the sconscript is run
376importer.unload()
377sys.meta_path.remove(importer)
378
379sim_objects = m5.SimObject.allClasses
380all_enums = m5.params.allEnums
381
382all_params = {}
383for name,obj in sorted(sim_objects.iteritems()):
384    for param in obj._params.local.values():
385        # load the ptype attribute now because it depends on the
386        # current version of SimObject.allClasses, but when scons
387        # actually uses the value, all versions of
388        # SimObject.allClasses will have been loaded
389        param.ptype
390
391        if not hasattr(param, 'swig_decl'):
392            continue
393        pname = param.ptype_str
394        if pname not in all_params:
395            all_params[pname] = param
396
397########################################################################
398#
399# calculate extra dependencies
400#
401module_depends = ["m5", "m5.SimObject", "m5.params"]
402depends = [ PySource.modules[dep].snode for dep in module_depends ]
403
404########################################################################
405#
406# Commands for the basic automatically generated python files
407#
408
409# Generate Python file containing a dict specifying the current
410# buildEnv flags.
411def makeDefinesPyFile(target, source, env):
412    build_env, hg_info = [ x.get_contents() for x in source ]
413
414    code = code_formatter()
415    code("""
416import m5.internal
417import m5.util
418
419buildEnv = m5.util.SmartDict($build_env)
420hgRev = '$hg_info'
421
422compileDate = m5.internal.core.compileDate
423_globals = globals()
424for key,val in m5.internal.core.__dict__.iteritems():
425    if key.startswith('flag_'):
426        flag = key[5:]
427        _globals[flag] = val
428del _globals
429""")
430    code.write(target[0].abspath)
431
432defines_info = [ Value(build_env), Value(env['HG_INFO']) ]
433# Generate a file with all of the compile options in it
434env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile)
435PySource('m5', 'python/m5/defines.py')
436
437# Generate python file containing info about the M5 source code
438def makeInfoPyFile(target, source, env):
439    code = code_formatter()
440    for src in source:
441        data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
442        code('$src = ${{repr(data)}}')
443    code.write(str(target[0]))
444
445# Generate a file that wraps the basic top level files
446env.Command('python/m5/info.py',
447            [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
448            makeInfoPyFile)
449PySource('m5', 'python/m5/info.py')
450
451########################################################################
452#
453# Create all of the SimObject param headers and enum headers
454#
455
456def createSimObjectParam(target, source, env):
457    assert len(target) == 1 and len(source) == 1
458
459    name = str(source[0].get_contents())
460    obj = sim_objects[name]
461
462    code = code_formatter()
463    obj.cxx_decl(code)
464    code.write(target[0].abspath)
465
466def createSwigParam(target, source, env):
467    assert len(target) == 1 and len(source) == 1
468
469    name = str(source[0].get_contents())
470    param = all_params[name]
471
472    code = code_formatter()
473    code('%module(package="m5.internal") $0_${name}', param.file_ext)
474    param.swig_decl(code)
475    code.write(target[0].abspath)
476
477def createEnumStrings(target, source, env):
478    assert len(target) == 1 and len(source) == 1
479
480    name = str(source[0].get_contents())
481    obj = all_enums[name]
482
483    code = code_formatter()
484    obj.cxx_def(code)
485    code.write(target[0].abspath)
486
487def createEnumParam(target, source, env):
488    assert len(target) == 1 and len(source) == 1
489
490    name = str(source[0].get_contents())
491    obj = all_enums[name]
492
493    code = code_formatter()
494    obj.cxx_decl(code)
495    code.write(target[0].abspath)
496
497def createEnumSwig(target, source, env):
498    assert len(target) == 1 and len(source) == 1
499
500    name = str(source[0].get_contents())
501    obj = all_enums[name]
502
503    code = code_formatter()
504    code('''\
505%module(package="m5.internal") enum_$name
506
507%{
508#include "enums/$name.hh"
509%}
510
511%include "enums/$name.hh"
512''')
513    code.write(target[0].abspath)
514
515# Generate all of the SimObject param struct header files
516params_hh_files = []
517for name,simobj in sorted(sim_objects.iteritems()):
518    py_source = PySource.modules[simobj.__module__]
519    extra_deps = [ py_source.tnode ]
520
521    hh_file = File('params/%s.hh' % name)
522    params_hh_files.append(hh_file)
523    env.Command(hh_file, Value(name), createSimObjectParam)
524    env.Depends(hh_file, depends + extra_deps)
525
526# Generate any parameter header files needed
527params_i_files = []
528for name,param in all_params.iteritems():
529    i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name))
530    params_i_files.append(i_file)
531    env.Command(i_file, Value(name), createSwigParam)
532    env.Depends(i_file, depends)
533    SwigSource('m5.internal', i_file)
534
535# Generate all enum header files
536for name,enum in sorted(all_enums.iteritems()):
537    py_source = PySource.modules[enum.__module__]
538    extra_deps = [ py_source.tnode ]
539
540    cc_file = File('enums/%s.cc' % name)
541    env.Command(cc_file, Value(name), createEnumStrings)
542    env.Depends(cc_file, depends + extra_deps)
543    Source(cc_file)
544
545    hh_file = File('enums/%s.hh' % name)
546    env.Command(hh_file, Value(name), createEnumParam)
547    env.Depends(hh_file, depends + extra_deps)
548
549    i_file = File('python/m5/internal/enum_%s.i' % name)
550    env.Command(i_file, Value(name), createEnumSwig)
551    env.Depends(i_file, depends + extra_deps)
552    SwigSource('m5.internal', i_file)
553
554def buildParam(target, source, env):
555    name = source[0].get_contents()
556    obj = sim_objects[name]
557    class_path = obj.cxx_class.split('::')
558    classname = class_path[-1]
559    namespaces = class_path[:-1]
560    params = obj._params.local.values()
561
562    code = code_formatter()
563
564    code('%module(package="m5.internal") param_$name')
565    code()
566    code('%{')
567    code('#include "params/$obj.hh"')
568    for param in params:
569        param.cxx_predecls(code)
570    code('%}')
571    code()
572
573    for param in params:
574        param.swig_predecls(code)
575
576    code()
577    if obj._base:
578        code('%import "python/m5/internal/param_${{obj._base}}.i"')
579    code()
580    obj.swig_objdecls(code)
581    code()
582
583    code('%include "params/$obj.hh"')
584
585    code.write(target[0].abspath)
586
587for name in sim_objects.iterkeys():
588    params_file = File('python/m5/internal/param_%s.i' % name)
589    env.Command(params_file, Value(name), buildParam)
590    env.Depends(params_file, depends)
591    SwigSource('m5.internal', params_file)
592
593# Generate the main swig init file
594def makeEmbeddedSwigInit(target, source, env):
595    code = code_formatter()
596    module = source[0].get_contents()
597    code('''\
598#include "sim/init.hh"
599
600extern "C" {
601    void init_${module}();
602}
603
604EmbeddedSwig embed_swig_${module}(init_${module});
605''')
606    code.write(str(target[0]))
607    
608# Build all swig modules
609for swig in SwigSource.all:
610    env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
611                '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
612                '-o ${TARGETS[0]} $SOURCES')
613    init_file = 'python/swig/init_%s.cc' % swig.module
614    env.Command(init_file, Value(swig.module), makeEmbeddedSwigInit)
615    Source(init_file)
616    env.Depends(swig.py_source.tnode, swig.tnode)
617    env.Depends(swig.cc_source.tnode, swig.tnode)
618
619def getFlags(source_flags):
620    flagsMap = {}
621    flagsList = []
622    for s in source_flags:
623        val = eval(s.get_contents())
624        name, compound, desc = val
625        flagsList.append(val)
626        flagsMap[name] = bool(compound)
627    
628    for name, compound, desc in flagsList:
629        for flag in compound:
630            if flag not in flagsMap:
631                raise AttributeError, "Trace flag %s not found" % flag
632            if flagsMap[flag]:
633                raise AttributeError, \
634                    "Compound flag can't point to another compound flag"
635
636    flagsList.sort()
637    return flagsList
638
639
640# Generate traceflags.py
641def traceFlagsPy(target, source, env):
642    assert(len(target) == 1)
643    code = code_formatter()
644
645    allFlags = getFlags(source)
646
647    code('basic = [')
648    code.indent()
649    for flag, compound, desc in allFlags:
650        if not compound:
651            code("'$flag',")
652    code(']')
653    code.dedent()
654    code()
655
656    code('compound = [')
657    code.indent()
658    code("'All',")
659    for flag, compound, desc in allFlags:
660        if compound:
661            code("'$flag',")
662    code("]")
663    code.dedent()
664    code()
665
666    code("all = frozenset(basic + compound)")
667    code()
668
669    code('compoundMap = {')
670    code.indent()
671    all = tuple([flag for flag,compound,desc in allFlags if not compound])
672    code("'All' : $all,")
673    for flag, compound, desc in allFlags:
674        if compound:
675            code("'$flag' : $compound,")
676    code('}')
677    code.dedent()
678    code()
679
680    code('descriptions = {')
681    code.indent()
682    code("'All' : 'All flags',")
683    for flag, compound, desc in allFlags:
684        code("'$flag' : '$desc',")
685    code("}")
686    code.dedent()
687
688    code.write(str(target[0]))
689
690def traceFlagsCC(target, source, env):
691    assert(len(target) == 1)
692
693    allFlags = getFlags(source)
694    code = code_formatter()
695
696    # file header
697    code('''
698/*
699 * DO NOT EDIT THIS FILE! Automatically generated
700 */
701
702#include "base/traceflags.hh"
703
704using namespace Trace;
705
706const char *Trace::flagStrings[] =
707{''')
708
709    code.indent()
710    # The string array is used by SimpleEnumParam to map the strings
711    # provided by the user to enum values.
712    for flag, compound, desc in allFlags:
713        if not compound:
714            code('"$flag",')
715
716    code('"All",')
717    for flag, compound, desc in allFlags:
718        if compound:
719            code('"$flag",')
720    code.dedent()
721
722    code('''\
723};
724
725const int Trace::numFlagStrings = ${{len(allFlags) + 1}};
726
727''')
728
729    # Now define the individual compound flag arrays.  There is an array
730    # for each compound flag listing the component base flags.
731    all = tuple([flag for flag,compound,desc in allFlags if not compound])
732    code('static const Flags AllMap[] = {')
733    code.indent()
734    for flag, compound, desc in allFlags:
735        if not compound:
736            code('$flag,')
737    code.dedent()
738    code('};')
739    code()
740
741    for flag, compound, desc in allFlags:
742        if not compound:
743            continue
744        code('static const Flags ${flag}Map[] = {')
745        code.indent()
746        for flag in compound:
747            code('$flag,')
748        code('(Flags)-1')
749        code.dedent()
750        code('};')
751        code()
752
753    # Finally the compoundFlags[] array maps the compound flags
754    # to their individual arrays/
755    code('const Flags *Trace::compoundFlags[] = {')
756    code.indent()
757    code('AllMap,')
758    for flag, compound, desc in allFlags:
759        if compound:
760            code('${flag}Map,')
761    # file trailer
762    code.dedent()
763    code('};')
764
765    code.write(str(target[0]))
766
767def traceFlagsHH(target, source, env):
768    assert(len(target) == 1)
769
770    allFlags = getFlags(source)
771    code = code_formatter()
772
773    # file header boilerplate
774    code('''\
775/*
776 * DO NOT EDIT THIS FILE!
777 *
778 * Automatically generated from traceflags.py
779 */
780
781#ifndef __BASE_TRACE_FLAGS_HH__
782#define __BASE_TRACE_FLAGS_HH__
783
784namespace Trace {
785
786enum Flags {''')
787
788    # Generate the enum.  Base flags come first, then compound flags.
789    idx = 0
790    code.indent()
791    for flag, compound, desc in allFlags:
792        if not compound:
793            code('$flag = $idx,')
794            idx += 1
795
796    numBaseFlags = idx
797    code('NumFlags = $idx,')
798    code.dedent()
799    code()
800
801    # put a comment in here to separate base from compound flags
802    code('''
803// The remaining enum values are *not* valid indices for Trace::flags.
804// They are "compound" flags, which correspond to sets of base
805// flags, and are used by changeFlag.''')
806
807    code.indent()
808    code('All = $idx,')
809    idx += 1
810    for flag, compound, desc in allFlags:
811        if compound:
812            code('$flag = $idx,')
813            idx += 1
814
815    numCompoundFlags = idx - numBaseFlags
816    code('NumCompoundFlags = $numCompoundFlags')
817    code.dedent()
818
819    # trailer boilerplate
820    code('''\
821}; // enum Flags
822
823// Array of strings for SimpleEnumParam
824extern const char *flagStrings[];
825extern const int numFlagStrings;
826
827// Array of arraay pointers: for each compound flag, gives the list of
828// base flags to set.  Inidividual flag arrays are terminated by -1.
829extern const Flags *compoundFlags[];
830
831/* namespace Trace */ }
832
833#endif // __BASE_TRACE_FLAGS_HH__
834''')
835
836    code.write(str(target[0]))
837
838flags = map(Value, trace_flags.values())
839env.Command('base/traceflags.py', flags, traceFlagsPy)
840PySource('m5', 'base/traceflags.py')
841
842env.Command('base/traceflags.hh', flags, traceFlagsHH)
843env.Command('base/traceflags.cc', flags, traceFlagsCC)
844Source('base/traceflags.cc')
845
846# Embed python files.  All .py files that have been indicated by a
847# PySource() call in a SConscript need to be embedded into the M5
848# library.  To do that, we compile the file to byte code, marshal the
849# byte code, compress it, and then generate a c++ file that
850# inserts the result into an array.
851def embedPyFile(target, source, env):
852    def c_str(string):
853        if string is None:
854            return "0"
855        return '"%s"' % string
856
857    '''Action function to compile a .py into a code object, marshal
858    it, compress it, and stick it into an asm file so the code appears
859    as just bytes with a label in the data section'''
860
861    src = file(str(source[0]), 'r').read()
862
863    pysource = PySource.tnodes[source[0]]
864    compiled = compile(src, pysource.abspath, 'exec')
865    marshalled = marshal.dumps(compiled)
866    compressed = zlib.compress(marshalled)
867    data = compressed
868    sym = pysource.symname
869
870    code = code_formatter()
871    code('''\
872#include "sim/init.hh"
873
874namespace {
875
876const char data_${sym}[] = {
877''')
878    code.indent()
879    step = 16
880    for i in xrange(0, len(data), step):
881        x = array.array('B', data[i:i+step])
882        code(''.join('%d,' % d for d in x))
883    code.dedent()
884    
885    code('''};
886
887EmbeddedPython embedded_${sym}(
888    ${{c_str(pysource.arcname)}},
889    ${{c_str(pysource.abspath)}},
890    ${{c_str(pysource.modpath)}},
891    data_${sym},
892    ${{len(data)}},
893    ${{len(marshalled)}});
894
895/* namespace */ }
896''')
897    code.write(str(target[0]))
898
899for source in PySource.all:
900    env.Command(source.cpp, source.tnode, embedPyFile)
901    Source(source.cpp)
902
903########################################################################
904#
905# Define binaries.  Each different build type (debug, opt, etc.) gets
906# a slightly different build environment.
907#
908
909# List of constructed environments to pass back to SConstruct
910envList = []
911
912date_source = Source('base/date.cc', skip_lib=True)
913
914# Function to create a new build environment as clone of current
915# environment 'env' with modified object suffix and optional stripped
916# binary.  Additional keyword arguments are appended to corresponding
917# build environment vars.
918def makeEnv(label, objsfx, strip = False, **kwargs):
919    # SCons doesn't know to append a library suffix when there is a '.' in the
920    # name.  Use '_' instead.
921    libname = 'm5_' + label
922    exename = 'm5.' + label
923
924    new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
925    new_env.Label = label
926    new_env.Append(**kwargs)
927
928    swig_env = new_env.Clone()
929    swig_env.Append(CCFLAGS='-Werror')
930    if env['GCC']:
931        swig_env.Append(CCFLAGS='-Wno-uninitialized')
932        swig_env.Append(CCFLAGS='-Wno-sign-compare')
933        swig_env.Append(CCFLAGS='-Wno-parentheses')
934
935    werror_env = new_env.Clone()
936    werror_env.Append(CCFLAGS='-Werror')
937
938    def make_obj(source, static, extra_deps = None):
939        '''This function adds the specified source to the correct
940        build environment, and returns the corresponding SCons Object
941        nodes'''
942
943        if source.swig:
944            env = swig_env
945        elif source.Werror:
946            env = werror_env
947        else:
948            env = new_env
949
950        if static:
951            obj = env.StaticObject(source.tnode)
952        else:
953            obj = env.SharedObject(source.tnode)
954
955        if extra_deps:
956            env.Depends(obj, extra_deps)
957
958        return obj
959
960    static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)]
961    shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)]
962
963    static_date = make_obj(date_source, static=True, extra_deps=static_objs)
964    static_objs.append(static_date)
965    
966    shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
967    shared_objs.append(shared_date)
968
969    # First make a library of everything but main() so other programs can
970    # link against m5.
971    static_lib = new_env.StaticLibrary(libname, static_objs)
972    shared_lib = new_env.SharedLibrary(libname, shared_objs)
973
974    for target, sources in unit_tests:
975        objs = [ make_obj(s, static=True) for s in sources ]
976        new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs)
977
978    # Now link a stub with main() and the static library.
979    bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ]
980    progname = exename
981    if strip:
982        progname += '.unstripped'
983
984    targets = new_env.Program(progname, bin_objs + static_objs)
985
986    if strip:
987        if sys.platform == 'sunos5':
988            cmd = 'cp $SOURCE $TARGET; strip $TARGET'
989        else:
990            cmd = 'strip $SOURCE -o $TARGET'
991        targets = new_env.Command(exename, progname, cmd)
992            
993    new_env.M5Binary = targets[0]
994    envList.append(new_env)
995
996# Debug binary
997ccflags = {}
998if env['GCC']:
999    if sys.platform == 'sunos5':
1000        ccflags['debug'] = '-gstabs+'
1001    else:
1002        ccflags['debug'] = '-ggdb3'
1003    ccflags['opt'] = '-g -O3'
1004    ccflags['fast'] = '-O3'
1005    ccflags['prof'] = '-O3 -g -pg'
1006elif env['SUNCC']:
1007    ccflags['debug'] = '-g0'
1008    ccflags['opt'] = '-g -O'
1009    ccflags['fast'] = '-fast'
1010    ccflags['prof'] = '-fast -g -pg'
1011elif env['ICC']:
1012    ccflags['debug'] = '-g -O0'
1013    ccflags['opt'] = '-g -O'
1014    ccflags['fast'] = '-fast'
1015    ccflags['prof'] = '-fast -g -pg'
1016else:
1017    print 'Unknown compiler, please fix compiler options'
1018    Exit(1)
1019
1020makeEnv('debug', '.do',
1021        CCFLAGS = Split(ccflags['debug']),
1022        CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1023
1024# Optimized binary
1025makeEnv('opt', '.o',
1026        CCFLAGS = Split(ccflags['opt']),
1027        CPPDEFINES = ['TRACING_ON=1'])
1028
1029# "Fast" binary
1030makeEnv('fast', '.fo', strip = True,
1031        CCFLAGS = Split(ccflags['fast']),
1032        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1033
1034# Profiled binary
1035makeEnv('prof', '.po',
1036        CCFLAGS = Split(ccflags['prof']),
1037        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1038        LINKFLAGS = '-pg')
1039
1040Return('envList')
1041