SConscript revision 8295
11689SN/A# -*- mode:python -*- 22316SN/A 31689SN/A# Copyright (c) 2004-2005 The Regents of The University of Michigan 41689SN/A# All rights reserved. 51689SN/A# 61689SN/A# Redistribution and use in source and binary forms, with or without 71689SN/A# modification, are permitted provided that the following conditions are 81689SN/A# met: redistributions of source code must retain the above copyright 91689SN/A# notice, this list of conditions and the following disclaimer; 101689SN/A# redistributions in binary form must reproduce the above copyright 111689SN/A# notice, this list of conditions and the following disclaimer in the 121689SN/A# documentation and/or other materials provided with the distribution; 131689SN/A# neither the name of the copyright holders nor the names of its 141689SN/A# contributors may be used to endorse or promote products derived from 151689SN/A# this software without specific prior written permission. 161689SN/A# 171689SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 181689SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 191689SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 201689SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 211689SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 221689SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 231689SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 241689SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 251689SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 261689SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 272665Ssaidi@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 282665Ssaidi@eecs.umich.edu# 292756Sksewell@umich.edu# Authors: Nathan Binkert 301689SN/A 311689SN/Aimport array 322292SN/Aimport bisect 332292SN/Aimport imp 341060SN/Aimport marshal 351461SN/Aimport os 367813Ssteve.reinhardt@amd.comimport re 372292SN/Aimport sys 382329SN/Aimport zlib 391060SN/A 405529Snate@binkert.orgfrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath 415529Snate@binkert.org 422292SN/Aimport SCons 432292SN/A 442292SN/A# This file defines how to build a particular configuration of M5 452292SN/A# based on variable settings in the 'env' build environment. 462316SN/A 472316SN/AImport('*') 482316SN/A 492316SN/A# Children need to see the environment 502316SN/AExport('env') 512316SN/A 522316SN/Abuild_env = [(opt, env[opt]) for opt in export_vars] 532316SN/A 542316SN/Afrom m5.util import code_formatter 552316SN/A 562316SN/A######################################################################## 572316SN/A# Code for adding source files of various types 582316SN/A# 592316SN/A# When specifying a source file of some type, a set of guards can be 602316SN/A# specified for that file. When get() is used to find the files, if 612316SN/A# get specifies a set of filters, only files that match those filters 622316SN/A# will be accepted (unspecified filters on files are assumed to be 632316SN/A# false). Current filters are: 642316SN/A# main -- specifies the m5 main() function 652329SN/A# skip_lib -- do not put this file into the m5 library 662292SN/A# <unittest> -- unit tests use filters based on the unit test name 671060SN/A# 682292SN/A# A parent can now be specified for a source file and default filter 691060SN/A# values will be retrieved recursively from parents (children override 701060SN/A# parents). 711060SN/A# 722733Sktlim@umich.educlass SourceMeta(type): 731061SN/A '''Meta class for source files that keeps track of all files of a 741061SN/A particular type and has a get function for finding all functions 751060SN/A of a certain type that match a set of guards''' 762292SN/A def __init__(cls, name, bases, dict): 771061SN/A super(SourceMeta, cls).__init__(name, bases, dict) 781060SN/A cls.all = [] 791061SN/A 802292SN/A def get(cls, **guards): 811061SN/A '''Find all files that match the specified guards. If a source 821061SN/A file does not specify a flag, the default is False''' 831060SN/A for src in cls.all: 842316SN/A for flag,value in guards.iteritems(): 852292SN/A # if the flag is found and has a different value, skip 862292SN/A # this file 872292SN/A if src.all_guards.get(flag, False) != value: 882292SN/A break 892348SN/A else: 902348SN/A yield src 912348SN/A 922292SN/Aclass SourceFile(object): 932292SN/A '''Base object that encapsulates the notion of a source file. 942292SN/A This includes, the source node, target node, various manipulations 956221Snate@binkert.org of those. A source file also specifies a set of guards which 962292SN/A describing which builds the source file applies to. A parent can 972292SN/A also be specified to get default guards from''' 986221Snate@binkert.org __metaclass__ = SourceMeta 992292SN/A def __init__(self, source, parent=None, **guards): 1002292SN/A self.guards = guards 1015336Shines@cs.fsu.edu self.parent = parent 1022292SN/A 1032292SN/A tnode = source 1042292SN/A if not isinstance(source, SCons.Node.FS.File): 1052292SN/A tnode = File(source) 1062292SN/A 1072292SN/A self.tnode = tnode 1082292SN/A self.snode = tnode.srcnode() 1092292SN/A 1102292SN/A for base in type(self).__mro__: 1112292SN/A if issubclass(base, SourceFile): 1122292SN/A base.all.append(self) 1132292SN/A 1141060SN/A @property 1151060SN/A def filename(self): 1161060SN/A return str(self.tnode) 1172292SN/A 1182292SN/A @property 1192292SN/A def dirname(self): 1202292SN/A return dirname(self.filename) 1212292SN/A 1222292SN/A @property 1232292SN/A def basename(self): 1242292SN/A return basename(self.filename) 1252292SN/A 1261060SN/A @property 1271060SN/A def extname(self): 1281060SN/A index = self.basename.rfind('.') 1292292SN/A if index <= 0: 1302292SN/A # dot files aren't extensions 1312292SN/A return self.basename, None 1322292SN/A 1332292SN/A return self.basename[:index], self.basename[index+1:] 1342292SN/A 1352292SN/A @property 1362292SN/A def all_guards(self): 1371060SN/A '''find all guards for this object getting default values 1381060SN/A recursively from its parents''' 1392292SN/A guards = {} 1405529Snate@binkert.org if self.parent: 1411060SN/A guards.update(self.parent.guards) 1422292SN/A guards.update(self.guards) 1432292SN/A return guards 1442292SN/A 1452292SN/A def __lt__(self, other): return self.filename < other.filename 1461062SN/A def __le__(self, other): return self.filename <= other.filename 1471062SN/A def __gt__(self, other): return self.filename > other.filename 1482292SN/A def __ge__(self, other): return self.filename >= other.filename 1492292SN/A def __eq__(self, other): return self.filename == other.filename 1502292SN/A def __ne__(self, other): return self.filename != other.filename 1512292SN/A 1521060SN/Aclass Source(SourceFile): 1531060SN/A '''Add a c/c++ source file to the build''' 1542292SN/A def __init__(self, source, Werror=True, swig=False, **guards): 1552292SN/A '''specify the source file, and any guards''' 1562292SN/A super(Source, self).__init__(source, **guards) 1571060SN/A 1581060SN/A self.Werror = Werror 1592292SN/A self.swig = swig 1601060SN/A 1611060SN/Aclass PySource(SourceFile): 1622348SN/A '''Add a python source file to the named package''' 1632292SN/A invalid_sym_char = re.compile('[^A-z0-9_]') 1642292SN/A modules = {} 1652965Sksewell@umich.edu tnodes = {} 1662965Sksewell@umich.edu symnames = {} 1672965Sksewell@umich.edu 1682316SN/A def __init__(self, package, source, **guards): 1692316SN/A '''specify the python package, the source file, and any guards''' 1702316SN/A super(PySource, self).__init__(source, **guards) 1712292SN/A 1722292SN/A modname,ext = self.extname 1732292SN/A assert ext == 'py' 1742292SN/A 1756221Snate@binkert.org if package: 1762292SN/A path = package.split('.') 1772292SN/A else: 1782292SN/A path = [] 1792292SN/A 1802292SN/A modpath = path[:] 1811060SN/A if modname != '__init__': 1821060SN/A modpath += [ modname ] 1832292SN/A modpath = '.'.join(modpath) 1842292SN/A 1852292SN/A arcpath = path + [ self.basename ] 1862843Sktlim@umich.edu abspath = self.snode.abspath 1872863Sktlim@umich.edu if not exists(abspath): 1882843Sktlim@umich.edu abspath = self.tnode.abspath 1892843Sktlim@umich.edu 1902843Sktlim@umich.edu self.package = package 1912307SN/A self.modname = modname 1922348SN/A self.modpath = modpath 1932843Sktlim@umich.edu self.arcname = joinpath(*arcpath) 1942316SN/A self.abspath = abspath 1952348SN/A self.compiled = File(self.filename + 'c') 1962307SN/A self.cpp = File(self.filename + '.cc') 1972307SN/A self.symname = PySource.invalid_sym_char.sub('_', modpath) 1982292SN/A 1991060SN/A PySource.modules[modpath] = self 2001060SN/A PySource.tnodes[self.tnode] = self 2012292SN/A PySource.symnames[self.symname] = self 2022292SN/A 2032292SN/Aclass SimObject(PySource): 2041060SN/A '''Add a SimObject python file as a python source object and add 2051060SN/A it to a list of sim object modules''' 2062292SN/A 2076221Snate@binkert.org fixed = False 2082292SN/A modnames = [] 2092348SN/A 2106221Snate@binkert.org def __init__(self, source, **guards): 2112348SN/A '''Specify the source file and any guards (automatically in 2122348SN/A the m5.objects package)''' 2132680Sktlim@umich.edu super(SimObject, self).__init__('m5.objects', source, **guards) 2142348SN/A if self.fixed: 2156221Snate@binkert.org raise AttributeError, "Too late to call SimObject now." 2162292SN/A 2171060SN/A bisect.insort_right(SimObject.modnames, self.modname) 2182292SN/A 2192348SN/Aclass SwigSource(SourceFile): 2202348SN/A '''Add a swig file to build''' 2212292SN/A 2221060SN/A def __init__(self, package, source, **guards): 2232292SN/A '''Specify the python package, the source file, and any guards''' 2242292SN/A super(SwigSource, self).__init__(source, **guards) 2252292SN/A 2262292SN/A modname,ext = self.extname 2272292SN/A assert ext == 'i' 2282292SN/A 2292292SN/A self.module = modname 2302292SN/A cc_file = joinpath(self.dirname, modname + '_wrap.cc') 2312292SN/A py_file = joinpath(self.dirname, modname + '.py') 2322292SN/A 2332292SN/A self.cc_source = Source(cc_file, swig=True, parent=self) 2342292SN/A self.py_source = PySource(package, py_file, parent=self) 2352292SN/A 2362292SN/Aclass UnitTest(object): 2372292SN/A '''Create a UnitTest''' 2382292SN/A 2392348SN/A all = [] 2406221Snate@binkert.org def __init__(self, target, *sources): 2412316SN/A '''Specify the target name and any sources. Sources that are 2422348SN/A not SourceFiles are evalued with Source(). All files are 2436221Snate@binkert.org guarded with a guard of the same name as the UnitTest 2442292SN/A target.''' 2452680Sktlim@umich.edu 2466221Snate@binkert.org srcs = [] 2472292SN/A for src in sources: 2487784SAli.Saidi@ARM.com if not isinstance(src, SourceFile): 2497784SAli.Saidi@ARM.com src = Source(src, skip_lib=True) 2507784SAli.Saidi@ARM.com src.guards[target] = True 2517784SAli.Saidi@ARM.com srcs.append(src) 2527784SAli.Saidi@ARM.com 2537784SAli.Saidi@ARM.com self.sources = srcs 2547784SAli.Saidi@ARM.com self.target = target 2554035Sktlim@umich.edu UnitTest.all.append(self) 2564035Sktlim@umich.edu 2574035Sktlim@umich.edu# Children should have access 2587847Sminkyu.jeong@arm.comExport('Source') 2597847Sminkyu.jeong@arm.comExport('PySource') 2607847Sminkyu.jeong@arm.comExport('SimObject') 2614035Sktlim@umich.eduExport('SwigSource') 2624035Sktlim@umich.eduExport('UnitTest') 2632292SN/A 2641060SN/A######################################################################## 2651060SN/A# 2662292SN/A# Debug Flags 2672292SN/A# 2682292SN/Adebug_flags = {} 2691061SN/Adef DebugFlag(name, desc=None): 2701060SN/A if name in debug_flags: 2712292SN/A raise AttributeError, "Flag %s already specified" % name 2721060SN/A debug_flags[name] = (name, (), desc) 2731060SN/ATraceFlag = DebugFlag 2742965Sksewell@umich.edu 2752965Sksewell@umich.edudef CompoundFlag(name, flags, desc=None): 2762965Sksewell@umich.edu if name in debug_flags: 2772292SN/A raise AttributeError, "Flag %s already specified" % name 2781060SN/A 2791060SN/A compound = tuple(flags) 2802292SN/A debug_flags[name] = (name, compound, desc) 2816221Snate@binkert.org 2822292SN/AExport('DebugFlag') 2832292SN/AExport('TraceFlag') 2846221Snate@binkert.orgExport('CompoundFlag') 2852292SN/A 2862292SN/A######################################################################## 2876221Snate@binkert.org# 2882292SN/A# Set some compiler variables 2891684SN/A# 2907720Sgblack@eecs.umich.edu 2917720Sgblack@eecs.umich.edu# Include file paths are rooted in this directory. SCons will 2927720Sgblack@eecs.umich.edu# automatically expand '.' to refer to both the source directory and 2937720Sgblack@eecs.umich.edu# the corresponding build directory to pick up generated include 2947720Sgblack@eecs.umich.edu# files. 2957720Sgblack@eecs.umich.eduenv.Append(CPPPATH=Dir('.')) 2961684SN/A 2972348SN/Afor extra_dir in extras_dir_list: 2987720Sgblack@eecs.umich.edu env.Append(CPPPATH=Dir(extra_dir)) 2992292SN/A 3007720Sgblack@eecs.umich.edu# Workaround for bug in SCons version > 0.97d20071212 3017720Sgblack@eecs.umich.edu# Scons bug id: 2006 M5 Bug id: 308 3024636Sgblack@eecs.umich.edufor root, dirs, files in os.walk(base_dir, topdown=True): 3034636Sgblack@eecs.umich.edu Dir(root[len(base_dir) + 1:]) 3047720Sgblack@eecs.umich.edu 3052756Sksewell@umich.edu######################################################################## 3061684SN/A# 3071060SN/A# Walk the tree and execute all SConscripts in subdirectories 3081060SN/A# 3091060SN/A 3101060SN/Ahere = Dir('.').srcnode().abspath 3111060SN/Afor root, dirs, files in os.walk(base_dir, topdown=True): 3121060SN/A if root == here: 3131060SN/A # we don't want to recurse back into this SConscript 3141060SN/A continue 3151060SN/A 3162292SN/A if 'SConscript' in files: 3172292SN/A build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 3182292SN/A SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 3192292SN/A 3201060SN/Afor extra_dir in extras_dir_list: 3211060SN/A prefix_len = len(dirname(extra_dir)) + 1 3221060SN/A for root, dirs, files in os.walk(extra_dir, topdown=True): 3231060SN/A # if build lives in the extras directory, don't walk down it 3241060SN/A if 'build' in dirs: 3251060SN/A dirs.remove('build') 3261060SN/A 3271060SN/A if 'SConscript' in files: 3281060SN/A build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 3291060SN/A SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 3301060SN/A 3311060SN/Afor opt in export_vars: 3322292SN/A env.ConfigFile(opt) 3331060SN/A 3341060SN/Adef makeTheISA(source, target, env): 3351060SN/A isas = [ src.get_contents() for src in source ] 3362292SN/A target_isa = env['TARGET_ISA'] 3372733Sktlim@umich.edu def define(isa): 3382733Sktlim@umich.edu return isa.upper() + '_ISA' 3391060SN/A 3402348SN/A def namespace(isa): 3412292SN/A return isa[0].upper() + isa[1:].lower() + 'ISA' 3421060SN/A 3432292SN/A 3442292SN/A code = code_formatter() 3452292SN/A code('''\ 3462292SN/A#ifndef __CONFIG_THE_ISA_HH__ 3472292SN/A#define __CONFIG_THE_ISA_HH__ 3482292SN/A 3492292SN/A''') 3502292SN/A 3512292SN/A for i,isa in enumerate(isas): 3522292SN/A code('#define $0 $1', define(isa), i + 1) 3532292SN/A 3546221Snate@binkert.org code(''' 3552292SN/A 3562292SN/A#define THE_ISA ${{define(target_isa)}} 3572292SN/A#define TheISA ${{namespace(target_isa)}} 3582292SN/A 3592292SN/A#endif // __CONFIG_THE_ISA_HH__''') 3602680Sktlim@umich.edu 3612292SN/A code.write(str(target[0])) 3622292SN/A 3636221Snate@binkert.orgenv.Command('config/the_isa.hh', map(Value, all_isa_list), 3642292SN/A MakeAction(makeTheISA, Transform("CFG ISA", 0))) 3651060SN/A 3661060SN/A######################################################################## 3671060SN/A# 3682292SN/A# Prevent any SimObjects from being added after this point, they 3692292SN/A# should all have been added in the SConscripts above 3702292SN/A# 3711060SN/ASimObject.fixed = True 3721060SN/A 3731060SN/Aclass DictImporter(object): 3742292SN/A '''This importer takes a dictionary of arbitrary module names that 3752292SN/A map to arbitrary filenames.''' 3761060SN/A def __init__(self, modules): 3771060SN/A self.modules = modules 3781060SN/A self.installed = set() 3791060SN/A 3801060SN/A def __del__(self): 3811060SN/A self.unload() 3821060SN/A 3831062SN/A def unload(self): 3842292SN/A import sys 3852292SN/A for module in self.installed: 3862292SN/A del sys.modules[module] 3872292SN/A self.installed = set() 3886221Snate@binkert.org 3892292SN/A def find_module(self, fullname, path): 3902843Sktlim@umich.edu if fullname == 'm5.defines': 3912843Sktlim@umich.edu return self 3922348SN/A 3932348SN/A if fullname == 'm5.objects': 3942307SN/A return self 3952307SN/A 3962348SN/A if fullname.startswith('m5.internal'): 3972348SN/A return None 3982348SN/A 3992292SN/A source = self.modules.get(fullname, None) 4002292SN/A if source is not None and fullname.startswith('m5.objects'): 4013640Sktlim@umich.edu return self 4023640Sktlim@umich.edu 4033640Sktlim@umich.edu return None 4047720Sgblack@eecs.umich.edu 4052348SN/A def load_module(self, fullname): 4062348SN/A mod = imp.new_module(fullname) 4077720Sgblack@eecs.umich.edu sys.modules[fullname] = mod 4084636Sgblack@eecs.umich.edu self.installed.add(fullname) 4092292SN/A 4102292SN/A mod.__loader__ = self 4112292SN/A if fullname == 'm5.objects': 4124035Sktlim@umich.edu mod.__path__ = fullname.split('.') 4134035Sktlim@umich.edu return mod 4144035Sktlim@umich.edu 4154035Sktlim@umich.edu if fullname == 'm5.defines': 4164035Sktlim@umich.edu mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 4174035Sktlim@umich.edu return mod 4184035Sktlim@umich.edu 4194035Sktlim@umich.edu source = self.modules[fullname] 4204035Sktlim@umich.edu if source.modname == '__init__': 4214035Sktlim@umich.edu mod.__path__ = source.modpath 4222292SN/A mod.__file__ = source.abspath 4236221Snate@binkert.org 4242292SN/A exec file(source.abspath, 'r') in mod.__dict__ 4252292SN/A 4262292SN/A return mod 4272292SN/A 4282348SN/Aimport m5.SimObject 4292301SN/Aimport m5.params 4302301SN/Afrom m5.util import code_formatter 4312292SN/A 4325999Snate@binkert.orgm5.SimObject.clear() 4332292SN/Am5.params.clear() 4342292SN/A 4355999Snate@binkert.org# install the python importer so we can grab stuff from the source 4362292SN/A# tree itself. We can't have SimObjects added after this point or 4372292SN/A# else we won't know about them for the rest of the stuff. 4382292SN/Aimporter = DictImporter(PySource.modules) 4395999Snate@binkert.orgsys.meta_path[0:0] = [ importer ] 4402292SN/A 4412292SN/A# import all sim objects so we can populate the all_objects list 4422292SN/A# make sure that we're working with a list, then let's sort it 4435999Snate@binkert.orgfor modname in SimObject.modnames: 4442292SN/A exec('from m5.objects import %s' % modname) 4455999Snate@binkert.org 4462292SN/A# we need to unload all of the currently imported modules so that they 4475999Snate@binkert.org# will be re-imported the next time the sconscript is run 4481062SN/Aimporter.unload() 4492316SN/Asys.meta_path.remove(importer) 4505999Snate@binkert.org 4512316SN/Asim_objects = m5.SimObject.allClasses 4525999Snate@binkert.orgall_enums = m5.params.allEnums 4532316SN/A 4545999Snate@binkert.orgall_params = {} 4552316SN/Afor name,obj in sorted(sim_objects.iteritems()): 4565999Snate@binkert.org for param in obj._params.local.values(): 4572316SN/A # load the ptype attribute now because it depends on the 4585999Snate@binkert.org # current version of SimObject.allClasses, but when scons 4592316SN/A # actually uses the value, all versions of 4605999Snate@binkert.org # SimObject.allClasses will have been loaded 4612301SN/A param.ptype 4622348SN/A 4635999Snate@binkert.org if not hasattr(param, 'swig_decl'): 4642348SN/A continue 4655999Snate@binkert.org pname = param.ptype_str 4661060SN/A if pname not in all_params: 4671060SN/A all_params[pname] = param 4682292SN/A 469######################################################################## 470# 471# calculate extra dependencies 472# 473module_depends = ["m5", "m5.SimObject", "m5.params"] 474depends = [ PySource.modules[dep].snode for dep in module_depends ] 475 476######################################################################## 477# 478# Commands for the basic automatically generated python files 479# 480 481# Generate Python file containing a dict specifying the current 482# buildEnv flags. 483def makeDefinesPyFile(target, source, env): 484 build_env = source[0].get_contents() 485 486 code = code_formatter() 487 code(""" 488import m5.internal 489import m5.util 490 491buildEnv = m5.util.SmartDict($build_env) 492 493compileDate = m5.internal.core.compileDate 494_globals = globals() 495for key,val in m5.internal.core.__dict__.iteritems(): 496 if key.startswith('flag_'): 497 flag = key[5:] 498 _globals[flag] = val 499del _globals 500""") 501 code.write(target[0].abspath) 502 503defines_info = Value(build_env) 504# Generate a file with all of the compile options in it 505env.Command('python/m5/defines.py', defines_info, 506 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 507PySource('m5', 'python/m5/defines.py') 508 509# Generate python file containing info about the M5 source code 510def makeInfoPyFile(target, source, env): 511 code = code_formatter() 512 for src in source: 513 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 514 code('$src = ${{repr(data)}}') 515 code.write(str(target[0])) 516 517# Generate a file that wraps the basic top level files 518env.Command('python/m5/info.py', 519 [ '#/AUTHORS', '#/LICENSE', '#/README', ], 520 MakeAction(makeInfoPyFile, Transform("INFO"))) 521PySource('m5', 'python/m5/info.py') 522 523######################################################################## 524# 525# Create all of the SimObject param headers and enum headers 526# 527 528def createSimObjectParam(target, source, env): 529 assert len(target) == 1 and len(source) == 1 530 531 name = str(source[0].get_contents()) 532 obj = sim_objects[name] 533 534 code = code_formatter() 535 obj.cxx_decl(code) 536 code.write(target[0].abspath) 537 538def createSwigParam(target, source, env): 539 assert len(target) == 1 and len(source) == 1 540 541 name = str(source[0].get_contents()) 542 param = all_params[name] 543 544 code = code_formatter() 545 code('%module(package="m5.internal") $0_${name}', param.file_ext) 546 param.swig_decl(code) 547 code.write(target[0].abspath) 548 549def createEnumStrings(target, source, env): 550 assert len(target) == 1 and len(source) == 1 551 552 name = str(source[0].get_contents()) 553 obj = all_enums[name] 554 555 code = code_formatter() 556 obj.cxx_def(code) 557 code.write(target[0].abspath) 558 559def createEnumParam(target, source, env): 560 assert len(target) == 1 and len(source) == 1 561 562 name = str(source[0].get_contents()) 563 obj = all_enums[name] 564 565 code = code_formatter() 566 obj.cxx_decl(code) 567 code.write(target[0].abspath) 568 569def createEnumSwig(target, source, env): 570 assert len(target) == 1 and len(source) == 1 571 572 name = str(source[0].get_contents()) 573 obj = all_enums[name] 574 575 code = code_formatter() 576 code('''\ 577%module(package="m5.internal") enum_$name 578 579%{ 580#include "enums/$name.hh" 581%} 582 583%include "enums/$name.hh" 584''') 585 code.write(target[0].abspath) 586 587# Generate all of the SimObject param struct header files 588params_hh_files = [] 589for name,simobj in sorted(sim_objects.iteritems()): 590 py_source = PySource.modules[simobj.__module__] 591 extra_deps = [ py_source.tnode ] 592 593 hh_file = File('params/%s.hh' % name) 594 params_hh_files.append(hh_file) 595 env.Command(hh_file, Value(name), 596 MakeAction(createSimObjectParam, Transform("SO PARAM"))) 597 env.Depends(hh_file, depends + extra_deps) 598 599# Generate any parameter header files needed 600params_i_files = [] 601for name,param in all_params.iteritems(): 602 i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name)) 603 params_i_files.append(i_file) 604 env.Command(i_file, Value(name), 605 MakeAction(createSwigParam, Transform("SW PARAM"))) 606 env.Depends(i_file, depends) 607 SwigSource('m5.internal', i_file) 608 609# Generate all enum header files 610for name,enum in sorted(all_enums.iteritems()): 611 py_source = PySource.modules[enum.__module__] 612 extra_deps = [ py_source.tnode ] 613 614 cc_file = File('enums/%s.cc' % name) 615 env.Command(cc_file, Value(name), 616 MakeAction(createEnumStrings, Transform("ENUM STR"))) 617 env.Depends(cc_file, depends + extra_deps) 618 Source(cc_file) 619 620 hh_file = File('enums/%s.hh' % name) 621 env.Command(hh_file, Value(name), 622 MakeAction(createEnumParam, Transform("EN PARAM"))) 623 env.Depends(hh_file, depends + extra_deps) 624 625 i_file = File('python/m5/internal/enum_%s.i' % name) 626 env.Command(i_file, Value(name), 627 MakeAction(createEnumSwig, Transform("ENUMSWIG"))) 628 env.Depends(i_file, depends + extra_deps) 629 SwigSource('m5.internal', i_file) 630 631def buildParam(target, source, env): 632 name = source[0].get_contents() 633 obj = sim_objects[name] 634 class_path = obj.cxx_class.split('::') 635 classname = class_path[-1] 636 namespaces = class_path[:-1] 637 params = obj._params.local.values() 638 639 code = code_formatter() 640 641 code('%module(package="m5.internal") param_$name') 642 code() 643 code('%{') 644 code('#include "params/$obj.hh"') 645 for param in params: 646 param.cxx_predecls(code) 647 code('%}') 648 code() 649 650 for param in params: 651 param.swig_predecls(code) 652 653 code() 654 if obj._base: 655 code('%import "python/m5/internal/param_${{obj._base}}.i"') 656 code() 657 obj.swig_objdecls(code) 658 code() 659 660 code('%include "params/$obj.hh"') 661 662 code.write(target[0].abspath) 663 664for name in sim_objects.iterkeys(): 665 params_file = File('python/m5/internal/param_%s.i' % name) 666 env.Command(params_file, Value(name), 667 MakeAction(buildParam, Transform("BLDPARAM"))) 668 env.Depends(params_file, depends) 669 SwigSource('m5.internal', params_file) 670 671# Generate the main swig init file 672def makeEmbeddedSwigInit(target, source, env): 673 code = code_formatter() 674 module = source[0].get_contents() 675 code('''\ 676#include "sim/init.hh" 677 678extern "C" { 679 void init_${module}(); 680} 681 682EmbeddedSwig embed_swig_${module}(init_${module}); 683''') 684 code.write(str(target[0])) 685 686# Build all swig modules 687for swig in SwigSource.all: 688 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 689 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 690 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG"))) 691 cc_file = str(swig.tnode) 692 init_file = '%s/init_%s.cc' % (dirname(cc_file), basename(cc_file)) 693 env.Command(init_file, Value(swig.module), 694 MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW"))) 695 Source(init_file, **swig.guards) 696 697# 698# Handle debug flags 699# 700def makeDebugFlagCC(target, source, env): 701 assert(len(target) == 1 and len(source) == 1) 702 703 val = eval(source[0].get_contents()) 704 name, compound, desc = val 705 compound = list(sorted(compound)) 706 707 code = code_formatter() 708 709 # file header 710 code(''' 711/* 712 * DO NOT EDIT THIS FILE! Automatically generated 713 */ 714 715#include "base/debug.hh" 716''') 717 718 for flag in compound: 719 code('#include "debug/$flag.hh"') 720 code() 721 code('namespace Debug {') 722 code() 723 724 if not compound: 725 code('SimpleFlag $name("$name", "$desc");') 726 else: 727 code('CompoundFlag $name("$name", "$desc",') 728 code.indent() 729 last = len(compound) - 1 730 for i,flag in enumerate(compound): 731 if i != last: 732 code('$flag,') 733 else: 734 code('$flag);') 735 code.dedent() 736 737 code() 738 code('} // namespace Debug') 739 740 code.write(str(target[0])) 741 742def makeDebugFlagHH(target, source, env): 743 assert(len(target) == 1 and len(source) == 1) 744 745 val = eval(source[0].get_contents()) 746 name, compound, desc = val 747 748 code = code_formatter() 749 750 # file header boilerplate 751 code('''\ 752/* 753 * DO NOT EDIT THIS FILE! 754 * 755 * Automatically generated by SCons 756 */ 757 758#ifndef __DEBUG_${name}_HH__ 759#define __DEBUG_${name}_HH__ 760 761namespace Debug { 762''') 763 764 if compound: 765 code('class CompoundFlag;') 766 code('class SimpleFlag;') 767 768 if compound: 769 code('extern CompoundFlag $name;') 770 for flag in compound: 771 code('extern SimpleFlag $flag;') 772 else: 773 code('extern SimpleFlag $name;') 774 775 code(''' 776} 777 778#endif // __DEBUG_${name}_HH__ 779''') 780 781 code.write(str(target[0])) 782 783for name,flag in sorted(debug_flags.iteritems()): 784 n, compound, desc = flag 785 assert n == name 786 787 env.Command('debug/%s.hh' % name, Value(flag), 788 MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) 789 env.Command('debug/%s.cc' % name, Value(flag), 790 MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) 791 Source('debug/%s.cc' % name) 792 793# Embed python files. All .py files that have been indicated by a 794# PySource() call in a SConscript need to be embedded into the M5 795# library. To do that, we compile the file to byte code, marshal the 796# byte code, compress it, and then generate a c++ file that 797# inserts the result into an array. 798def embedPyFile(target, source, env): 799 def c_str(string): 800 if string is None: 801 return "0" 802 return '"%s"' % string 803 804 '''Action function to compile a .py into a code object, marshal 805 it, compress it, and stick it into an asm file so the code appears 806 as just bytes with a label in the data section''' 807 808 src = file(str(source[0]), 'r').read() 809 810 pysource = PySource.tnodes[source[0]] 811 compiled = compile(src, pysource.abspath, 'exec') 812 marshalled = marshal.dumps(compiled) 813 compressed = zlib.compress(marshalled) 814 data = compressed 815 sym = pysource.symname 816 817 code = code_formatter() 818 code('''\ 819#include "sim/init.hh" 820 821namespace { 822 823const char data_${sym}[] = { 824''') 825 code.indent() 826 step = 16 827 for i in xrange(0, len(data), step): 828 x = array.array('B', data[i:i+step]) 829 code(''.join('%d,' % d for d in x)) 830 code.dedent() 831 832 code('''}; 833 834EmbeddedPython embedded_${sym}( 835 ${{c_str(pysource.arcname)}}, 836 ${{c_str(pysource.abspath)}}, 837 ${{c_str(pysource.modpath)}}, 838 data_${sym}, 839 ${{len(data)}}, 840 ${{len(marshalled)}}); 841 842} // anonymous namespace 843''') 844 code.write(str(target[0])) 845 846for source in PySource.all: 847 env.Command(source.cpp, source.tnode, 848 MakeAction(embedPyFile, Transform("EMBED PY"))) 849 Source(source.cpp) 850 851######################################################################## 852# 853# Define binaries. Each different build type (debug, opt, etc.) gets 854# a slightly different build environment. 855# 856 857# List of constructed environments to pass back to SConstruct 858envList = [] 859 860date_source = Source('base/date.cc', skip_lib=True) 861 862# Function to create a new build environment as clone of current 863# environment 'env' with modified object suffix and optional stripped 864# binary. Additional keyword arguments are appended to corresponding 865# build environment vars. 866def makeEnv(label, objsfx, strip = False, **kwargs): 867 # SCons doesn't know to append a library suffix when there is a '.' in the 868 # name. Use '_' instead. 869 libname = 'm5_' + label 870 exename = 'm5.' + label 871 872 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 873 new_env.Label = label 874 new_env.Append(**kwargs) 875 876 swig_env = new_env.Clone() 877 swig_env.Append(CCFLAGS='-Werror') 878 if env['GCC']: 879 swig_env.Append(CCFLAGS='-Wno-uninitialized') 880 swig_env.Append(CCFLAGS='-Wno-sign-compare') 881 swig_env.Append(CCFLAGS='-Wno-parentheses') 882 883 werror_env = new_env.Clone() 884 werror_env.Append(CCFLAGS='-Werror') 885 886 def make_obj(source, static, extra_deps = None): 887 '''This function adds the specified source to the correct 888 build environment, and returns the corresponding SCons Object 889 nodes''' 890 891 if source.swig: 892 env = swig_env 893 elif source.Werror: 894 env = werror_env 895 else: 896 env = new_env 897 898 if static: 899 obj = env.StaticObject(source.tnode) 900 else: 901 obj = env.SharedObject(source.tnode) 902 903 if extra_deps: 904 env.Depends(obj, extra_deps) 905 906 return obj 907 908 sources = Source.get(main=False, skip_lib=False) 909 static_objs = [ make_obj(s, True) for s in sources ] 910 shared_objs = [ make_obj(s, False) for s in sources ] 911 912 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 913 static_objs.append(static_date) 914 915 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 916 shared_objs.append(shared_date) 917 918 # First make a library of everything but main() so other programs can 919 # link against m5. 920 static_lib = new_env.StaticLibrary(libname, static_objs) 921 shared_lib = new_env.SharedLibrary(libname, shared_objs) 922 923 # Now link a stub with main() and the static library. 924 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ] 925 926 for test in UnitTest.all: 927 flags = { test.target : True } 928 test_sources = Source.get(**flags) 929 test_objs = [ make_obj(s, static=True) for s in test_sources ] 930 testname = "unittest/%s.%s" % (test.target, label) 931 new_env.Program(testname, main_objs + test_objs + static_objs) 932 933 progname = exename 934 if strip: 935 progname += '.unstripped' 936 937 targets = new_env.Program(progname, main_objs + static_objs) 938 939 if strip: 940 if sys.platform == 'sunos5': 941 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 942 else: 943 cmd = 'strip $SOURCE -o $TARGET' 944 targets = new_env.Command(exename, progname, 945 MakeAction(cmd, Transform("STRIP"))) 946 947 new_env.M5Binary = targets[0] 948 envList.append(new_env) 949 950# Debug binary 951ccflags = {} 952if env['GCC']: 953 if sys.platform == 'sunos5': 954 ccflags['debug'] = '-gstabs+' 955 else: 956 ccflags['debug'] = '-ggdb3' 957 ccflags['opt'] = '-g -O3' 958 ccflags['fast'] = '-O3' 959 ccflags['prof'] = '-O3 -g -pg' 960elif env['SUNCC']: 961 ccflags['debug'] = '-g0' 962 ccflags['opt'] = '-g -O' 963 ccflags['fast'] = '-fast' 964 ccflags['prof'] = '-fast -g -pg' 965elif env['ICC']: 966 ccflags['debug'] = '-g -O0' 967 ccflags['opt'] = '-g -O' 968 ccflags['fast'] = '-fast' 969 ccflags['prof'] = '-fast -g -pg' 970else: 971 print 'Unknown compiler, please fix compiler options' 972 Exit(1) 973 974makeEnv('debug', '.do', 975 CCFLAGS = Split(ccflags['debug']), 976 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 977 978# Optimized binary 979makeEnv('opt', '.o', 980 CCFLAGS = Split(ccflags['opt']), 981 CPPDEFINES = ['TRACING_ON=1']) 982 983# "Fast" binary 984makeEnv('fast', '.fo', strip = True, 985 CCFLAGS = Split(ccflags['fast']), 986 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 987 988# Profiled binary 989makeEnv('prof', '.po', 990 CCFLAGS = Split(ccflags['prof']), 991 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 992 LINKFLAGS = '-pg') 993 994Return('envList') 995