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