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