SConscript revision 5863
110037SARM gem5 Developers# -*- mode:python -*-
212271Sjose.marinho@arm.com
312271Sjose.marinho@arm.com# Copyright (c) 2004-2005 The Regents of The University of Michigan
410037SARM gem5 Developers# All rights reserved.
512271Sjose.marinho@arm.com#
612271Sjose.marinho@arm.com# Redistribution and use in source and binary forms, with or without
712271Sjose.marinho@arm.com# modification, are permitted provided that the following conditions are
812271Sjose.marinho@arm.com# met: redistributions of source code must retain the above copyright
912271Sjose.marinho@arm.com# notice, this list of conditions and the following disclaimer;
1012271Sjose.marinho@arm.com# redistributions in binary form must reproduce the above copyright
1112271Sjose.marinho@arm.com# notice, this list of conditions and the following disclaimer in the
1212271Sjose.marinho@arm.com# documentation and/or other materials provided with the distribution;
1310037SARM gem5 Developers# neither the name of the copyright holders nor the names of its
1412271Sjose.marinho@arm.com# contributors may be used to endorse or promote products derived from
1512271Sjose.marinho@arm.com# this software without specific prior written permission.
1612271Sjose.marinho@arm.com#
1712271Sjose.marinho@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1812271Sjose.marinho@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1912271Sjose.marinho@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2012271Sjose.marinho@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2112271Sjose.marinho@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2212271Sjose.marinho@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2312271Sjose.marinho@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2412271Sjose.marinho@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2512271Sjose.marinho@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2612271Sjose.marinho@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2712271Sjose.marinho@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2812271Sjose.marinho@arm.com#
2912271Sjose.marinho@arm.com# Authors: Nathan Binkert
3012271Sjose.marinho@arm.com
3112271Sjose.marinho@arm.comimport array
3212271Sjose.marinho@arm.comimport imp
3312271Sjose.marinho@arm.comimport marshal
3412271Sjose.marinho@arm.comimport os
3512271Sjose.marinho@arm.comimport re
3612271Sjose.marinho@arm.comimport sys
3710037SARM gem5 Developersimport zlib
3810037SARM gem5 Developers
3910037SARM gem5 Developersfrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath
4010037SARM gem5 Developers
4110037SARM gem5 Developersimport SCons
4210037SARM gem5 Developers
4310037SARM gem5 Developers# This file defines how to build a particular configuration of M5
4410037SARM gem5 Developers# based on variable settings in the 'env' build environment.
4510037SARM gem5 Developers
4610037SARM gem5 DevelopersImport('*')
4710037SARM gem5 Developers
4810037SARM gem5 Developers# Children need to see the environment
4910037SARM gem5 DevelopersExport('env')
5010037SARM gem5 Developers
5110037SARM gem5 Developersbuild_env = dict([(opt, env[opt]) for opt in env.ExportVariables])
5210037SARM gem5 Developers
5310037SARM gem5 Developersdef sort_list(_list):
5410037SARM gem5 Developers    """return a sorted copy of '_list'"""
5510037SARM gem5 Developers    if isinstance(_list, list):
5610037SARM gem5 Developers        _list = _list[:]
5710037SARM gem5 Developers    else:
5810037SARM gem5 Developers        _list = list(_list)
5910037SARM gem5 Developers    _list.sort()
6010037SARM gem5 Developers    return _list
6110037SARM gem5 Developers
6210037SARM gem5 Developersclass PySourceFile(object):
6310037SARM gem5 Developers    invalid_sym_char = re.compile('[^A-z0-9_]')
6410037SARM gem5 Developers    def __init__(self, package, tnode):
6510037SARM gem5 Developers        snode = tnode.srcnode()
6611258Skarthik.sangaiah@arm.com        filename = str(tnode)
6711258Skarthik.sangaiah@arm.com        pyname = basename(filename)
6811258Skarthik.sangaiah@arm.com        assert pyname.endswith('.py')
6911258Skarthik.sangaiah@arm.com        name = pyname[:-3]
7013509Sjairo.balart@metempsy.com        if package:
7113509Sjairo.balart@metempsy.com            path = package.split('.')
7213509Sjairo.balart@metempsy.com        else:
7313509Sjairo.balart@metempsy.com            path = []
7413509Sjairo.balart@metempsy.com
7513509Sjairo.balart@metempsy.com        modpath = path[:]
7613509Sjairo.balart@metempsy.com        if name != '__init__':
7713509Sjairo.balart@metempsy.com            modpath += [name]
7813509Sjairo.balart@metempsy.com        modpath = '.'.join(modpath)
7913509Sjairo.balart@metempsy.com
8013509Sjairo.balart@metempsy.com        arcpath = path + [ pyname ]
8113509Sjairo.balart@metempsy.com        arcname = joinpath(*arcpath)
8213509Sjairo.balart@metempsy.com
8313509Sjairo.balart@metempsy.com        debugname = snode.abspath
8413509Sjairo.balart@metempsy.com        if not exists(debugname):
8513509Sjairo.balart@metempsy.com            debugname = tnode.abspath
8613509Sjairo.balart@metempsy.com
8713509Sjairo.balart@metempsy.com        self.tnode = tnode
8813509Sjairo.balart@metempsy.com        self.snode = snode
8913509Sjairo.balart@metempsy.com        self.pyname = pyname
9013509Sjairo.balart@metempsy.com        self.package = package
9113509Sjairo.balart@metempsy.com        self.modpath = modpath
9213509Sjairo.balart@metempsy.com        self.arcname = arcname
9314113Schunchenhsu@google.com        self.debugname = debugname
9414113Schunchenhsu@google.com        self.compiled = File(filename + 'c')
9514113Schunchenhsu@google.com        self.assembly = File(filename + '.s')
9614113Schunchenhsu@google.com        self.symname = "PyEMB_" + self.invalid_sym_char.sub('_', modpath)
9714113Schunchenhsu@google.com        
9813509Sjairo.balart@metempsy.com
9913509Sjairo.balart@metempsy.com########################################################################
10013509Sjairo.balart@metempsy.com# Code for adding source files of various types
10113509Sjairo.balart@metempsy.com#
10213509Sjairo.balart@metempsy.comcc_lib_sources = []
10311258Skarthik.sangaiah@arm.comdef Source(source):
10411258Skarthik.sangaiah@arm.com    '''Add a source file to the libm5 build'''
10510037SARM gem5 Developers    if not isinstance(source, SCons.Node.FS.File):
10610037SARM gem5 Developers        source = File(source)
10710037SARM gem5 Developers
10810037SARM gem5 Developers    cc_lib_sources.append(source)
10910037SARM gem5 Developers
11010037SARM gem5 Developerscc_bin_sources = []
11110037SARM gem5 Developersdef BinSource(source):
11210037SARM gem5 Developers    '''Add a source file to the m5 binary build'''
11310037SARM gem5 Developers    if not isinstance(source, SCons.Node.FS.File):
11410037SARM gem5 Developers        source = File(source)
11510037SARM gem5 Developers
11610037SARM gem5 Developers    cc_bin_sources.append(source)
11710037SARM gem5 Developers
11810037SARM gem5 Developerspy_sources = []
11910037SARM gem5 Developersdef PySource(package, source):
12010037SARM gem5 Developers    '''Add a python source file to the named package'''
12110037SARM gem5 Developers    if not isinstance(source, SCons.Node.FS.File):
12210037SARM gem5 Developers        source = File(source)
12310037SARM gem5 Developers
12413509Sjairo.balart@metempsy.com    source = PySourceFile(package, source)
12510037SARM gem5 Developers    py_sources.append(source)
12610037SARM gem5 Developers
12710037SARM gem5 Developerssim_objects_fixed = False
12810037SARM gem5 Developerssim_object_modfiles = set()
12910037SARM gem5 Developersdef SimObject(source):
13010037SARM gem5 Developers    '''Add a SimObject python file as a python source object and add
13110037SARM gem5 Developers    it to a list of sim object modules'''
13210037SARM gem5 Developers
13310037SARM gem5 Developers    if sim_objects_fixed:
13410037SARM gem5 Developers        raise AttributeError, "Too late to call SimObject now."
13510037SARM gem5 Developers
13610037SARM gem5 Developers    if not isinstance(source, SCons.Node.FS.File):
13710037SARM gem5 Developers        source = File(source)
13810037SARM gem5 Developers
13910037SARM gem5 Developers    PySource('m5.objects', source)
14010037SARM gem5 Developers    modfile = basename(str(source))
14110037SARM gem5 Developers    assert modfile.endswith('.py')
14210037SARM gem5 Developers    modname = modfile[:-3]
14310037SARM gem5 Developers    sim_object_modfiles.add(modname)
14410037SARM gem5 Developers
14510037SARM gem5 Developersswig_sources = []
14610037SARM gem5 Developersdef SwigSource(package, source):
14711258Skarthik.sangaiah@arm.com    '''Add a swig file to build'''
14811258Skarthik.sangaiah@arm.com    if not isinstance(source, SCons.Node.FS.File):
14911258Skarthik.sangaiah@arm.com        source = File(source)
15011258Skarthik.sangaiah@arm.com    val = source,package
15111258Skarthik.sangaiah@arm.com    swig_sources.append(val)
15211258Skarthik.sangaiah@arm.com
15311258Skarthik.sangaiah@arm.comunit_tests = []
15410037SARM gem5 Developersdef UnitTest(target, sources):
15510037SARM gem5 Developers    if not isinstance(sources, (list, tuple)):
15610037SARM gem5 Developers        sources = [ sources ]
15710037SARM gem5 Developers    
15810037SARM gem5 Developers    srcs = []
15910037SARM gem5 Developers    for source in sources:
16010037SARM gem5 Developers        if not isinstance(source, SCons.Node.FS.File):
16110037SARM gem5 Developers            source = File(source)
16210037SARM gem5 Developers        srcs.append(source)
16310037SARM gem5 Developers            
16410037SARM gem5 Developers    unit_tests.append((target, srcs))
16510037SARM gem5 Developers
16610037SARM gem5 Developers# Children should have access
16710037SARM gem5 DevelopersExport('Source')
16810037SARM gem5 DevelopersExport('BinSource')
16910037SARM gem5 DevelopersExport('PySource')
17010037SARM gem5 DevelopersExport('SimObject')
17110037SARM gem5 DevelopersExport('SwigSource')
17210037SARM gem5 DevelopersExport('UnitTest')
17310037SARM gem5 Developers
17410037SARM gem5 Developers########################################################################
17510037SARM gem5 Developers#
17610037SARM gem5 Developers# Trace Flags
17710037SARM gem5 Developers#
17810037SARM gem5 Developerstrace_flags = {}
17910037SARM gem5 Developersdef TraceFlag(name, desc=None):
18010037SARM gem5 Developers    if name in trace_flags:
18110037SARM gem5 Developers        raise AttributeError, "Flag %s already specified" % name
18210037SARM gem5 Developers    trace_flags[name] = (name, (), desc)
18310037SARM gem5 Developers
18410037SARM gem5 Developersdef CompoundFlag(name, flags, desc=None):
18510037SARM gem5 Developers    if name in trace_flags:
18610037SARM gem5 Developers        raise AttributeError, "Flag %s already specified" % name
18710037SARM gem5 Developers
18810037SARM gem5 Developers    compound = tuple(flags)
18910037SARM gem5 Developers    for flag in compound:
19010037SARM gem5 Developers        if flag not in trace_flags:
19110037SARM gem5 Developers            raise AttributeError, "Trace flag %s not found" % flag
19210037SARM gem5 Developers        if trace_flags[flag][1]:
19310037SARM gem5 Developers            raise AttributeError, \
19410037SARM gem5 Developers                "Compound flag can't point to another compound flag"
19510037SARM gem5 Developers
19610037SARM gem5 Developers    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