SConscript revision 6656:69714e675ee2
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 = [(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 trace_flags[name] = (name, compound, desc) 213 214Export('TraceFlag') 215Export('CompoundFlag') 216 217######################################################################## 218# 219# Set some compiler variables 220# 221 222# Include file paths are rooted in this directory. SCons will 223# automatically expand '.' to refer to both the source directory and 224# the corresponding build directory to pick up generated include 225# files. 226env.Append(CPPPATH=Dir('.')) 227 228for extra_dir in extras_dir_list: 229 env.Append(CPPPATH=Dir(extra_dir)) 230 231# Add a flag defining what THE_ISA should be for all compilation 232env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) 233 234# Workaround for bug in SCons version > 0.97d20071212 235# Scons bug id: 2006 M5 Bug id: 308 236for root, dirs, files in os.walk(base_dir, topdown=True): 237 Dir(root[len(base_dir) + 1:]) 238 239######################################################################## 240# 241# Walk the tree and execute all SConscripts in subdirectories 242# 243 244here = Dir('.').srcnode().abspath 245for root, dirs, files in os.walk(base_dir, topdown=True): 246 if root == here: 247 # we don't want to recurse back into this SConscript 248 continue 249 250 if 'SConscript' in files: 251 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 252 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir) 253 254for extra_dir in extras_dir_list: 255 prefix_len = len(dirname(extra_dir)) + 1 256 for root, dirs, files in os.walk(extra_dir, topdown=True): 257 if 'SConscript' in files: 258 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 259 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir) 260 261for opt in export_vars: 262 env.ConfigFile(opt) 263 264######################################################################## 265# 266# Prevent any SimObjects from being added after this point, they 267# should all have been added in the SConscripts above 268# 269SimObject.fixed = True 270 271class DictImporter(object): 272 '''This importer takes a dictionary of arbitrary module names that 273 map to arbitrary filenames.''' 274 def __init__(self, modules): 275 self.modules = modules 276 self.installed = set() 277 278 def __del__(self): 279 self.unload() 280 281 def unload(self): 282 import sys 283 for module in self.installed: 284 del sys.modules[module] 285 self.installed = set() 286 287 def find_module(self, fullname, path): 288 if fullname == 'm5.defines': 289 return self 290 291 if fullname == 'm5.objects': 292 return self 293 294 if fullname.startswith('m5.internal'): 295 return None 296 297 source = self.modules.get(fullname, None) 298 if source is not None and fullname.startswith('m5.objects'): 299 return self 300 301 return None 302 303 def load_module(self, fullname): 304 mod = imp.new_module(fullname) 305 sys.modules[fullname] = mod 306 self.installed.add(fullname) 307 308 mod.__loader__ = self 309 if fullname == 'm5.objects': 310 mod.__path__ = fullname.split('.') 311 return mod 312 313 if fullname == 'm5.defines': 314 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 315 return mod 316 317 source = self.modules[fullname] 318 if source.modname == '__init__': 319 mod.__path__ = source.modpath 320 mod.__file__ = source.snode.abspath 321 322 exec file(source.snode.abspath, 'r') in mod.__dict__ 323 324 return mod 325 326import m5.SimObject 327import m5.params 328 329m5.SimObject.clear() 330m5.params.clear() 331 332# install the python importer so we can grab stuff from the source 333# tree itself. We can't have SimObjects added after this point or 334# else we won't know about them for the rest of the stuff. 335importer = DictImporter(PySource.modules) 336sys.meta_path[0:0] = [ importer ] 337 338# import all sim objects so we can populate the all_objects list 339# make sure that we're working with a list, then let's sort it 340for modname in SimObject.modnames: 341 exec('from m5.objects import %s' % modname) 342 343# we need to unload all of the currently imported modules so that they 344# will be re-imported the next time the sconscript is run 345importer.unload() 346sys.meta_path.remove(importer) 347 348sim_objects = m5.SimObject.allClasses 349all_enums = m5.params.allEnums 350 351all_params = {} 352for name,obj in sorted(sim_objects.iteritems()): 353 for param in obj._params.local.values(): 354 # load the ptype attribute now because it depends on the 355 # current version of SimObject.allClasses, but when scons 356 # actually uses the value, all versions of 357 # SimObject.allClasses will have been loaded 358 param.ptype 359 360 if not hasattr(param, 'swig_decl'): 361 continue 362 pname = param.ptype_str 363 if pname not in all_params: 364 all_params[pname] = param 365 366######################################################################## 367# 368# calculate extra dependencies 369# 370module_depends = ["m5", "m5.SimObject", "m5.params"] 371depends = [ PySource.modules[dep].tnode for dep in module_depends ] 372 373######################################################################## 374# 375# Commands for the basic automatically generated python files 376# 377 378# Generate Python file containing a dict specifying the current 379# buildEnv flags. 380def makeDefinesPyFile(target, source, env): 381 build_env, hg_info = [ x.get_contents() for x in source ] 382 383 code = m5.util.code_formatter() 384 code(""" 385import m5.internal 386import m5.util 387 388buildEnv = m5.util.SmartDict($build_env) 389hgRev = '$hg_info' 390 391compileDate = m5.internal.core.compileDate 392for k,v in m5.internal.core.__dict__.iteritems(): 393 if k.startswith('flag_'): 394 setattr(buildEnv, k[5:], v) 395""") 396 code.write(str(target[0])) 397 398defines_info = [ Value(build_env), Value(env['HG_INFO']) ] 399# Generate a file with all of the compile options in it 400env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile) 401PySource('m5', 'python/m5/defines.py') 402 403# Generate python file containing info about the M5 source code 404def makeInfoPyFile(target, source, env): 405 f = file(str(target[0]), 'w') 406 for src in source: 407 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 408 print >>f, "%s = %s" % (src, repr(data)) 409 f.close() 410 411# Generate a file that wraps the basic top level files 412env.Command('python/m5/info.py', 413 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], 414 makeInfoPyFile) 415PySource('m5', 'python/m5/info.py') 416 417# Generate the __init__.py file for m5.objects 418def makeObjectsInitFile(target, source, env): 419 f = file(str(target[0]), 'w') 420 print >>f, 'from params import *' 421 print >>f, 'from m5.SimObject import *' 422 for module in source: 423 print >>f, 'from %s import *' % module.get_contents() 424 f.close() 425 426# Generate an __init__.py file for the objects package 427env.Command('python/m5/objects/__init__.py', 428 map(Value, SimObject.modnames), 429 makeObjectsInitFile) 430PySource('m5.objects', 'python/m5/objects/__init__.py') 431 432######################################################################## 433# 434# Create all of the SimObject param headers and enum headers 435# 436 437def createSimObjectParam(target, source, env): 438 assert len(target) == 1 and len(source) == 1 439 440 hh_file = file(target[0].abspath, 'w') 441 name = str(source[0].get_contents()) 442 obj = sim_objects[name] 443 444 print >>hh_file, obj.cxx_decl() 445 hh_file.close() 446 447def createSwigParam(target, source, env): 448 assert len(target) == 1 and len(source) == 1 449 450 i_file = file(target[0].abspath, 'w') 451 name = str(source[0].get_contents()) 452 param = all_params[name] 453 454 for line in param.swig_decl(): 455 print >>i_file, line 456 i_file.close() 457 458def createEnumStrings(target, source, env): 459 assert len(target) == 1 and len(source) == 1 460 461 cc_file = file(target[0].abspath, 'w') 462 name = str(source[0].get_contents()) 463 obj = all_enums[name] 464 465 print >>cc_file, obj.cxx_def() 466 cc_file.close() 467 468def createEnumParam(target, source, env): 469 assert len(target) == 1 and len(source) == 1 470 471 hh_file = file(target[0].abspath, 'w') 472 name = str(source[0].get_contents()) 473 obj = all_enums[name] 474 475 print >>hh_file, obj.cxx_decl() 476 hh_file.close() 477 478# Generate all of the SimObject param struct header files 479params_hh_files = [] 480for name,simobj in sorted(sim_objects.iteritems()): 481 py_source = PySource.modules[simobj.__module__] 482 extra_deps = [ py_source.tnode ] 483 484 hh_file = File('params/%s.hh' % name) 485 params_hh_files.append(hh_file) 486 env.Command(hh_file, Value(name), createSimObjectParam) 487 env.Depends(hh_file, depends + extra_deps) 488 489# Generate any parameter header files needed 490params_i_files = [] 491for name,param in all_params.iteritems(): 492 i_file = File('params/%s_%s.i' % (name, param.file_ext)) 493 params_i_files.append(i_file) 494 env.Command(i_file, Value(name), createSwigParam) 495 env.Depends(i_file, depends) 496 497# Generate all enum header files 498for name,enum in sorted(all_enums.iteritems()): 499 py_source = PySource.modules[enum.__module__] 500 extra_deps = [ py_source.tnode ] 501 502 cc_file = File('enums/%s.cc' % name) 503 env.Command(cc_file, Value(name), createEnumStrings) 504 env.Depends(cc_file, depends + extra_deps) 505 Source(cc_file) 506 507 hh_file = File('enums/%s.hh' % name) 508 env.Command(hh_file, Value(name), createEnumParam) 509 env.Depends(hh_file, depends + extra_deps) 510 511# Build the big monolithic swigged params module (wraps all SimObject 512# param structs and enum structs) 513def buildParams(target, source, env): 514 names = [ s.get_contents() for s in source ] 515 objs = [ sim_objects[name] for name in names ] 516 out = file(target[0].abspath, 'w') 517 518 ordered_objs = [] 519 obj_seen = set() 520 def order_obj(obj): 521 name = str(obj) 522 if name in obj_seen: 523 return 524 525 obj_seen.add(name) 526 if str(obj) != 'SimObject': 527 order_obj(obj.__bases__[0]) 528 529 ordered_objs.append(obj) 530 531 for obj in objs: 532 order_obj(obj) 533 534 enums = set() 535 predecls = [] 536 pd_seen = set() 537 538 def add_pds(*pds): 539 for pd in pds: 540 if pd not in pd_seen: 541 predecls.append(pd) 542 pd_seen.add(pd) 543 544 for obj in ordered_objs: 545 params = obj._params.local.values() 546 for param in params: 547 ptype = param.ptype 548 if issubclass(ptype, m5.params.Enum): 549 if ptype not in enums: 550 enums.add(ptype) 551 pds = param.swig_predecls() 552 if isinstance(pds, (list, tuple)): 553 add_pds(*pds) 554 else: 555 add_pds(pds) 556 557 print >>out, '%module params' 558 559 print >>out, '%{' 560 for obj in ordered_objs: 561 print >>out, '#include "params/%s.hh"' % obj 562 print >>out, '%}' 563 564 for pd in predecls: 565 print >>out, pd 566 567 enums = list(enums) 568 enums.sort() 569 for enum in enums: 570 print >>out, '%%include "enums/%s.hh"' % enum.__name__ 571 print >>out 572 573 for obj in ordered_objs: 574 if obj.swig_objdecls: 575 for decl in obj.swig_objdecls: 576 print >>out, decl 577 continue 578 579 class_path = obj.cxx_class.split('::') 580 classname = class_path[-1] 581 namespaces = class_path[:-1] 582 namespaces.reverse() 583 584 code = '' 585 586 if namespaces: 587 code += '// avoid name conflicts\n' 588 sep_string = '_COLONS_' 589 flat_name = sep_string.join(class_path) 590 code += '%%rename(%s) %s;\n' % (flat_name, classname) 591 592 code += '// stop swig from creating/wrapping default ctor/dtor\n' 593 code += '%%nodefault %s;\n' % classname 594 code += 'class %s ' % classname 595 if obj._base: 596 code += ': public %s' % obj._base.cxx_class 597 code += ' {};\n' 598 599 for ns in namespaces: 600 new_code = 'namespace %s {\n' % ns 601 new_code += code 602 new_code += '}\n' 603 code = new_code 604 605 print >>out, code 606 607 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj 608 for obj in ordered_objs: 609 print >>out, '%%include "params/%s.hh"' % obj 610 611params_file = File('params/params.i') 612names = sorted(sim_objects.keys()) 613env.Command(params_file, map(Value, names), buildParams) 614env.Depends(params_file, params_hh_files + params_i_files + depends) 615SwigSource('m5.objects', params_file) 616 617# Build all swig modules 618for swig in SwigSource.all: 619 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 620 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 621 '-o ${TARGETS[0]} $SOURCES') 622 env.Depends(swig.py_source.tnode, swig.tnode) 623 env.Depends(swig.cc_source.tnode, swig.tnode) 624 625# Generate the main swig init file 626def makeSwigInit(target, source, env): 627 f = file(str(target[0]), 'w') 628 print >>f, 'extern "C" {' 629 for module in source: 630 print >>f, ' void init_%s();' % module.get_contents() 631 print >>f, '}' 632 print >>f, 'void initSwig() {' 633 for module in source: 634 print >>f, ' init_%s();' % module.get_contents() 635 print >>f, '}' 636 f.close() 637 638env.Command('python/swig/init.cc', 639 map(Value, sorted(s.module for s in SwigSource.all)), 640 makeSwigInit) 641Source('python/swig/init.cc') 642 643def getFlags(source_flags): 644 flagsMap = {} 645 flagsList = [] 646 for s in source_flags: 647 val = eval(s.get_contents()) 648 name, compound, desc = val 649 flagsList.append(val) 650 flagsMap[name] = bool(compound) 651 652 for name, compound, desc in flagsList: 653 for flag in compound: 654 if flag not in flagsMap: 655 raise AttributeError, "Trace flag %s not found" % flag 656 if flagsMap[flag]: 657 raise AttributeError, \ 658 "Compound flag can't point to another compound flag" 659 660 flagsList.sort() 661 return flagsList 662 663 664# Generate traceflags.py 665def traceFlagsPy(target, source, env): 666 assert(len(target) == 1) 667 668 f = file(str(target[0]), 'w') 669 670 allFlags = getFlags(source) 671 672 print >>f, 'basic = [' 673 for flag, compound, desc in allFlags: 674 if not compound: 675 print >>f, " '%s'," % flag 676 print >>f, " ]" 677 print >>f 678 679 print >>f, 'compound = [' 680 print >>f, " 'All'," 681 for flag, compound, desc in allFlags: 682 if compound: 683 print >>f, " '%s'," % flag 684 print >>f, " ]" 685 print >>f 686 687 print >>f, "all = frozenset(basic + compound)" 688 print >>f 689 690 print >>f, 'compoundMap = {' 691 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 692 print >>f, " 'All' : %s," % (all, ) 693 for flag, compound, desc in allFlags: 694 if compound: 695 print >>f, " '%s' : %s," % (flag, compound) 696 print >>f, " }" 697 print >>f 698 699 print >>f, 'descriptions = {' 700 print >>f, " 'All' : 'All flags'," 701 for flag, compound, desc in allFlags: 702 print >>f, " '%s' : '%s'," % (flag, desc) 703 print >>f, " }" 704 705 f.close() 706 707def traceFlagsCC(target, source, env): 708 assert(len(target) == 1) 709 710 f = file(str(target[0]), 'w') 711 712 allFlags = getFlags(source) 713 714 # file header 715 print >>f, ''' 716/* 717 * DO NOT EDIT THIS FILE! Automatically generated 718 */ 719 720#include "base/traceflags.hh" 721 722using namespace Trace; 723 724const char *Trace::flagStrings[] = 725{''' 726 727 # The string array is used by SimpleEnumParam to map the strings 728 # provided by the user to enum values. 729 for flag, compound, desc in allFlags: 730 if not compound: 731 print >>f, ' "%s",' % flag 732 733 print >>f, ' "All",' 734 for flag, compound, desc in allFlags: 735 if compound: 736 print >>f, ' "%s",' % flag 737 738 print >>f, '};' 739 print >>f 740 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1) 741 print >>f 742 743 # 744 # Now define the individual compound flag arrays. There is an array 745 # for each compound flag listing the component base flags. 746 # 747 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 748 print >>f, 'static const Flags AllMap[] = {' 749 for flag, compound, desc in allFlags: 750 if not compound: 751 print >>f, " %s," % flag 752 print >>f, '};' 753 print >>f 754 755 for flag, compound, desc in allFlags: 756 if not compound: 757 continue 758 print >>f, 'static const Flags %sMap[] = {' % flag 759 for flag in compound: 760 print >>f, " %s," % flag 761 print >>f, " (Flags)-1" 762 print >>f, '};' 763 print >>f 764 765 # 766 # Finally the compoundFlags[] array maps the compound flags 767 # to their individual arrays/ 768 # 769 print >>f, 'const Flags *Trace::compoundFlags[] =' 770 print >>f, '{' 771 print >>f, ' AllMap,' 772 for flag, compound, desc in allFlags: 773 if compound: 774 print >>f, ' %sMap,' % flag 775 # file trailer 776 print >>f, '};' 777 778 f.close() 779 780def traceFlagsHH(target, source, env): 781 assert(len(target) == 1) 782 783 f = file(str(target[0]), 'w') 784 785 allFlags = getFlags(source) 786 787 # file header boilerplate 788 print >>f, ''' 789/* 790 * DO NOT EDIT THIS FILE! 791 * 792 * Automatically generated from traceflags.py 793 */ 794 795#ifndef __BASE_TRACE_FLAGS_HH__ 796#define __BASE_TRACE_FLAGS_HH__ 797 798namespace Trace { 799 800enum Flags {''' 801 802 # Generate the enum. Base flags come first, then compound flags. 803 idx = 0 804 for flag, compound, desc in allFlags: 805 if not compound: 806 print >>f, ' %s = %d,' % (flag, idx) 807 idx += 1 808 809 numBaseFlags = idx 810 print >>f, ' NumFlags = %d,' % idx 811 812 # put a comment in here to separate base from compound flags 813 print >>f, ''' 814// The remaining enum values are *not* valid indices for Trace::flags. 815// They are "compound" flags, which correspond to sets of base 816// flags, and are used by changeFlag.''' 817 818 print >>f, ' All = %d,' % idx 819 idx += 1 820 for flag, compound, desc in allFlags: 821 if compound: 822 print >>f, ' %s = %d,' % (flag, idx) 823 idx += 1 824 825 numCompoundFlags = idx - numBaseFlags 826 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags 827 828 # trailer boilerplate 829 print >>f, '''\ 830}; // enum Flags 831 832// Array of strings for SimpleEnumParam 833extern const char *flagStrings[]; 834extern const int numFlagStrings; 835 836// Array of arraay pointers: for each compound flag, gives the list of 837// base flags to set. Inidividual flag arrays are terminated by -1. 838extern const Flags *compoundFlags[]; 839 840/* namespace Trace */ } 841 842#endif // __BASE_TRACE_FLAGS_HH__ 843''' 844 845 f.close() 846 847flags = map(Value, trace_flags.values()) 848env.Command('base/traceflags.py', flags, traceFlagsPy) 849PySource('m5', 'base/traceflags.py') 850 851env.Command('base/traceflags.hh', flags, traceFlagsHH) 852env.Command('base/traceflags.cc', flags, traceFlagsCC) 853Source('base/traceflags.cc') 854 855# embed python files. All .py files that have been indicated by a 856# PySource() call in a SConscript need to be embedded into the M5 857# library. To do that, we compile the file to byte code, marshal the 858# byte code, compress it, and then generate an assembly file that 859# inserts the result into the data section with symbols indicating the 860# beginning, and end (and with the size at the end) 861def objectifyPyFile(target, source, env): 862 '''Action function to compile a .py into a code object, marshal 863 it, compress it, and stick it into an asm file so the code appears 864 as just bytes with a label in the data section''' 865 866 src = file(str(source[0]), 'r').read() 867 dst = file(str(target[0]), 'w') 868 869 pysource = PySource.tnodes[source[0]] 870 compiled = compile(src, pysource.debugname, 'exec') 871 marshalled = marshal.dumps(compiled) 872 compressed = zlib.compress(marshalled) 873 data = compressed 874 875 # Some C/C++ compilers prepend an underscore to global symbol 876 # names, so if they're going to do that, we need to prepend that 877 # leading underscore to globals in the assembly file. 878 if env['LEADING_UNDERSCORE']: 879 sym = '_' + pysource.symname 880 else: 881 sym = pysource.symname 882 883 step = 16 884 print >>dst, ".data" 885 print >>dst, ".globl %s_beg" % sym 886 print >>dst, ".globl %s_end" % sym 887 print >>dst, "%s_beg:" % sym 888 for i in xrange(0, len(data), step): 889 x = array.array('B', data[i:i+step]) 890 print >>dst, ".byte", ','.join([str(d) for d in x]) 891 print >>dst, "%s_end:" % sym 892 print >>dst, ".long %d" % len(marshalled) 893 894for source in PySource.all: 895 env.Command(source.assembly, source.tnode, objectifyPyFile) 896 Source(source.assembly) 897 898# Generate init_python.cc which creates a bunch of EmbeddedPyModule 899# structs that describe the embedded python code. One such struct 900# contains information about the importer that python uses to get at 901# the embedded files, and then there's a list of all of the rest that 902# the importer uses to load the rest on demand. 903def pythonInit(target, source, env): 904 dst = file(str(target[0]), 'w') 905 906 def dump_mod(sym, endchar=','): 907 pysource = PySource.symnames[sym] 908 print >>dst, ' { "%s",' % pysource.arcname 909 print >>dst, ' "%s",' % pysource.modpath 910 print >>dst, ' %s_beg, %s_end,' % (sym, sym) 911 print >>dst, ' %s_end - %s_beg,' % (sym, sym) 912 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar) 913 914 print >>dst, '#include "sim/init.hh"' 915 916 for sym in source: 917 sym = sym.get_contents() 918 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym) 919 920 print >>dst, "const EmbeddedPyModule embeddedPyImporter = " 921 dump_mod("PyEMB_importer", endchar=';'); 922 print >>dst 923 924 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {" 925 for i,sym in enumerate(source): 926 sym = sym.get_contents() 927 if sym == "PyEMB_importer": 928 # Skip the importer since we've already exported it 929 continue 930 dump_mod(sym) 931 print >>dst, " { 0, 0, 0, 0, 0, 0 }" 932 print >>dst, "};" 933 934 935env.Command('sim/init_python.cc', 936 map(Value, (s.symname for s in PySource.all)), 937 pythonInit) 938Source('sim/init_python.cc') 939 940######################################################################## 941# 942# Define binaries. Each different build type (debug, opt, etc.) gets 943# a slightly different build environment. 944# 945 946# List of constructed environments to pass back to SConstruct 947envList = [] 948 949date_source = Source('base/date.cc', skip_lib=True) 950 951# Function to create a new build environment as clone of current 952# environment 'env' with modified object suffix and optional stripped 953# binary. Additional keyword arguments are appended to corresponding 954# build environment vars. 955def makeEnv(label, objsfx, strip = False, **kwargs): 956 # SCons doesn't know to append a library suffix when there is a '.' in the 957 # name. Use '_' instead. 958 libname = 'm5_' + label 959 exename = 'm5.' + label 960 961 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 962 new_env.Label = label 963 new_env.Append(**kwargs) 964 965 swig_env = new_env.Clone() 966 swig_env.Append(CCFLAGS='-Werror') 967 if env['GCC']: 968 swig_env.Append(CCFLAGS='-Wno-uninitialized') 969 swig_env.Append(CCFLAGS='-Wno-sign-compare') 970 swig_env.Append(CCFLAGS='-Wno-parentheses') 971 972 werror_env = new_env.Clone() 973 werror_env.Append(CCFLAGS='-Werror') 974 975 def make_obj(source, static, extra_deps = None): 976 '''This function adds the specified source to the correct 977 build environment, and returns the corresponding SCons Object 978 nodes''' 979 980 if source.swig: 981 env = swig_env 982 elif source.Werror: 983 env = werror_env 984 else: 985 env = new_env 986 987 if static: 988 obj = env.StaticObject(source.tnode) 989 else: 990 obj = env.SharedObject(source.tnode) 991 992 if extra_deps: 993 env.Depends(obj, extra_deps) 994 995 return obj 996 997 static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)] 998 shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)] 999 1000 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 1001 static_objs.append(static_date) 1002 1003 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 1004 shared_objs.append(shared_date) 1005 1006 # First make a library of everything but main() so other programs can 1007 # link against m5. 1008 static_lib = new_env.StaticLibrary(libname, static_objs) 1009 shared_lib = new_env.SharedLibrary(libname, shared_objs) 1010 1011 for target, sources in unit_tests: 1012 objs = [ make_obj(s, static=True) for s in sources ] 1013 new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs) 1014 1015 # Now link a stub with main() and the static library. 1016 bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ] 1017 progname = exename 1018 if strip: 1019 progname += '.unstripped' 1020 1021 targets = new_env.Program(progname, bin_objs + static_objs) 1022 1023 if strip: 1024 if sys.platform == 'sunos5': 1025 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 1026 else: 1027 cmd = 'strip $SOURCE -o $TARGET' 1028 targets = new_env.Command(exename, progname, cmd) 1029 1030 new_env.M5Binary = targets[0] 1031 envList.append(new_env) 1032 1033# Debug binary 1034ccflags = {} 1035if env['GCC']: 1036 if sys.platform == 'sunos5': 1037 ccflags['debug'] = '-gstabs+' 1038 else: 1039 ccflags['debug'] = '-ggdb3' 1040 ccflags['opt'] = '-g -O3' 1041 ccflags['fast'] = '-O3' 1042 ccflags['prof'] = '-O3 -g -pg' 1043elif env['SUNCC']: 1044 ccflags['debug'] = '-g0' 1045 ccflags['opt'] = '-g -O' 1046 ccflags['fast'] = '-fast' 1047 ccflags['prof'] = '-fast -g -pg' 1048elif env['ICC']: 1049 ccflags['debug'] = '-g -O0' 1050 ccflags['opt'] = '-g -O' 1051 ccflags['fast'] = '-fast' 1052 ccflags['prof'] = '-fast -g -pg' 1053else: 1054 print 'Unknown compiler, please fix compiler options' 1055 Exit(1) 1056 1057makeEnv('debug', '.do', 1058 CCFLAGS = Split(ccflags['debug']), 1059 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 1060 1061# Optimized binary 1062makeEnv('opt', '.o', 1063 CCFLAGS = Split(ccflags['opt']), 1064 CPPDEFINES = ['TRACING_ON=1']) 1065 1066# "Fast" binary 1067makeEnv('fast', '.fo', strip = True, 1068 CCFLAGS = Split(ccflags['fast']), 1069 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 1070 1071# Profiled binary 1072makeEnv('prof', '.po', 1073 CCFLAGS = Split(ccflags['prof']), 1074 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1075 LINKFLAGS = '-pg') 1076 1077Return('envList') 1078