SConscript revision 6502
12567SN/A# -*- mode:python -*- 212525Sandreas.sandberg@arm.com 37585SAli.Saidi@arm.com# Copyright (c) 2004-2005 The Regents of The University of Michigan 47585SAli.Saidi@arm.com# All rights reserved. 57585SAli.Saidi@arm.com# 67585SAli.Saidi@arm.com# Redistribution and use in source and binary forms, with or without 77585SAli.Saidi@arm.com# modification, are permitted provided that the following conditions are 87585SAli.Saidi@arm.com# met: redistributions of source code must retain the above copyright 97585SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer; 107585SAli.Saidi@arm.com# redistributions in binary form must reproduce the above copyright 117585SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer in the 127585SAli.Saidi@arm.com# documentation and/or other materials provided with the distribution; 137585SAli.Saidi@arm.com# neither the name of the copyright holders nor the names of its 142567SN/A# contributors may be used to endorse or promote products derived from 152567SN/A# this software without specific prior written permission. 162567SN/A# 172567SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 182567SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 192567SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 202567SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 212567SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 222567SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 232567SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 242567SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 252567SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 262567SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 272567SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 282567SN/A# 292567SN/A# Authors: Nathan Binkert 302567SN/A 312567SN/Aimport array 322567SN/Aimport bisect 332567SN/Aimport imp 342567SN/Aimport marshal 352567SN/Aimport os 362567SN/Aimport re 372567SN/Aimport sys 382567SN/Aimport zlib 392665SN/A 402665SN/Afrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath 412567SN/A 422567SN/Aimport SCons 4311793Sbrandon.potter@amd.com 4411793Sbrandon.potter@amd.com# This file defines how to build a particular configuration of M5 458229Snate@binkert.org# based on variable settings in the 'env' build environment. 468229Snate@binkert.org 478286SAli.Saidi@ARM.comImport('*') 488286SAli.Saidi@ARM.com 498286SAli.Saidi@ARM.com# Children need to see the environment 5011793Sbrandon.potter@amd.comExport('env') 518286SAli.Saidi@ARM.com 5210037SARM gem5 Developersbuild_env = dict([(opt, env[opt]) for opt in export_vars]) 532567SN/A 547650SAli.Saidi@ARM.com######################################################################## 557650SAli.Saidi@ARM.com# Code for adding source files of various types 562567SN/A# 576757SAli.Saidi@ARM.comclass SourceMeta(type): 5811234Sandreas.sandberg@arm.com def __init__(cls, name, bases, dict): 5911234Sandreas.sandberg@arm.com super(SourceMeta, cls).__init__(name, bases, dict) 6011234Sandreas.sandberg@arm.com cls.all = [] 6110037SARM gem5 Developers 6210037SARM gem5 Developers def get(cls, **kwargs): 6310537Sandreas.hansson@arm.com for src in cls.all: 6410037SARM gem5 Developers for attr,value in kwargs.iteritems(): 6512525Sandreas.sandberg@arm.com if getattr(src, attr) != value: 6612525Sandreas.sandberg@arm.com break 6712525Sandreas.sandberg@arm.com else: 6810037SARM gem5 Developers yield src 6910037SARM gem5 Developers 7012005Sandreas.sandberg@arm.comclass SourceFile(object): 7112005Sandreas.sandberg@arm.com __metaclass__ = SourceMeta 7212005Sandreas.sandberg@arm.com def __init__(self, source): 7310037SARM gem5 Developers tnode = source 742567SN/A if not isinstance(source, SCons.Node.FS.File): 7510037SARM gem5 Developers tnode = File(source) 7610037SARM gem5 Developers 7710037SARM gem5 Developers self.tnode = tnode 7810037SARM gem5 Developers self.snode = tnode.srcnode() 7910037SARM gem5 Developers self.filename = str(tnode) 8010037SARM gem5 Developers self.dirname = dirname(self.filename) 8110037SARM gem5 Developers self.basename = basename(self.filename) 8210037SARM gem5 Developers index = self.basename.rfind('.') 8311234Sandreas.sandberg@arm.com if index <= 0: 8411234Sandreas.sandberg@arm.com # dot files aren't extensions 8511234Sandreas.sandberg@arm.com self.extname = self.basename, None 8611234Sandreas.sandberg@arm.com else: 878885SAli.Saidi@ARM.com self.extname = self.basename[:index], self.basename[index+1:] 8811234Sandreas.sandberg@arm.com 8911234Sandreas.sandberg@arm.com for base in type(self).__mro__: 9011234Sandreas.sandberg@arm.com if issubclass(base, SourceFile): 918885SAli.Saidi@ARM.com bisect.insort_right(base.all, self) 9211234Sandreas.sandberg@arm.com 9311234Sandreas.sandberg@arm.com def __lt__(self, other): return self.filename < other.filename 9411234Sandreas.sandberg@arm.com def __le__(self, other): return self.filename <= other.filename 9511234Sandreas.sandberg@arm.com def __gt__(self, other): return self.filename > other.filename 9611234Sandreas.sandberg@arm.com def __ge__(self, other): return self.filename >= other.filename 9711234Sandreas.sandberg@arm.com def __eq__(self, other): return self.filename == other.filename 9811234Sandreas.sandberg@arm.com def __ne__(self, other): return self.filename != other.filename 9911234Sandreas.sandberg@arm.com 10011234Sandreas.sandberg@arm.comclass Source(SourceFile): 10111234Sandreas.sandberg@arm.com '''Add a c/c++ source file to the build''' 10211234Sandreas.sandberg@arm.com def __init__(self, source, Werror=True, swig=False, bin_only=False, 10311234Sandreas.sandberg@arm.com skip_lib=False): 10410037SARM gem5 Developers super(Source, self).__init__(source) 10510037SARM gem5 Developers 10610037SARM gem5 Developers self.Werror = Werror 10710037SARM gem5 Developers self.swig = swig 10810037SARM gem5 Developers self.bin_only = bin_only 10910037SARM gem5 Developers self.skip_lib = bin_only or skip_lib 11010037SARM gem5 Developers 11110037SARM gem5 Developersclass PySource(SourceFile): 11210037SARM gem5 Developers '''Add a python source file to the named package''' 11311234Sandreas.sandberg@arm.com invalid_sym_char = re.compile('[^A-z0-9_]') 11410037SARM gem5 Developers modules = {} 1158885SAli.Saidi@ARM.com tnodes = {} 1168706Sandreas.hansson@arm.com symnames = {} 1178706Sandreas.hansson@arm.com 1188706Sandreas.hansson@arm.com def __init__(self, package, source): 1198706Sandreas.hansson@arm.com super(PySource, self).__init__(source) 1208706Sandreas.hansson@arm.com 1218706Sandreas.hansson@arm.com modname,ext = self.extname 1228706Sandreas.hansson@arm.com assert ext == 'py' 1238706Sandreas.hansson@arm.com 1248706Sandreas.hansson@arm.com if package: 1258706Sandreas.hansson@arm.com path = package.split('.') 1268706Sandreas.hansson@arm.com else: 1278706Sandreas.hansson@arm.com path = [] 1282567SN/A 1298885SAli.Saidi@ARM.com modpath = path[:] 1308706Sandreas.hansson@arm.com if modname != '__init__': 1318286SAli.Saidi@ARM.com modpath += [ modname ] 13210037SARM gem5 Developers modpath = '.'.join(modpath) 1338286SAli.Saidi@ARM.com 13410037SARM gem5 Developers arcpath = path + [ self.basename ] 1358286SAli.Saidi@ARM.com debugname = self.snode.abspath 13610037SARM gem5 Developers if not exists(debugname): 13710037SARM gem5 Developers debugname = self.tnode.abspath 13810037SARM gem5 Developers 13910037SARM gem5 Developers self.package = package 14010037SARM gem5 Developers self.modname = modname 14110037SARM gem5 Developers self.modpath = modpath 14210037SARM gem5 Developers self.arcname = joinpath(*arcpath) 14310037SARM gem5 Developers self.debugname = debugname 14410037SARM gem5 Developers self.compiled = File(self.filename + 'c') 14510037SARM gem5 Developers self.assembly = File(self.filename + '.s') 14610037SARM gem5 Developers self.symname = "PyEMB_" + PySource.invalid_sym_char.sub('_', modpath) 1478286SAli.Saidi@ARM.com 1488286SAli.Saidi@ARM.com PySource.modules[modpath] = self 1498286SAli.Saidi@ARM.com PySource.tnodes[self.tnode] = self 1508286SAli.Saidi@ARM.com PySource.symnames[self.symname] = self 1518286SAli.Saidi@ARM.com 1528286SAli.Saidi@ARM.comclass SimObject(PySource): 1538885SAli.Saidi@ARM.com '''Add a SimObject python file as a python source object and add 1548885SAli.Saidi@ARM.com it to a list of sim object modules''' 1558885SAli.Saidi@ARM.com 1568286SAli.Saidi@ARM.com fixed = False 15710037SARM gem5 Developers modnames = [] 15810037SARM gem5 Developers 15910037SARM gem5 Developers def __init__(self, source): 1608286SAli.Saidi@ARM.com super(SimObject, self).__init__('m5.objects', source) 1618286SAli.Saidi@ARM.com if self.fixed: 1628286SAli.Saidi@ARM.com raise AttributeError, "Too late to call SimObject now." 1638286SAli.Saidi@ARM.com 16410037SARM gem5 Developers bisect.insort_right(SimObject.modnames, self.modname) 16510037SARM gem5 Developers 1668286SAli.Saidi@ARM.comclass SwigSource(SourceFile): 1678286SAli.Saidi@ARM.com '''Add a swig file to build''' 16810037SARM gem5 Developers 16910037SARM gem5 Developers def __init__(self, package, source): 17010037SARM gem5 Developers super(SwigSource, self).__init__(source) 1718286SAli.Saidi@ARM.com 1722567SN/A modname,ext = self.extname 1732567SN/A assert ext == 'i' 17412317Sgiacomo.travaglini@arm.com 17512317Sgiacomo.travaglini@arm.com self.module = modname 17612317Sgiacomo.travaglini@arm.com cc_file = joinpath(self.dirname, modname + '_wrap.cc') 17712317Sgiacomo.travaglini@arm.com py_file = joinpath(self.dirname, modname + '.py') 17812317Sgiacomo.travaglini@arm.com 17912317Sgiacomo.travaglini@arm.com self.cc_source = Source(cc_file, swig=True) 18012317Sgiacomo.travaglini@arm.com self.py_source = PySource(package, py_file) 18112317Sgiacomo.travaglini@arm.com 18210037SARM gem5 Developersunit_tests = [] 18310037SARM gem5 Developersdef UnitTest(target, sources): 18410037SARM gem5 Developers if not isinstance(sources, (list, tuple)): 18512317Sgiacomo.travaglini@arm.com sources = [ sources ] 18610037SARM gem5 Developers 18710037SARM gem5 Developers sources = [ Source(src, skip_lib=True) for src in sources ] 18810037SARM gem5 Developers unit_tests.append((target, sources)) 1896757SAli.Saidi@ARM.com 1902567SN/A# Children should have access 1918286SAli.Saidi@ARM.comExport('Source') 1928286SAli.Saidi@ARM.comExport('PySource') 1932567SN/AExport('SimObject') 1942567SN/AExport('SwigSource') 19511234Sandreas.sandberg@arm.comExport('UnitTest') 19611234Sandreas.sandberg@arm.com 19711234Sandreas.sandberg@arm.com######################################################################## 19811234Sandreas.sandberg@arm.com# 19911234Sandreas.sandberg@arm.com# Trace Flags 20011234Sandreas.sandberg@arm.com# 20111234Sandreas.sandberg@arm.comtrace_flags = {} 20211234Sandreas.sandberg@arm.comdef TraceFlag(name, desc=None): 20311234Sandreas.sandberg@arm.com if name in trace_flags: 20411234Sandreas.sandberg@arm.com raise AttributeError, "Flag %s already specified" % name 20511234Sandreas.sandberg@arm.com trace_flags[name] = (name, (), desc) 20610037SARM gem5 Developers 20710037SARM gem5 Developersdef CompoundFlag(name, flags, desc=None): 20810037SARM gem5 Developers if name in trace_flags: 20912317Sgiacomo.travaglini@arm.com raise AttributeError, "Flag %s already specified" % name 21010037SARM gem5 Developers 21110037SARM gem5 Developers compound = tuple(flags) 21210037SARM gem5 Developers trace_flags[name] = (name, compound, desc) 21310037SARM gem5 Developers 21410037SARM gem5 DevelopersExport('TraceFlag') 21512317Sgiacomo.travaglini@arm.comExport('CompoundFlag') 21610037SARM gem5 Developers 21710037SARM gem5 Developers######################################################################## 21810037SARM gem5 Developers# 21910037SARM gem5 Developers# Set some compiler variables 22010037SARM gem5 Developers# 22112317Sgiacomo.travaglini@arm.com 22210037SARM gem5 Developers# Include file paths are rooted in this directory. SCons will 22310037SARM gem5 Developers# automatically expand '.' to refer to both the source directory and 22410037SARM gem5 Developers# the corresponding build directory to pick up generated include 22510037SARM gem5 Developers# files. 22610037SARM gem5 Developersenv.Append(CPPPATH=Dir('.')) 22712317Sgiacomo.travaglini@arm.com 22810037SARM gem5 Developersfor extra_dir in extras_dir_list: 22910037SARM gem5 Developers env.Append(CPPPATH=Dir(extra_dir)) 23012318Sgiacomo.travaglini@arm.com 23112318Sgiacomo.travaglini@arm.com# Add a flag defining what THE_ISA should be for all compilation 23212318Sgiacomo.travaglini@arm.comenv.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) 23312318Sgiacomo.travaglini@arm.com 23412318Sgiacomo.travaglini@arm.com# Workaround for bug in SCons version > 0.97d20071212 23512318Sgiacomo.travaglini@arm.com# Scons bug id: 2006 M5 Bug id: 308 23612318Sgiacomo.travaglini@arm.comfor root, dirs, files in os.walk(base_dir, topdown=True): 23712318Sgiacomo.travaglini@arm.com Dir(root[len(base_dir) + 1:]) 23812318Sgiacomo.travaglini@arm.com 23912318Sgiacomo.travaglini@arm.com######################################################################## 24012318Sgiacomo.travaglini@arm.com# 24112318Sgiacomo.travaglini@arm.com# Walk the tree and execute all SConscripts in subdirectories 24212318Sgiacomo.travaglini@arm.com# 24312318Sgiacomo.travaglini@arm.com 24412318Sgiacomo.travaglini@arm.comhere = Dir('.').srcnode().abspath 24512318Sgiacomo.travaglini@arm.comfor root, dirs, files in os.walk(base_dir, topdown=True): 24612318Sgiacomo.travaglini@arm.com if root == here: 24710037SARM gem5 Developers # we don't want to recurse back into this SConscript 24810037SARM gem5 Developers continue 24910037SARM gem5 Developers 25012317Sgiacomo.travaglini@arm.com if 'SConscript' in files: 25110037SARM gem5 Developers build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 25210037SARM gem5 Developers SConscript(joinpath(root, 'SConscript'), build_dir=build_dir) 25310037SARM gem5 Developers 25410037SARM gem5 Developersfor extra_dir in extras_dir_list: 25510037SARM gem5 Developers prefix_len = len(dirname(extra_dir)) + 1 25612317Sgiacomo.travaglini@arm.com for root, dirs, files in os.walk(extra_dir, topdown=True): 25710037SARM gem5 Developers if 'SConscript' in files: 25810037SARM gem5 Developers build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 25910037SARM gem5 Developers SConscript(joinpath(root, 'SConscript'), build_dir=build_dir) 26010037SARM gem5 Developers 26110037SARM gem5 Developersfor opt in export_vars: 26212317Sgiacomo.travaglini@arm.com env.ConfigFile(opt) 26310037SARM gem5 Developers 26410037SARM gem5 Developers######################################################################## 26510037SARM gem5 Developers# 26610037SARM gem5 Developers# Prevent any SimObjects from being added after this point, they 26710037SARM gem5 Developers# should all have been added in the SConscripts above 26812317Sgiacomo.travaglini@arm.com# 26910037SARM gem5 Developersclass DictImporter(object): 27010810Sbr@bsdpad.com '''This importer takes a dictionary of arbitrary module names that 2716757SAli.Saidi@ARM.com map to arbitrary filenames.''' 2726757SAli.Saidi@ARM.com def __init__(self, modules): 2732567SN/A self.modules = modules 2746757SAli.Saidi@ARM.com self.installed = set() 2752567SN/A 27610810Sbr@bsdpad.com def __del__(self): 27710810Sbr@bsdpad.com self.unload() 27810810Sbr@bsdpad.com 27910810Sbr@bsdpad.com def unload(self): 28010810Sbr@bsdpad.com import sys 28110810Sbr@bsdpad.com for module in self.installed: 28210810Sbr@bsdpad.com del sys.modules[module] 28310810Sbr@bsdpad.com self.installed = set() 28410810Sbr@bsdpad.com 28510810Sbr@bsdpad.com def find_module(self, fullname, path): 28610810Sbr@bsdpad.com if fullname == 'defines': 28710810Sbr@bsdpad.com return self 28810810Sbr@bsdpad.com 28910810Sbr@bsdpad.com if fullname == 'm5.objects': 29010810Sbr@bsdpad.com return self 29110810Sbr@bsdpad.com 29210810Sbr@bsdpad.com if fullname.startswith('m5.internal'): 293 return None 294 295 source = self.modules.get(fullname, None) 296 if source is not None and exists(source.snode.abspath): 297 return self 298 299 return None 300 301 def load_module(self, fullname): 302 mod = imp.new_module(fullname) 303 sys.modules[fullname] = mod 304 self.installed.add(fullname) 305 306 mod.__loader__ = self 307 if fullname == 'm5.objects': 308 mod.__path__ = fullname.split('.') 309 return mod 310 311 if fullname == 'defines': 312 mod.__dict__['buildEnv'] = build_env 313 return mod 314 315 source = self.modules[fullname] 316 if source.modname == '__init__': 317 mod.__path__ = source.modpath 318 mod.__file__ = source.snode.abspath 319 320 exec file(source.snode.abspath, 'r') in mod.__dict__ 321 322 return mod 323 324# install the python importer so we can grab stuff from the source 325# tree itself. We can't have SimObjects added after this point or 326# else we won't know about them for the rest of the stuff. 327SimObject.fixed = True 328importer = DictImporter(PySource.modules) 329sys.meta_path[0:0] = [ importer ] 330 331import m5 332 333# import all sim objects so we can populate the all_objects list 334# make sure that we're working with a list, then let's sort it 335for modname in SimObject.modnames: 336 exec('from m5.objects import %s' % modname) 337 338# we need to unload all of the currently imported modules so that they 339# will be re-imported the next time the sconscript is run 340importer.unload() 341sys.meta_path.remove(importer) 342 343sim_objects = m5.SimObject.allClasses 344all_enums = m5.params.allEnums 345 346all_params = {} 347for name,obj in sorted(sim_objects.iteritems()): 348 for param in obj._params.local.values(): 349 if not hasattr(param, 'swig_decl'): 350 continue 351 pname = param.ptype_str 352 if pname not in all_params: 353 all_params[pname] = param 354 355######################################################################## 356# 357# calculate extra dependencies 358# 359module_depends = ["m5", "m5.SimObject", "m5.params"] 360depends = [ PySource.modules[dep].tnode for dep in module_depends ] 361 362######################################################################## 363# 364# Commands for the basic automatically generated python files 365# 366 367# Generate Python file containing a dict specifying the current 368# build_env flags. 369def makeDefinesPyFile(target, source, env): 370 f = file(str(target[0]), 'w') 371 build_env, hg_info = [ x.get_contents() for x in source ] 372 print >>f, "buildEnv = %s" % build_env 373 print >>f, "hgRev = '%s'" % hg_info 374 f.close() 375 376defines_info = [ Value(build_env), Value(env['HG_INFO']) ] 377# Generate a file with all of the compile options in it 378env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile) 379PySource('m5', 'python/m5/defines.py') 380 381# Generate python file containing info about the M5 source code 382def makeInfoPyFile(target, source, env): 383 f = file(str(target[0]), 'w') 384 for src in source: 385 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 386 print >>f, "%s = %s" % (src, repr(data)) 387 f.close() 388 389# Generate a file that wraps the basic top level files 390env.Command('python/m5/info.py', 391 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], 392 makeInfoPyFile) 393PySource('m5', 'python/m5/info.py') 394 395# Generate the __init__.py file for m5.objects 396def makeObjectsInitFile(target, source, env): 397 f = file(str(target[0]), 'w') 398 print >>f, 'from params import *' 399 print >>f, 'from m5.SimObject import *' 400 for module in source: 401 print >>f, 'from %s import *' % module.get_contents() 402 f.close() 403 404# Generate an __init__.py file for the objects package 405env.Command('python/m5/objects/__init__.py', 406 map(Value, SimObject.modnames), 407 makeObjectsInitFile) 408PySource('m5.objects', 'python/m5/objects/__init__.py') 409 410######################################################################## 411# 412# Create all of the SimObject param headers and enum headers 413# 414 415def createSimObjectParam(target, source, env): 416 assert len(target) == 1 and len(source) == 1 417 418 hh_file = file(target[0].abspath, 'w') 419 name = str(source[0].get_contents()) 420 obj = sim_objects[name] 421 422 print >>hh_file, obj.cxx_decl() 423 hh_file.close() 424 425def createSwigParam(target, source, env): 426 assert len(target) == 1 and len(source) == 1 427 428 i_file = file(target[0].abspath, 'w') 429 name = str(source[0].get_contents()) 430 param = all_params[name] 431 432 for line in param.swig_decl(): 433 print >>i_file, line 434 i_file.close() 435 436def createEnumStrings(target, source, env): 437 assert len(target) == 1 and len(source) == 1 438 439 cc_file = file(target[0].abspath, 'w') 440 name = str(source[0].get_contents()) 441 obj = all_enums[name] 442 443 print >>cc_file, obj.cxx_def() 444 cc_file.close() 445 446def createEnumParam(target, source, env): 447 assert len(target) == 1 and len(source) == 1 448 449 hh_file = file(target[0].abspath, 'w') 450 name = str(source[0].get_contents()) 451 obj = all_enums[name] 452 453 print >>hh_file, obj.cxx_decl() 454 hh_file.close() 455 456# Generate all of the SimObject param struct header files 457params_hh_files = [] 458for name,simobj in sorted(sim_objects.iteritems()): 459 py_source = PySource.modules[simobj.__module__] 460 extra_deps = [ py_source.tnode ] 461 462 hh_file = File('params/%s.hh' % name) 463 params_hh_files.append(hh_file) 464 env.Command(hh_file, Value(name), createSimObjectParam) 465 env.Depends(hh_file, depends + extra_deps) 466 467# Generate any parameter header files needed 468params_i_files = [] 469for name,param in all_params.iteritems(): 470 if isinstance(param, m5.params.VectorParamDesc): 471 ext = 'vptype' 472 else: 473 ext = 'ptype' 474 475 i_file = File('params/%s_%s.i' % (name, ext)) 476 params_i_files.append(i_file) 477 env.Command(i_file, Value(name), createSwigParam) 478 env.Depends(i_file, depends) 479 480# Generate all enum header files 481for name,enum in sorted(all_enums.iteritems()): 482 py_source = PySource.modules[enum.__module__] 483 extra_deps = [ py_source.tnode ] 484 485 cc_file = File('enums/%s.cc' % name) 486 env.Command(cc_file, Value(name), createEnumStrings) 487 env.Depends(cc_file, depends + extra_deps) 488 Source(cc_file) 489 490 hh_file = File('enums/%s.hh' % name) 491 env.Command(hh_file, Value(name), createEnumParam) 492 env.Depends(hh_file, depends + extra_deps) 493 494# Build the big monolithic swigged params module (wraps all SimObject 495# param structs and enum structs) 496def buildParams(target, source, env): 497 names = [ s.get_contents() for s in source ] 498 objs = [ sim_objects[name] for name in names ] 499 out = file(target[0].abspath, 'w') 500 501 ordered_objs = [] 502 obj_seen = set() 503 def order_obj(obj): 504 name = str(obj) 505 if name in obj_seen: 506 return 507 508 obj_seen.add(name) 509 if str(obj) != 'SimObject': 510 order_obj(obj.__bases__[0]) 511 512 ordered_objs.append(obj) 513 514 for obj in objs: 515 order_obj(obj) 516 517 enums = set() 518 predecls = [] 519 pd_seen = set() 520 521 def add_pds(*pds): 522 for pd in pds: 523 if pd not in pd_seen: 524 predecls.append(pd) 525 pd_seen.add(pd) 526 527 for obj in ordered_objs: 528 params = obj._params.local.values() 529 for param in params: 530 ptype = param.ptype 531 if issubclass(ptype, m5.params.Enum): 532 if ptype not in enums: 533 enums.add(ptype) 534 pds = param.swig_predecls() 535 if isinstance(pds, (list, tuple)): 536 add_pds(*pds) 537 else: 538 add_pds(pds) 539 540 print >>out, '%module params' 541 542 print >>out, '%{' 543 for obj in ordered_objs: 544 print >>out, '#include "params/%s.hh"' % obj 545 print >>out, '%}' 546 547 for pd in predecls: 548 print >>out, pd 549 550 enums = list(enums) 551 enums.sort() 552 for enum in enums: 553 print >>out, '%%include "enums/%s.hh"' % enum.__name__ 554 print >>out 555 556 for obj in ordered_objs: 557 if obj.swig_objdecls: 558 for decl in obj.swig_objdecls: 559 print >>out, decl 560 continue 561 562 class_path = obj.cxx_class.split('::') 563 classname = class_path[-1] 564 namespaces = class_path[:-1] 565 namespaces.reverse() 566 567 code = '' 568 569 if namespaces: 570 code += '// avoid name conflicts\n' 571 sep_string = '_COLONS_' 572 flat_name = sep_string.join(class_path) 573 code += '%%rename(%s) %s;\n' % (flat_name, classname) 574 575 code += '// stop swig from creating/wrapping default ctor/dtor\n' 576 code += '%%nodefault %s;\n' % classname 577 code += 'class %s ' % classname 578 if obj._base: 579 code += ': public %s' % obj._base.cxx_class 580 code += ' {};\n' 581 582 for ns in namespaces: 583 new_code = 'namespace %s {\n' % ns 584 new_code += code 585 new_code += '}\n' 586 code = new_code 587 588 print >>out, code 589 590 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj 591 for obj in ordered_objs: 592 print >>out, '%%include "params/%s.hh"' % obj 593 594params_file = File('params/params.i') 595names = sorted(sim_objects.keys()) 596env.Command(params_file, map(Value, names), buildParams) 597env.Depends(params_file, params_hh_files + params_i_files + depends) 598SwigSource('m5.objects', params_file) 599 600# Build all swig modules 601for swig in SwigSource.all: 602 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 603 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 604 '-o ${TARGETS[0]} $SOURCES') 605 env.Depends(swig.py_source.tnode, swig.tnode) 606 env.Depends(swig.cc_source.tnode, swig.tnode) 607 608# Generate the main swig init file 609def makeSwigInit(target, source, env): 610 f = file(str(target[0]), 'w') 611 print >>f, 'extern "C" {' 612 for module in source: 613 print >>f, ' void init_%s();' % module.get_contents() 614 print >>f, '}' 615 print >>f, 'void initSwig() {' 616 for module in source: 617 print >>f, ' init_%s();' % module.get_contents() 618 print >>f, '}' 619 f.close() 620 621env.Command('python/swig/init.cc', 622 map(Value, sorted(s.module for s in SwigSource.all)), 623 makeSwigInit) 624Source('python/swig/init.cc') 625 626def getFlags(source_flags): 627 flagsMap = {} 628 flagsList = [] 629 for s in source_flags: 630 val = eval(s.get_contents()) 631 name, compound, desc = val 632 flagsList.append(val) 633 flagsMap[name] = bool(compound) 634 635 for name, compound, desc in flagsList: 636 for flag in compound: 637 if flag not in flagsMap: 638 raise AttributeError, "Trace flag %s not found" % flag 639 if flagsMap[flag]: 640 raise AttributeError, \ 641 "Compound flag can't point to another compound flag" 642 643 flagsList.sort() 644 return flagsList 645 646 647# Generate traceflags.py 648def traceFlagsPy(target, source, env): 649 assert(len(target) == 1) 650 651 f = file(str(target[0]), 'w') 652 653 allFlags = getFlags(source) 654 655 print >>f, 'basic = [' 656 for flag, compound, desc in allFlags: 657 if not compound: 658 print >>f, " '%s'," % flag 659 print >>f, " ]" 660 print >>f 661 662 print >>f, 'compound = [' 663 print >>f, " 'All'," 664 for flag, compound, desc in allFlags: 665 if compound: 666 print >>f, " '%s'," % flag 667 print >>f, " ]" 668 print >>f 669 670 print >>f, "all = frozenset(basic + compound)" 671 print >>f 672 673 print >>f, 'compoundMap = {' 674 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 675 print >>f, " 'All' : %s," % (all, ) 676 for flag, compound, desc in allFlags: 677 if compound: 678 print >>f, " '%s' : %s," % (flag, compound) 679 print >>f, " }" 680 print >>f 681 682 print >>f, 'descriptions = {' 683 print >>f, " 'All' : 'All flags'," 684 for flag, compound, desc in allFlags: 685 print >>f, " '%s' : '%s'," % (flag, desc) 686 print >>f, " }" 687 688 f.close() 689 690def traceFlagsCC(target, source, env): 691 assert(len(target) == 1) 692 693 f = file(str(target[0]), 'w') 694 695 allFlags = getFlags(source) 696 697 # file header 698 print >>f, ''' 699/* 700 * DO NOT EDIT THIS FILE! Automatically generated 701 */ 702 703#include "base/traceflags.hh" 704 705using namespace Trace; 706 707const char *Trace::flagStrings[] = 708{''' 709 710 # The string array is used by SimpleEnumParam to map the strings 711 # provided by the user to enum values. 712 for flag, compound, desc in allFlags: 713 if not compound: 714 print >>f, ' "%s",' % flag 715 716 print >>f, ' "All",' 717 for flag, compound, desc in allFlags: 718 if compound: 719 print >>f, ' "%s",' % flag 720 721 print >>f, '};' 722 print >>f 723 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1) 724 print >>f 725 726 # 727 # Now define the individual compound flag arrays. There is an array 728 # for each compound flag listing the component base flags. 729 # 730 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 731 print >>f, 'static const Flags AllMap[] = {' 732 for flag, compound, desc in allFlags: 733 if not compound: 734 print >>f, " %s," % flag 735 print >>f, '};' 736 print >>f 737 738 for flag, compound, desc in allFlags: 739 if not compound: 740 continue 741 print >>f, 'static const Flags %sMap[] = {' % flag 742 for flag in compound: 743 print >>f, " %s," % flag 744 print >>f, " (Flags)-1" 745 print >>f, '};' 746 print >>f 747 748 # 749 # Finally the compoundFlags[] array maps the compound flags 750 # to their individual arrays/ 751 # 752 print >>f, 'const Flags *Trace::compoundFlags[] =' 753 print >>f, '{' 754 print >>f, ' AllMap,' 755 for flag, compound, desc in allFlags: 756 if compound: 757 print >>f, ' %sMap,' % flag 758 # file trailer 759 print >>f, '};' 760 761 f.close() 762 763def traceFlagsHH(target, source, env): 764 assert(len(target) == 1) 765 766 f = file(str(target[0]), 'w') 767 768 allFlags = getFlags(source) 769 770 # file header boilerplate 771 print >>f, ''' 772/* 773 * DO NOT EDIT THIS FILE! 774 * 775 * Automatically generated from traceflags.py 776 */ 777 778#ifndef __BASE_TRACE_FLAGS_HH__ 779#define __BASE_TRACE_FLAGS_HH__ 780 781namespace Trace { 782 783enum Flags {''' 784 785 # Generate the enum. Base flags come first, then compound flags. 786 idx = 0 787 for flag, compound, desc in allFlags: 788 if not compound: 789 print >>f, ' %s = %d,' % (flag, idx) 790 idx += 1 791 792 numBaseFlags = idx 793 print >>f, ' NumFlags = %d,' % idx 794 795 # put a comment in here to separate base from compound flags 796 print >>f, ''' 797// The remaining enum values are *not* valid indices for Trace::flags. 798// They are "compound" flags, which correspond to sets of base 799// flags, and are used by changeFlag.''' 800 801 print >>f, ' All = %d,' % idx 802 idx += 1 803 for flag, compound, desc in allFlags: 804 if compound: 805 print >>f, ' %s = %d,' % (flag, idx) 806 idx += 1 807 808 numCompoundFlags = idx - numBaseFlags 809 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags 810 811 # trailer boilerplate 812 print >>f, '''\ 813}; // enum Flags 814 815// Array of strings for SimpleEnumParam 816extern const char *flagStrings[]; 817extern const int numFlagStrings; 818 819// Array of arraay pointers: for each compound flag, gives the list of 820// base flags to set. Inidividual flag arrays are terminated by -1. 821extern const Flags *compoundFlags[]; 822 823/* namespace Trace */ } 824 825#endif // __BASE_TRACE_FLAGS_HH__ 826''' 827 828 f.close() 829 830flags = map(Value, trace_flags.values()) 831env.Command('base/traceflags.py', flags, traceFlagsPy) 832PySource('m5', 'base/traceflags.py') 833 834env.Command('base/traceflags.hh', flags, traceFlagsHH) 835env.Command('base/traceflags.cc', flags, traceFlagsCC) 836Source('base/traceflags.cc') 837 838# embed python files. All .py files that have been indicated by a 839# PySource() call in a SConscript need to be embedded into the M5 840# library. To do that, we compile the file to byte code, marshal the 841# byte code, compress it, and then generate an assembly file that 842# inserts the result into the data section with symbols indicating the 843# beginning, and end (and with the size at the end) 844def objectifyPyFile(target, source, env): 845 '''Action function to compile a .py into a code object, marshal 846 it, compress it, and stick it into an asm file so the code appears 847 as just bytes with a label in the data section''' 848 849 src = file(str(source[0]), 'r').read() 850 dst = file(str(target[0]), 'w') 851 852 pysource = PySource.tnodes[source[0]] 853 compiled = compile(src, pysource.debugname, 'exec') 854 marshalled = marshal.dumps(compiled) 855 compressed = zlib.compress(marshalled) 856 data = compressed 857 858 # Some C/C++ compilers prepend an underscore to global symbol 859 # names, so if they're going to do that, we need to prepend that 860 # leading underscore to globals in the assembly file. 861 if env['LEADING_UNDERSCORE']: 862 sym = '_' + pysource.symname 863 else: 864 sym = pysource.symname 865 866 step = 16 867 print >>dst, ".data" 868 print >>dst, ".globl %s_beg" % sym 869 print >>dst, ".globl %s_end" % sym 870 print >>dst, "%s_beg:" % sym 871 for i in xrange(0, len(data), step): 872 x = array.array('B', data[i:i+step]) 873 print >>dst, ".byte", ','.join([str(d) for d in x]) 874 print >>dst, "%s_end:" % sym 875 print >>dst, ".long %d" % len(marshalled) 876 877for source in PySource.all: 878 env.Command(source.assembly, source.tnode, objectifyPyFile) 879 Source(source.assembly) 880 881# Generate init_python.cc which creates a bunch of EmbeddedPyModule 882# structs that describe the embedded python code. One such struct 883# contains information about the importer that python uses to get at 884# the embedded files, and then there's a list of all of the rest that 885# the importer uses to load the rest on demand. 886def pythonInit(target, source, env): 887 dst = file(str(target[0]), 'w') 888 889 def dump_mod(sym, endchar=','): 890 pysource = PySource.symnames[sym] 891 print >>dst, ' { "%s",' % pysource.arcname 892 print >>dst, ' "%s",' % pysource.modpath 893 print >>dst, ' %s_beg, %s_end,' % (sym, sym) 894 print >>dst, ' %s_end - %s_beg,' % (sym, sym) 895 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar) 896 897 print >>dst, '#include "sim/init.hh"' 898 899 for sym in source: 900 sym = sym.get_contents() 901 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym) 902 903 print >>dst, "const EmbeddedPyModule embeddedPyImporter = " 904 dump_mod("PyEMB_importer", endchar=';'); 905 print >>dst 906 907 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {" 908 for i,sym in enumerate(source): 909 sym = sym.get_contents() 910 if sym == "PyEMB_importer": 911 # Skip the importer since we've already exported it 912 continue 913 dump_mod(sym) 914 print >>dst, " { 0, 0, 0, 0, 0, 0 }" 915 print >>dst, "};" 916 917 918env.Command('sim/init_python.cc', 919 map(Value, (s.symname for s in PySource.all)), 920 pythonInit) 921Source('sim/init_python.cc') 922 923######################################################################## 924# 925# Define binaries. Each different build type (debug, opt, etc.) gets 926# a slightly different build environment. 927# 928 929# List of constructed environments to pass back to SConstruct 930envList = [] 931 932date_source = Source('base/date.cc', skip_lib=True) 933 934# Function to create a new build environment as clone of current 935# environment 'env' with modified object suffix and optional stripped 936# binary. Additional keyword arguments are appended to corresponding 937# build environment vars. 938def makeEnv(label, objsfx, strip = False, **kwargs): 939 # SCons doesn't know to append a library suffix when there is a '.' in the 940 # name. Use '_' instead. 941 libname = 'm5_' + label 942 exename = 'm5.' + label 943 944 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 945 new_env.Label = label 946 new_env.Append(**kwargs) 947 948 swig_env = new_env.Clone() 949 swig_env.Append(CCFLAGS='-Werror') 950 if env['GCC']: 951 swig_env.Append(CCFLAGS='-Wno-uninitialized') 952 swig_env.Append(CCFLAGS='-Wno-sign-compare') 953 swig_env.Append(CCFLAGS='-Wno-parentheses') 954 955 werror_env = new_env.Clone() 956 werror_env.Append(CCFLAGS='-Werror') 957 958 def make_obj(source, static, extra_deps = None): 959 '''This function adds the specified source to the correct 960 build environment, and returns the corresponding SCons Object 961 nodes''' 962 963 if source.swig: 964 env = swig_env 965 elif source.Werror: 966 env = werror_env 967 else: 968 env = new_env 969 970 if static: 971 obj = env.StaticObject(source.tnode) 972 else: 973 obj = env.SharedObject(source.tnode) 974 975 if extra_deps: 976 env.Depends(obj, extra_deps) 977 978 return obj 979 980 static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)] 981 shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)] 982 983 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 984 static_objs.append(static_date) 985 986 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 987 shared_objs.append(shared_date) 988 989 # First make a library of everything but main() so other programs can 990 # link against m5. 991 static_lib = new_env.StaticLibrary(libname, static_objs) 992 shared_lib = new_env.SharedLibrary(libname, shared_objs) 993 994 for target, sources in unit_tests: 995 objs = [ make_obj(s, static=True) for s in sources ] 996 new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs) 997 998 # Now link a stub with main() and the static library. 999 bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ] 1000 progname = exename 1001 if strip: 1002 progname += '.unstripped' 1003 1004 targets = new_env.Program(progname, bin_objs + static_objs) 1005 1006 if strip: 1007 if sys.platform == 'sunos5': 1008 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 1009 else: 1010 cmd = 'strip $SOURCE -o $TARGET' 1011 targets = new_env.Command(exename, progname, cmd) 1012 1013 new_env.M5Binary = targets[0] 1014 envList.append(new_env) 1015 1016# Debug binary 1017ccflags = {} 1018if env['GCC']: 1019 if sys.platform == 'sunos5': 1020 ccflags['debug'] = '-gstabs+' 1021 else: 1022 ccflags['debug'] = '-ggdb3' 1023 ccflags['opt'] = '-g -O3' 1024 ccflags['fast'] = '-O3' 1025 ccflags['prof'] = '-O3 -g -pg' 1026elif env['SUNCC']: 1027 ccflags['debug'] = '-g0' 1028 ccflags['opt'] = '-g -O' 1029 ccflags['fast'] = '-fast' 1030 ccflags['prof'] = '-fast -g -pg' 1031elif env['ICC']: 1032 ccflags['debug'] = '-g -O0' 1033 ccflags['opt'] = '-g -O' 1034 ccflags['fast'] = '-fast' 1035 ccflags['prof'] = '-fast -g -pg' 1036else: 1037 print 'Unknown compiler, please fix compiler options' 1038 Exit(1) 1039 1040makeEnv('debug', '.do', 1041 CCFLAGS = Split(ccflags['debug']), 1042 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 1043 1044# Optimized binary 1045makeEnv('opt', '.o', 1046 CCFLAGS = Split(ccflags['opt']), 1047 CPPDEFINES = ['TRACING_ON=1']) 1048 1049# "Fast" binary 1050makeEnv('fast', '.fo', strip = True, 1051 CCFLAGS = Split(ccflags['fast']), 1052 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 1053 1054# Profiled binary 1055makeEnv('prof', '.po', 1056 CCFLAGS = Split(ccflags['prof']), 1057 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1058 LINKFLAGS = '-pg') 1059 1060Return('envList') 1061