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