SConscript revision 8105
16157Snate@binkert.org# -*- mode:python -*- 26157Snate@binkert.org 36157Snate@binkert.org# Copyright (c) 2004-2005 The Regents of The University of Michigan 46157Snate@binkert.org# All rights reserved. 56157Snate@binkert.org# 66157Snate@binkert.org# Redistribution and use in source and binary forms, with or without 76157Snate@binkert.org# modification, are permitted provided that the following conditions are 86157Snate@binkert.org# met: redistributions of source code must retain the above copyright 96157Snate@binkert.org# notice, this list of conditions and the following disclaimer; 106157Snate@binkert.org# redistributions in binary form must reproduce the above copyright 116157Snate@binkert.org# notice, this list of conditions and the following disclaimer in the 126157Snate@binkert.org# documentation and/or other materials provided with the distribution; 136157Snate@binkert.org# neither the name of the copyright holders nor the names of its 146157Snate@binkert.org# contributors may be used to endorse or promote products derived from 156157Snate@binkert.org# this software without specific prior written permission. 166157Snate@binkert.org# 176157Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 186157Snate@binkert.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 196157Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 206157Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 216157Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 226157Snate@binkert.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 236157Snate@binkert.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 246157Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 256157Snate@binkert.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 266157Snate@binkert.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 276157Snate@binkert.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 286157Snate@binkert.org# 296157Snate@binkert.org# Authors: Nathan Binkert 306157Snate@binkert.org 316157Snate@binkert.orgimport array 326157Snate@binkert.orgimport bisect 336157Snate@binkert.orgimport imp 346157Snate@binkert.orgimport marshal 356157Snate@binkert.orgimport os 366157Snate@binkert.orgimport re 376157Snate@binkert.orgimport sys 386157Snate@binkert.orgimport zlib 396157Snate@binkert.org 407768SAli.Saidi@ARM.comfrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath 417768SAli.Saidi@ARM.com 427768SAli.Saidi@ARM.comimport SCons 436168Snate@binkert.org 446168Snate@binkert.org# This file defines how to build a particular configuration of M5 456168Snate@binkert.org# based on variable settings in the 'env' build environment. 466157Snate@binkert.org 476157Snate@binkert.orgImport('*') 486157Snate@binkert.org 496157Snate@binkert.org# Children need to see the environment 506157Snate@binkert.orgExport('env') 516157Snate@binkert.org 526157Snate@binkert.orgbuild_env = [(opt, env[opt]) for opt in export_vars] 536157Snate@binkert.org 546157Snate@binkert.orgfrom m5.util import code_formatter 556157Snate@binkert.org 566157Snate@binkert.org######################################################################## 576157Snate@binkert.org# Code for adding source files of various types 586157Snate@binkert.org# 596157Snate@binkert.orgclass SourceMeta(type): 606157Snate@binkert.org def __init__(cls, name, bases, dict): 616157Snate@binkert.org super(SourceMeta, cls).__init__(name, bases, dict) 626157Snate@binkert.org cls.all = [] 636157Snate@binkert.org 646157Snate@binkert.org def get(cls, **kwargs): 656157Snate@binkert.org for src in cls.all: 666157Snate@binkert.org for attr,value in kwargs.iteritems(): 676157Snate@binkert.org if getattr(src, attr) != value: 686157Snate@binkert.org break 696157Snate@binkert.org else: 706157Snate@binkert.org yield src 716157Snate@binkert.org 726157Snate@binkert.orgclass SourceFile(object): 736157Snate@binkert.org __metaclass__ = SourceMeta 746157Snate@binkert.org def __init__(self, source): 756157Snate@binkert.org tnode = source 766157Snate@binkert.org if not isinstance(source, SCons.Node.FS.File): 776157Snate@binkert.org tnode = File(source) 786157Snate@binkert.org 796157Snate@binkert.org self.tnode = tnode 806157Snate@binkert.org self.snode = tnode.srcnode() 816157Snate@binkert.org self.filename = str(tnode) 826157Snate@binkert.org self.dirname = dirname(self.filename) 836157Snate@binkert.org self.basename = basename(self.filename) 846157Snate@binkert.org index = self.basename.rfind('.') 856157Snate@binkert.org if index <= 0: 866157Snate@binkert.org # dot files aren't extensions 876157Snate@binkert.org self.extname = self.basename, None 886157Snate@binkert.org else: 898483Sgblack@eecs.umich.edu self.extname = self.basename[:index], self.basename[index+1:] 908483Sgblack@eecs.umich.edu 916157Snate@binkert.org for base in type(self).__mro__: 926882SBrad.Beckmann@amd.com if issubclass(base, SourceFile): 936286Snate@binkert.org base.all.append(self) 946286Snate@binkert.org 956286Snate@binkert.org def __lt__(self, other): return self.filename < other.filename 966286Snate@binkert.org def __le__(self, other): return self.filename <= other.filename 978092Snilay@cs.wisc.edu def __gt__(self, other): return self.filename > other.filename 986286Snate@binkert.org def __ge__(self, other): return self.filename >= other.filename 996286Snate@binkert.org def __eq__(self, other): return self.filename == other.filename 1006157Snate@binkert.org def __ne__(self, other): return self.filename != other.filename 1016157Snate@binkert.org 1026157Snate@binkert.orgclass Source(SourceFile): 1036157Snate@binkert.org '''Add a c/c++ source file to the build''' 1046157Snate@binkert.org def __init__(self, source, Werror=True, swig=False, bin_only=False, 1056286Snate@binkert.org skip_lib=False): 1066157Snate@binkert.org super(Source, self).__init__(source) 1076286Snate@binkert.org 1086157Snate@binkert.org self.Werror = Werror 1096157Snate@binkert.org self.swig = swig 1106157Snate@binkert.org self.bin_only = bin_only 1118191SLisa.Hsu@amd.com self.skip_lib = bin_only or skip_lib 1126157Snate@binkert.org 1136157Snate@binkert.orgclass PySource(SourceFile): 1146797SBrad.Beckmann@amd.com '''Add a python source file to the named package''' 1156157Snate@binkert.org invalid_sym_char = re.compile('[^A-z0-9_]') 1166157Snate@binkert.org modules = {} 1176157Snate@binkert.org tnodes = {} 118 symnames = {} 119 120 def __init__(self, package, source): 121 super(PySource, self).__init__(source) 122 123 modname,ext = self.extname 124 assert ext == 'py' 125 126 if package: 127 path = package.split('.') 128 else: 129 path = [] 130 131 modpath = path[:] 132 if modname != '__init__': 133 modpath += [ modname ] 134 modpath = '.'.join(modpath) 135 136 arcpath = path + [ self.basename ] 137 abspath = self.snode.abspath 138 if not exists(abspath): 139 abspath = self.tnode.abspath 140 141 self.package = package 142 self.modname = modname 143 self.modpath = modpath 144 self.arcname = joinpath(*arcpath) 145 self.abspath = abspath 146 self.compiled = File(self.filename + 'c') 147 self.cpp = File(self.filename + '.cc') 148 self.symname = PySource.invalid_sym_char.sub('_', modpath) 149 150 PySource.modules[modpath] = self 151 PySource.tnodes[self.tnode] = self 152 PySource.symnames[self.symname] = self 153 154class SimObject(PySource): 155 '''Add a SimObject python file as a python source object and add 156 it to a list of sim object modules''' 157 158 fixed = False 159 modnames = [] 160 161 def __init__(self, source): 162 super(SimObject, self).__init__('m5.objects', source) 163 if self.fixed: 164 raise AttributeError, "Too late to call SimObject now." 165 166 bisect.insort_right(SimObject.modnames, self.modname) 167 168class SwigSource(SourceFile): 169 '''Add a swig file to build''' 170 171 def __init__(self, package, source): 172 super(SwigSource, self).__init__(source) 173 174 modname,ext = self.extname 175 assert ext == 'i' 176 177 self.module = modname 178 cc_file = joinpath(self.dirname, modname + '_wrap.cc') 179 py_file = joinpath(self.dirname, modname + '.py') 180 181 self.cc_source = Source(cc_file, swig=True) 182 self.py_source = PySource(package, py_file) 183 184unit_tests = [] 185def UnitTest(target, sources): 186 if not isinstance(sources, (list, tuple)): 187 sources = [ sources ] 188 189 sources = [ Source(src, skip_lib=True) for src in sources ] 190 unit_tests.append((target, sources)) 191 192# Children should have access 193Export('Source') 194Export('PySource') 195Export('SimObject') 196Export('SwigSource') 197Export('UnitTest') 198 199######################################################################## 200# 201# Trace Flags 202# 203trace_flags = {} 204def TraceFlag(name, desc=None): 205 if name in trace_flags: 206 raise AttributeError, "Flag %s already specified" % name 207 trace_flags[name] = (name, (), desc) 208 209def CompoundFlag(name, flags, desc=None): 210 if name in trace_flags: 211 raise AttributeError, "Flag %s already specified" % name 212 213 compound = tuple(flags) 214 trace_flags[name] = (name, compound, desc) 215 216Export('TraceFlag') 217Export('CompoundFlag') 218 219######################################################################## 220# 221# Set some compiler variables 222# 223 224# Include file paths are rooted in this directory. SCons will 225# automatically expand '.' to refer to both the source directory and 226# the corresponding build directory to pick up generated include 227# files. 228env.Append(CPPPATH=Dir('.')) 229 230for extra_dir in extras_dir_list: 231 env.Append(CPPPATH=Dir(extra_dir)) 232 233# Workaround for bug in SCons version > 0.97d20071212 234# Scons bug id: 2006 M5 Bug id: 308 235for root, dirs, files in os.walk(base_dir, topdown=True): 236 Dir(root[len(base_dir) + 1:]) 237 238######################################################################## 239# 240# Walk the tree and execute all SConscripts in subdirectories 241# 242 243here = Dir('.').srcnode().abspath 244for root, dirs, files in os.walk(base_dir, topdown=True): 245 if root == here: 246 # we don't want to recurse back into this SConscript 247 continue 248 249 if 'SConscript' in files: 250 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 251 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 252 253for extra_dir in extras_dir_list: 254 prefix_len = len(dirname(extra_dir)) + 1 255 for root, dirs, files in os.walk(extra_dir, topdown=True): 256 if 'SConscript' in files: 257 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 258 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 259 260for opt in export_vars: 261 env.ConfigFile(opt) 262 263def makeTheISA(source, target, env): 264 isas = [ src.get_contents() for src in source ] 265 target_isa = env['TARGET_ISA'] 266 def define(isa): 267 return isa.upper() + '_ISA' 268 269 def namespace(isa): 270 return isa[0].upper() + isa[1:].lower() + 'ISA' 271 272 273 code = code_formatter() 274 code('''\ 275#ifndef __CONFIG_THE_ISA_HH__ 276#define __CONFIG_THE_ISA_HH__ 277 278''') 279 280 for i,isa in enumerate(isas): 281 code('#define $0 $1', define(isa), i + 1) 282 283 code(''' 284 285#define THE_ISA ${{define(target_isa)}} 286#define TheISA ${{namespace(target_isa)}} 287 288#endif // __CONFIG_THE_ISA_HH__''') 289 290 code.write(str(target[0])) 291 292env.Command('config/the_isa.hh', map(Value, all_isa_list), 293 MakeAction(makeTheISA, Transform("CFG ISA", 0))) 294 295######################################################################## 296# 297# Prevent any SimObjects from being added after this point, they 298# should all have been added in the SConscripts above 299# 300SimObject.fixed = True 301 302class DictImporter(object): 303 '''This importer takes a dictionary of arbitrary module names that 304 map to arbitrary filenames.''' 305 def __init__(self, modules): 306 self.modules = modules 307 self.installed = set() 308 309 def __del__(self): 310 self.unload() 311 312 def unload(self): 313 import sys 314 for module in self.installed: 315 del sys.modules[module] 316 self.installed = set() 317 318 def find_module(self, fullname, path): 319 if fullname == 'm5.defines': 320 return self 321 322 if fullname == 'm5.objects': 323 return self 324 325 if fullname.startswith('m5.internal'): 326 return None 327 328 source = self.modules.get(fullname, None) 329 if source is not None and fullname.startswith('m5.objects'): 330 return self 331 332 return None 333 334 def load_module(self, fullname): 335 mod = imp.new_module(fullname) 336 sys.modules[fullname] = mod 337 self.installed.add(fullname) 338 339 mod.__loader__ = self 340 if fullname == 'm5.objects': 341 mod.__path__ = fullname.split('.') 342 return mod 343 344 if fullname == 'm5.defines': 345 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 346 return mod 347 348 source = self.modules[fullname] 349 if source.modname == '__init__': 350 mod.__path__ = source.modpath 351 mod.__file__ = source.abspath 352 353 exec file(source.abspath, 'r') in mod.__dict__ 354 355 return mod 356 357import m5.SimObject 358import m5.params 359from m5.util import code_formatter 360 361m5.SimObject.clear() 362m5.params.clear() 363 364# install the python importer so we can grab stuff from the source 365# tree itself. We can't have SimObjects added after this point or 366# else we won't know about them for the rest of the stuff. 367importer = DictImporter(PySource.modules) 368sys.meta_path[0:0] = [ importer ] 369 370# import all sim objects so we can populate the all_objects list 371# make sure that we're working with a list, then let's sort it 372for modname in SimObject.modnames: 373 exec('from m5.objects import %s' % modname) 374 375# we need to unload all of the currently imported modules so that they 376# will be re-imported the next time the sconscript is run 377importer.unload() 378sys.meta_path.remove(importer) 379 380sim_objects = m5.SimObject.allClasses 381all_enums = m5.params.allEnums 382 383all_params = {} 384for name,obj in sorted(sim_objects.iteritems()): 385 for param in obj._params.local.values(): 386 # load the ptype attribute now because it depends on the 387 # current version of SimObject.allClasses, but when scons 388 # actually uses the value, all versions of 389 # SimObject.allClasses will have been loaded 390 param.ptype 391 392 if not hasattr(param, 'swig_decl'): 393 continue 394 pname = param.ptype_str 395 if pname not in all_params: 396 all_params[pname] = param 397 398######################################################################## 399# 400# calculate extra dependencies 401# 402module_depends = ["m5", "m5.SimObject", "m5.params"] 403depends = [ PySource.modules[dep].snode for dep in module_depends ] 404 405######################################################################## 406# 407# Commands for the basic automatically generated python files 408# 409 410# Generate Python file containing a dict specifying the current 411# buildEnv flags. 412def makeDefinesPyFile(target, source, env): 413 build_env, hg_info = [ x.get_contents() for x in source ] 414 415 code = code_formatter() 416 code(""" 417import m5.internal 418import m5.util 419 420buildEnv = m5.util.SmartDict($build_env) 421hgRev = '$hg_info' 422 423compileDate = m5.internal.core.compileDate 424_globals = globals() 425for key,val in m5.internal.core.__dict__.iteritems(): 426 if key.startswith('flag_'): 427 flag = key[5:] 428 _globals[flag] = val 429del _globals 430""") 431 code.write(target[0].abspath) 432 433defines_info = [ Value(build_env), Value(env['HG_INFO']) ] 434# Generate a file with all of the compile options in it 435env.Command('python/m5/defines.py', defines_info, 436 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 437PySource('m5', 'python/m5/defines.py') 438 439# Generate python file containing info about the M5 source code 440def makeInfoPyFile(target, source, env): 441 code = code_formatter() 442 for src in source: 443 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 444 code('$src = ${{repr(data)}}') 445 code.write(str(target[0])) 446 447# Generate a file that wraps the basic top level files 448env.Command('python/m5/info.py', 449 [ '#/AUTHORS', '#/LICENSE', '#/README', ], 450 MakeAction(makeInfoPyFile, Transform("INFO"))) 451PySource('m5', 'python/m5/info.py') 452 453######################################################################## 454# 455# Create all of the SimObject param headers and enum headers 456# 457 458def createSimObjectParam(target, source, env): 459 assert len(target) == 1 and len(source) == 1 460 461 name = str(source[0].get_contents()) 462 obj = sim_objects[name] 463 464 code = code_formatter() 465 obj.cxx_decl(code) 466 code.write(target[0].abspath) 467 468def createSwigParam(target, source, env): 469 assert len(target) == 1 and len(source) == 1 470 471 name = str(source[0].get_contents()) 472 param = all_params[name] 473 474 code = code_formatter() 475 code('%module(package="m5.internal") $0_${name}', param.file_ext) 476 param.swig_decl(code) 477 code.write(target[0].abspath) 478 479def createEnumStrings(target, source, env): 480 assert len(target) == 1 and len(source) == 1 481 482 name = str(source[0].get_contents()) 483 obj = all_enums[name] 484 485 code = code_formatter() 486 obj.cxx_def(code) 487 code.write(target[0].abspath) 488 489def createEnumParam(target, source, env): 490 assert len(target) == 1 and len(source) == 1 491 492 name = str(source[0].get_contents()) 493 obj = all_enums[name] 494 495 code = code_formatter() 496 obj.cxx_decl(code) 497 code.write(target[0].abspath) 498 499def createEnumSwig(target, source, env): 500 assert len(target) == 1 and len(source) == 1 501 502 name = str(source[0].get_contents()) 503 obj = all_enums[name] 504 505 code = code_formatter() 506 code('''\ 507%module(package="m5.internal") enum_$name 508 509%{ 510#include "enums/$name.hh" 511%} 512 513%include "enums/$name.hh" 514''') 515 code.write(target[0].abspath) 516 517# Generate all of the SimObject param struct header files 518params_hh_files = [] 519for name,simobj in sorted(sim_objects.iteritems()): 520 py_source = PySource.modules[simobj.__module__] 521 extra_deps = [ py_source.tnode ] 522 523 hh_file = File('params/%s.hh' % name) 524 params_hh_files.append(hh_file) 525 env.Command(hh_file, Value(name), 526 MakeAction(createSimObjectParam, Transform("SO PARAM"))) 527 env.Depends(hh_file, depends + extra_deps) 528 529# Generate any parameter header files needed 530params_i_files = [] 531for name,param in all_params.iteritems(): 532 i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name)) 533 params_i_files.append(i_file) 534 env.Command(i_file, Value(name), 535 MakeAction(createSwigParam, Transform("SW PARAM"))) 536 env.Depends(i_file, depends) 537 SwigSource('m5.internal', i_file) 538 539# Generate all enum header files 540for name,enum in sorted(all_enums.iteritems()): 541 py_source = PySource.modules[enum.__module__] 542 extra_deps = [ py_source.tnode ] 543 544 cc_file = File('enums/%s.cc' % name) 545 env.Command(cc_file, Value(name), 546 MakeAction(createEnumStrings, Transform("ENUM STR"))) 547 env.Depends(cc_file, depends + extra_deps) 548 Source(cc_file) 549 550 hh_file = File('enums/%s.hh' % name) 551 env.Command(hh_file, Value(name), 552 MakeAction(createEnumParam, Transform("EN PARAM"))) 553 env.Depends(hh_file, depends + extra_deps) 554 555 i_file = File('python/m5/internal/enum_%s.i' % name) 556 env.Command(i_file, Value(name), 557 MakeAction(createEnumSwig, Transform("ENUMSWIG"))) 558 env.Depends(i_file, depends + extra_deps) 559 SwigSource('m5.internal', i_file) 560 561def buildParam(target, source, env): 562 name = source[0].get_contents() 563 obj = sim_objects[name] 564 class_path = obj.cxx_class.split('::') 565 classname = class_path[-1] 566 namespaces = class_path[:-1] 567 params = obj._params.local.values() 568 569 code = code_formatter() 570 571 code('%module(package="m5.internal") param_$name') 572 code() 573 code('%{') 574 code('#include "params/$obj.hh"') 575 for param in params: 576 param.cxx_predecls(code) 577 code('%}') 578 code() 579 580 for param in params: 581 param.swig_predecls(code) 582 583 code() 584 if obj._base: 585 code('%import "python/m5/internal/param_${{obj._base}}.i"') 586 code() 587 obj.swig_objdecls(code) 588 code() 589 590 code('%include "params/$obj.hh"') 591 592 code.write(target[0].abspath) 593 594for name in sim_objects.iterkeys(): 595 params_file = File('python/m5/internal/param_%s.i' % name) 596 env.Command(params_file, Value(name), 597 MakeAction(buildParam, Transform("BLDPARAM"))) 598 env.Depends(params_file, depends) 599 SwigSource('m5.internal', params_file) 600 601# Generate the main swig init file 602def makeEmbeddedSwigInit(target, source, env): 603 code = code_formatter() 604 module = source[0].get_contents() 605 code('''\ 606#include "sim/init.hh" 607 608extern "C" { 609 void init_${module}(); 610} 611 612EmbeddedSwig embed_swig_${module}(init_${module}); 613''') 614 code.write(str(target[0])) 615 616# Build all swig modules 617for swig in SwigSource.all: 618 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 619 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 620 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG"))) 621 init_file = 'python/swig/init_%s.cc' % swig.module 622 env.Command(init_file, Value(swig.module), 623 MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW"))) 624 Source(init_file) 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 code = code_formatter() 651 652 allFlags = getFlags(source) 653 654 code('basic = [') 655 code.indent() 656 for flag, compound, desc in allFlags: 657 if not compound: 658 code("'$flag',") 659 code(']') 660 code.dedent() 661 code() 662 663 code('compound = [') 664 code.indent() 665 code("'All',") 666 for flag, compound, desc in allFlags: 667 if compound: 668 code("'$flag',") 669 code("]") 670 code.dedent() 671 code() 672 673 code("all = frozenset(basic + compound)") 674 code() 675 676 code('compoundMap = {') 677 code.indent() 678 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 679 code("'All' : $all,") 680 for flag, compound, desc in allFlags: 681 if compound: 682 code("'$flag' : $compound,") 683 code('}') 684 code.dedent() 685 code() 686 687 code('descriptions = {') 688 code.indent() 689 code("'All' : 'All flags',") 690 for flag, compound, desc in allFlags: 691 code("'$flag' : '$desc',") 692 code("}") 693 code.dedent() 694 695 code.write(str(target[0])) 696 697def traceFlagsCC(target, source, env): 698 assert(len(target) == 1) 699 700 allFlags = getFlags(source) 701 code = code_formatter() 702 703 # file header 704 code(''' 705/* 706 * DO NOT EDIT THIS FILE! Automatically generated 707 */ 708 709#include "base/traceflags.hh" 710 711using namespace Trace; 712 713const char *Trace::flagStrings[] = 714{''') 715 716 code.indent() 717 # The string array is used by SimpleEnumParam to map the strings 718 # provided by the user to enum values. 719 for flag, compound, desc in allFlags: 720 if not compound: 721 code('"$flag",') 722 723 code('"All",') 724 for flag, compound, desc in allFlags: 725 if compound: 726 code('"$flag",') 727 code.dedent() 728 729 code('''\ 730}; 731 732const int Trace::numFlagStrings = ${{len(allFlags) + 1}}; 733 734''') 735 736 # Now define the individual compound flag arrays. There is an array 737 # for each compound flag listing the component base flags. 738 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 739 code('static const Flags AllMap[] = {') 740 code.indent() 741 for flag, compound, desc in allFlags: 742 if not compound: 743 code('$flag,') 744 code.dedent() 745 code('};') 746 code() 747 748 for flag, compound, desc in allFlags: 749 if not compound: 750 continue 751 code('static const Flags ${flag}Map[] = {') 752 code.indent() 753 for flag in compound: 754 code('$flag,') 755 code('(Flags)-1') 756 code.dedent() 757 code('};') 758 code() 759 760 # Finally the compoundFlags[] array maps the compound flags 761 # to their individual arrays/ 762 code('const Flags *Trace::compoundFlags[] = {') 763 code.indent() 764 code('AllMap,') 765 for flag, compound, desc in allFlags: 766 if compound: 767 code('${flag}Map,') 768 # file trailer 769 code.dedent() 770 code('};') 771 772 code.write(str(target[0])) 773 774def traceFlagsHH(target, source, env): 775 assert(len(target) == 1) 776 777 allFlags = getFlags(source) 778 code = code_formatter() 779 780 # file header boilerplate 781 code('''\ 782/* 783 * DO NOT EDIT THIS FILE! 784 * 785 * Automatically generated from traceflags.py 786 */ 787 788#ifndef __BASE_TRACE_FLAGS_HH__ 789#define __BASE_TRACE_FLAGS_HH__ 790 791namespace Trace { 792 793enum Flags {''') 794 795 # Generate the enum. Base flags come first, then compound flags. 796 idx = 0 797 code.indent() 798 for flag, compound, desc in allFlags: 799 if not compound: 800 code('$flag = $idx,') 801 idx += 1 802 803 numBaseFlags = idx 804 code('NumFlags = $idx,') 805 code.dedent() 806 code() 807 808 # put a comment in here to separate base from compound flags 809 code(''' 810// The remaining enum values are *not* valid indices for Trace::flags. 811// They are "compound" flags, which correspond to sets of base 812// flags, and are used by changeFlag.''') 813 814 code.indent() 815 code('All = $idx,') 816 idx += 1 817 for flag, compound, desc in allFlags: 818 if compound: 819 code('$flag = $idx,') 820 idx += 1 821 822 numCompoundFlags = idx - numBaseFlags 823 code('NumCompoundFlags = $numCompoundFlags') 824 code.dedent() 825 826 # trailer boilerplate 827 code('''\ 828}; // enum Flags 829 830// Array of strings for SimpleEnumParam 831extern const char *flagStrings[]; 832extern const int numFlagStrings; 833 834// Array of arraay pointers: for each compound flag, gives the list of 835// base flags to set. Inidividual flag arrays are terminated by -1. 836extern const Flags *compoundFlags[]; 837 838} // namespace Trace 839 840#endif // __BASE_TRACE_FLAGS_HH__ 841''') 842 843 code.write(str(target[0])) 844 845flags = map(Value, trace_flags.values()) 846env.Command('base/traceflags.py', flags, 847 MakeAction(traceFlagsPy, Transform("TRACING", 0))) 848PySource('m5', 'base/traceflags.py') 849 850env.Command('base/traceflags.hh', flags, 851 MakeAction(traceFlagsHH, Transform("TRACING", 0))) 852env.Command('base/traceflags.cc', flags, 853 MakeAction(traceFlagsCC, Transform("TRACING", 0))) 854Source('base/traceflags.cc') 855 856# Embed python files. All .py files that have been indicated by a 857# PySource() call in a SConscript need to be embedded into the M5 858# library. To do that, we compile the file to byte code, marshal the 859# byte code, compress it, and then generate a c++ file that 860# inserts the result into an array. 861def embedPyFile(target, source, env): 862 def c_str(string): 863 if string is None: 864 return "0" 865 return '"%s"' % string 866 867 '''Action function to compile a .py into a code object, marshal 868 it, compress it, and stick it into an asm file so the code appears 869 as just bytes with a label in the data section''' 870 871 src = file(str(source[0]), 'r').read() 872 873 pysource = PySource.tnodes[source[0]] 874 compiled = compile(src, pysource.abspath, 'exec') 875 marshalled = marshal.dumps(compiled) 876 compressed = zlib.compress(marshalled) 877 data = compressed 878 sym = pysource.symname 879 880 code = code_formatter() 881 code('''\ 882#include "sim/init.hh" 883 884namespace { 885 886const char data_${sym}[] = { 887''') 888 code.indent() 889 step = 16 890 for i in xrange(0, len(data), step): 891 x = array.array('B', data[i:i+step]) 892 code(''.join('%d,' % d for d in x)) 893 code.dedent() 894 895 code('''}; 896 897EmbeddedPython embedded_${sym}( 898 ${{c_str(pysource.arcname)}}, 899 ${{c_str(pysource.abspath)}}, 900 ${{c_str(pysource.modpath)}}, 901 data_${sym}, 902 ${{len(data)}}, 903 ${{len(marshalled)}}); 904 905} // anonymous namespace 906''') 907 code.write(str(target[0])) 908 909for source in PySource.all: 910 env.Command(source.cpp, source.tnode, 911 MakeAction(embedPyFile, Transform("EMBED PY"))) 912 Source(source.cpp) 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 923date_source = Source('base/date.cc', skip_lib=True) 924 925# Function to create a new build environment as clone of current 926# environment 'env' with modified object suffix and optional stripped 927# binary. Additional keyword arguments are appended to corresponding 928# build environment vars. 929def makeEnv(label, objsfx, strip = False, **kwargs): 930 # SCons doesn't know to append a library suffix when there is a '.' in the 931 # name. Use '_' instead. 932 libname = 'm5_' + label 933 exename = 'm5.' + label 934 935 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 936 new_env.Label = label 937 new_env.Append(**kwargs) 938 939 swig_env = new_env.Clone() 940 swig_env.Append(CCFLAGS='-Werror') 941 if env['GCC']: 942 swig_env.Append(CCFLAGS='-Wno-uninitialized') 943 swig_env.Append(CCFLAGS='-Wno-sign-compare') 944 swig_env.Append(CCFLAGS='-Wno-parentheses') 945 946 werror_env = new_env.Clone() 947 werror_env.Append(CCFLAGS='-Werror') 948 949 def make_obj(source, static, extra_deps = None): 950 '''This function adds the specified source to the correct 951 build environment, and returns the corresponding SCons Object 952 nodes''' 953 954 if source.swig: 955 env = swig_env 956 elif source.Werror: 957 env = werror_env 958 else: 959 env = new_env 960 961 if static: 962 obj = env.StaticObject(source.tnode) 963 else: 964 obj = env.SharedObject(source.tnode) 965 966 if extra_deps: 967 env.Depends(obj, extra_deps) 968 969 return obj 970 971 static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)] 972 shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)] 973 974 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 975 static_objs.append(static_date) 976 977 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 978 shared_objs.append(shared_date) 979 980 # First make a library of everything but main() so other programs can 981 # link against m5. 982 static_lib = new_env.StaticLibrary(libname, static_objs) 983 shared_lib = new_env.SharedLibrary(libname, shared_objs) 984 985 for target, sources in unit_tests: 986 objs = [ make_obj(s, static=True) for s in sources ] 987 new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs) 988 989 # Now link a stub with main() and the static library. 990 bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ] 991 progname = exename 992 if strip: 993 progname += '.unstripped' 994 995 targets = new_env.Program(progname, bin_objs + static_objs) 996 997 if strip: 998 if sys.platform == 'sunos5': 999 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 1000 else: 1001 cmd = 'strip $SOURCE -o $TARGET' 1002 targets = new_env.Command(exename, progname, 1003 MakeAction(cmd, Transform("STRIP"))) 1004 1005 new_env.M5Binary = targets[0] 1006 envList.append(new_env) 1007 1008# Debug binary 1009ccflags = {} 1010if env['GCC']: 1011 if sys.platform == 'sunos5': 1012 ccflags['debug'] = '-gstabs+' 1013 else: 1014 ccflags['debug'] = '-ggdb3' 1015 ccflags['opt'] = '-g -O3' 1016 ccflags['fast'] = '-O3' 1017 ccflags['prof'] = '-O3 -g -pg' 1018elif env['SUNCC']: 1019 ccflags['debug'] = '-g0' 1020 ccflags['opt'] = '-g -O' 1021 ccflags['fast'] = '-fast' 1022 ccflags['prof'] = '-fast -g -pg' 1023elif env['ICC']: 1024 ccflags['debug'] = '-g -O0' 1025 ccflags['opt'] = '-g -O' 1026 ccflags['fast'] = '-fast' 1027 ccflags['prof'] = '-fast -g -pg' 1028else: 1029 print 'Unknown compiler, please fix compiler options' 1030 Exit(1) 1031 1032makeEnv('debug', '.do', 1033 CCFLAGS = Split(ccflags['debug']), 1034 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 1035 1036# Optimized binary 1037makeEnv('opt', '.o', 1038 CCFLAGS = Split(ccflags['opt']), 1039 CPPDEFINES = ['TRACING_ON=1']) 1040 1041# "Fast" binary 1042makeEnv('fast', '.fo', strip = True, 1043 CCFLAGS = Split(ccflags['fast']), 1044 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 1045 1046# Profiled binary 1047makeEnv('prof', '.po', 1048 CCFLAGS = Split(ccflags['prof']), 1049 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1050 LINKFLAGS = '-pg') 1051 1052Return('envList') 1053