SConscript revision 6654
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 if isinstance(param, m5.params.VectorParamDesc): 493 ext = 'vptype' 494 else: 495 ext = 'ptype' 496 497 i_file = File('params/%s_%s.i' % (name, ext)) 498 params_i_files.append(i_file) 499 env.Command(i_file, Value(name), createSwigParam) 500 env.Depends(i_file, depends) 501 502# Generate all enum header files 503for name,enum in sorted(all_enums.iteritems()): 504 py_source = PySource.modules[enum.__module__] 505 extra_deps = [ py_source.tnode ] 506 507 cc_file = File('enums/%s.cc' % name) 508 env.Command(cc_file, Value(name), createEnumStrings) 509 env.Depends(cc_file, depends + extra_deps) 510 Source(cc_file) 511 512 hh_file = File('enums/%s.hh' % name) 513 env.Command(hh_file, Value(name), createEnumParam) 514 env.Depends(hh_file, depends + extra_deps) 515 516# Build the big monolithic swigged params module (wraps all SimObject 517# param structs and enum structs) 518def buildParams(target, source, env): 519 names = [ s.get_contents() for s in source ] 520 objs = [ sim_objects[name] for name in names ] 521 out = file(target[0].abspath, 'w') 522 523 ordered_objs = [] 524 obj_seen = set() 525 def order_obj(obj): 526 name = str(obj) 527 if name in obj_seen: 528 return 529 530 obj_seen.add(name) 531 if str(obj) != 'SimObject': 532 order_obj(obj.__bases__[0]) 533 534 ordered_objs.append(obj) 535 536 for obj in objs: 537 order_obj(obj) 538 539 enums = set() 540 predecls = [] 541 pd_seen = set() 542 543 def add_pds(*pds): 544 for pd in pds: 545 if pd not in pd_seen: 546 predecls.append(pd) 547 pd_seen.add(pd) 548 549 for obj in ordered_objs: 550 params = obj._params.local.values() 551 for param in params: 552 ptype = param.ptype 553 if issubclass(ptype, m5.params.Enum): 554 if ptype not in enums: 555 enums.add(ptype) 556 pds = param.swig_predecls() 557 if isinstance(pds, (list, tuple)): 558 add_pds(*pds) 559 else: 560 add_pds(pds) 561 562 print >>out, '%module params' 563 564 print >>out, '%{' 565 for obj in ordered_objs: 566 print >>out, '#include "params/%s.hh"' % obj 567 print >>out, '%}' 568 569 for pd in predecls: 570 print >>out, pd 571 572 enums = list(enums) 573 enums.sort() 574 for enum in enums: 575 print >>out, '%%include "enums/%s.hh"' % enum.__name__ 576 print >>out 577 578 for obj in ordered_objs: 579 if obj.swig_objdecls: 580 for decl in obj.swig_objdecls: 581 print >>out, decl 582 continue 583 584 class_path = obj.cxx_class.split('::') 585 classname = class_path[-1] 586 namespaces = class_path[:-1] 587 namespaces.reverse() 588 589 code = '' 590 591 if namespaces: 592 code += '// avoid name conflicts\n' 593 sep_string = '_COLONS_' 594 flat_name = sep_string.join(class_path) 595 code += '%%rename(%s) %s;\n' % (flat_name, classname) 596 597 code += '// stop swig from creating/wrapping default ctor/dtor\n' 598 code += '%%nodefault %s;\n' % classname 599 code += 'class %s ' % classname 600 if obj._base: 601 code += ': public %s' % obj._base.cxx_class 602 code += ' {};\n' 603 604 for ns in namespaces: 605 new_code = 'namespace %s {\n' % ns 606 new_code += code 607 new_code += '}\n' 608 code = new_code 609 610 print >>out, code 611 612 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj 613 for obj in ordered_objs: 614 print >>out, '%%include "params/%s.hh"' % obj 615 616params_file = File('params/params.i') 617names = sorted(sim_objects.keys()) 618env.Command(params_file, map(Value, names), buildParams) 619env.Depends(params_file, params_hh_files + params_i_files + depends) 620SwigSource('m5.objects', params_file) 621 622# Build all swig modules 623for swig in SwigSource.all: 624 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 625 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 626 '-o ${TARGETS[0]} $SOURCES') 627 env.Depends(swig.py_source.tnode, swig.tnode) 628 env.Depends(swig.cc_source.tnode, swig.tnode) 629 630# Generate the main swig init file 631def makeSwigInit(target, source, env): 632 f = file(str(target[0]), 'w') 633 print >>f, 'extern "C" {' 634 for module in source: 635 print >>f, ' void init_%s();' % module.get_contents() 636 print >>f, '}' 637 print >>f, 'void initSwig() {' 638 for module in source: 639 print >>f, ' init_%s();' % module.get_contents() 640 print >>f, '}' 641 f.close() 642 643env.Command('python/swig/init.cc', 644 map(Value, sorted(s.module for s in SwigSource.all)), 645 makeSwigInit) 646Source('python/swig/init.cc') 647 648def getFlags(source_flags): 649 flagsMap = {} 650 flagsList = [] 651 for s in source_flags: 652 val = eval(s.get_contents()) 653 name, compound, desc = val 654 flagsList.append(val) 655 flagsMap[name] = bool(compound) 656 657 for name, compound, desc in flagsList: 658 for flag in compound: 659 if flag not in flagsMap: 660 raise AttributeError, "Trace flag %s not found" % flag 661 if flagsMap[flag]: 662 raise AttributeError, \ 663 "Compound flag can't point to another compound flag" 664 665 flagsList.sort() 666 return flagsList 667 668 669# Generate traceflags.py 670def traceFlagsPy(target, source, env): 671 assert(len(target) == 1) 672 673 f = file(str(target[0]), 'w') 674 675 allFlags = getFlags(source) 676 677 print >>f, 'basic = [' 678 for flag, compound, desc in allFlags: 679 if not compound: 680 print >>f, " '%s'," % flag 681 print >>f, " ]" 682 print >>f 683 684 print >>f, 'compound = [' 685 print >>f, " 'All'," 686 for flag, compound, desc in allFlags: 687 if compound: 688 print >>f, " '%s'," % flag 689 print >>f, " ]" 690 print >>f 691 692 print >>f, "all = frozenset(basic + compound)" 693 print >>f 694 695 print >>f, 'compoundMap = {' 696 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 697 print >>f, " 'All' : %s," % (all, ) 698 for flag, compound, desc in allFlags: 699 if compound: 700 print >>f, " '%s' : %s," % (flag, compound) 701 print >>f, " }" 702 print >>f 703 704 print >>f, 'descriptions = {' 705 print >>f, " 'All' : 'All flags'," 706 for flag, compound, desc in allFlags: 707 print >>f, " '%s' : '%s'," % (flag, desc) 708 print >>f, " }" 709 710 f.close() 711 712def traceFlagsCC(target, source, env): 713 assert(len(target) == 1) 714 715 f = file(str(target[0]), 'w') 716 717 allFlags = getFlags(source) 718 719 # file header 720 print >>f, ''' 721/* 722 * DO NOT EDIT THIS FILE! Automatically generated 723 */ 724 725#include "base/traceflags.hh" 726 727using namespace Trace; 728 729const char *Trace::flagStrings[] = 730{''' 731 732 # The string array is used by SimpleEnumParam to map the strings 733 # provided by the user to enum values. 734 for flag, compound, desc in allFlags: 735 if not compound: 736 print >>f, ' "%s",' % flag 737 738 print >>f, ' "All",' 739 for flag, compound, desc in allFlags: 740 if compound: 741 print >>f, ' "%s",' % flag 742 743 print >>f, '};' 744 print >>f 745 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1) 746 print >>f 747 748 # 749 # Now define the individual compound flag arrays. There is an array 750 # for each compound flag listing the component base flags. 751 # 752 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 753 print >>f, 'static const Flags AllMap[] = {' 754 for flag, compound, desc in allFlags: 755 if not compound: 756 print >>f, " %s," % flag 757 print >>f, '};' 758 print >>f 759 760 for flag, compound, desc in allFlags: 761 if not compound: 762 continue 763 print >>f, 'static const Flags %sMap[] = {' % flag 764 for flag in compound: 765 print >>f, " %s," % flag 766 print >>f, " (Flags)-1" 767 print >>f, '};' 768 print >>f 769 770 # 771 # Finally the compoundFlags[] array maps the compound flags 772 # to their individual arrays/ 773 # 774 print >>f, 'const Flags *Trace::compoundFlags[] =' 775 print >>f, '{' 776 print >>f, ' AllMap,' 777 for flag, compound, desc in allFlags: 778 if compound: 779 print >>f, ' %sMap,' % flag 780 # file trailer 781 print >>f, '};' 782 783 f.close() 784 785def traceFlagsHH(target, source, env): 786 assert(len(target) == 1) 787 788 f = file(str(target[0]), 'w') 789 790 allFlags = getFlags(source) 791 792 # file header boilerplate 793 print >>f, ''' 794/* 795 * DO NOT EDIT THIS FILE! 796 * 797 * Automatically generated from traceflags.py 798 */ 799 800#ifndef __BASE_TRACE_FLAGS_HH__ 801#define __BASE_TRACE_FLAGS_HH__ 802 803namespace Trace { 804 805enum Flags {''' 806 807 # Generate the enum. Base flags come first, then compound flags. 808 idx = 0 809 for flag, compound, desc in allFlags: 810 if not compound: 811 print >>f, ' %s = %d,' % (flag, idx) 812 idx += 1 813 814 numBaseFlags = idx 815 print >>f, ' NumFlags = %d,' % idx 816 817 # put a comment in here to separate base from compound flags 818 print >>f, ''' 819// The remaining enum values are *not* valid indices for Trace::flags. 820// They are "compound" flags, which correspond to sets of base 821// flags, and are used by changeFlag.''' 822 823 print >>f, ' All = %d,' % idx 824 idx += 1 825 for flag, compound, desc in allFlags: 826 if compound: 827 print >>f, ' %s = %d,' % (flag, idx) 828 idx += 1 829 830 numCompoundFlags = idx - numBaseFlags 831 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags 832 833 # trailer boilerplate 834 print >>f, '''\ 835}; // enum Flags 836 837// Array of strings for SimpleEnumParam 838extern const char *flagStrings[]; 839extern const int numFlagStrings; 840 841// Array of arraay pointers: for each compound flag, gives the list of 842// base flags to set. Inidividual flag arrays are terminated by -1. 843extern const Flags *compoundFlags[]; 844 845/* namespace Trace */ } 846 847#endif // __BASE_TRACE_FLAGS_HH__ 848''' 849 850 f.close() 851 852flags = map(Value, trace_flags.values()) 853env.Command('base/traceflags.py', flags, traceFlagsPy) 854PySource('m5', 'base/traceflags.py') 855 856env.Command('base/traceflags.hh', flags, traceFlagsHH) 857env.Command('base/traceflags.cc', flags, traceFlagsCC) 858Source('base/traceflags.cc') 859 860# embed python files. All .py files that have been indicated by a 861# PySource() call in a SConscript need to be embedded into the M5 862# library. To do that, we compile the file to byte code, marshal the 863# byte code, compress it, and then generate an assembly file that 864# inserts the result into the data section with symbols indicating the 865# beginning, and end (and with the size at the end) 866def objectifyPyFile(target, source, env): 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 dst = file(str(target[0]), 'w') 873 874 pysource = PySource.tnodes[source[0]] 875 compiled = compile(src, pysource.debugname, 'exec') 876 marshalled = marshal.dumps(compiled) 877 compressed = zlib.compress(marshalled) 878 data = compressed 879 880 # Some C/C++ compilers prepend an underscore to global symbol 881 # names, so if they're going to do that, we need to prepend that 882 # leading underscore to globals in the assembly file. 883 if env['LEADING_UNDERSCORE']: 884 sym = '_' + pysource.symname 885 else: 886 sym = pysource.symname 887 888 step = 16 889 print >>dst, ".data" 890 print >>dst, ".globl %s_beg" % sym 891 print >>dst, ".globl %s_end" % sym 892 print >>dst, "%s_beg:" % sym 893 for i in xrange(0, len(data), step): 894 x = array.array('B', data[i:i+step]) 895 print >>dst, ".byte", ','.join([str(d) for d in x]) 896 print >>dst, "%s_end:" % sym 897 print >>dst, ".long %d" % len(marshalled) 898 899for source in PySource.all: 900 env.Command(source.assembly, source.tnode, objectifyPyFile) 901 Source(source.assembly) 902 903# Generate init_python.cc which creates a bunch of EmbeddedPyModule 904# structs that describe the embedded python code. One such struct 905# contains information about the importer that python uses to get at 906# the embedded files, and then there's a list of all of the rest that 907# the importer uses to load the rest on demand. 908def pythonInit(target, source, env): 909 dst = file(str(target[0]), 'w') 910 911 def dump_mod(sym, endchar=','): 912 pysource = PySource.symnames[sym] 913 print >>dst, ' { "%s",' % pysource.arcname 914 print >>dst, ' "%s",' % pysource.modpath 915 print >>dst, ' %s_beg, %s_end,' % (sym, sym) 916 print >>dst, ' %s_end - %s_beg,' % (sym, sym) 917 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar) 918 919 print >>dst, '#include "sim/init.hh"' 920 921 for sym in source: 922 sym = sym.get_contents() 923 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym) 924 925 print >>dst, "const EmbeddedPyModule embeddedPyImporter = " 926 dump_mod("PyEMB_importer", endchar=';'); 927 print >>dst 928 929 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {" 930 for i,sym in enumerate(source): 931 sym = sym.get_contents() 932 if sym == "PyEMB_importer": 933 # Skip the importer since we've already exported it 934 continue 935 dump_mod(sym) 936 print >>dst, " { 0, 0, 0, 0, 0, 0 }" 937 print >>dst, "};" 938 939 940env.Command('sim/init_python.cc', 941 map(Value, (s.symname for s in PySource.all)), 942 pythonInit) 943Source('sim/init_python.cc') 944 945######################################################################## 946# 947# Define binaries. Each different build type (debug, opt, etc.) gets 948# a slightly different build environment. 949# 950 951# List of constructed environments to pass back to SConstruct 952envList = [] 953 954date_source = Source('base/date.cc', skip_lib=True) 955 956# Function to create a new build environment as clone of current 957# environment 'env' with modified object suffix and optional stripped 958# binary. Additional keyword arguments are appended to corresponding 959# build environment vars. 960def makeEnv(label, objsfx, strip = False, **kwargs): 961 # SCons doesn't know to append a library suffix when there is a '.' in the 962 # name. Use '_' instead. 963 libname = 'm5_' + label 964 exename = 'm5.' + label 965 966 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 967 new_env.Label = label 968 new_env.Append(**kwargs) 969 970 swig_env = new_env.Clone() 971 swig_env.Append(CCFLAGS='-Werror') 972 if env['GCC']: 973 swig_env.Append(CCFLAGS='-Wno-uninitialized') 974 swig_env.Append(CCFLAGS='-Wno-sign-compare') 975 swig_env.Append(CCFLAGS='-Wno-parentheses') 976 977 werror_env = new_env.Clone() 978 werror_env.Append(CCFLAGS='-Werror') 979 980 def make_obj(source, static, extra_deps = None): 981 '''This function adds the specified source to the correct 982 build environment, and returns the corresponding SCons Object 983 nodes''' 984 985 if source.swig: 986 env = swig_env 987 elif source.Werror: 988 env = werror_env 989 else: 990 env = new_env 991 992 if static: 993 obj = env.StaticObject(source.tnode) 994 else: 995 obj = env.SharedObject(source.tnode) 996 997 if extra_deps: 998 env.Depends(obj, extra_deps) 999 1000 return obj 1001 1002 static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)] 1003 shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)] 1004 1005 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 1006 static_objs.append(static_date) 1007 1008 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 1009 shared_objs.append(shared_date) 1010 1011 # First make a library of everything but main() so other programs can 1012 # link against m5. 1013 static_lib = new_env.StaticLibrary(libname, static_objs) 1014 shared_lib = new_env.SharedLibrary(libname, shared_objs) 1015 1016 for target, sources in unit_tests: 1017 objs = [ make_obj(s, static=True) for s in sources ] 1018 new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs) 1019 1020 # Now link a stub with main() and the static library. 1021 bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ] 1022 progname = exename 1023 if strip: 1024 progname += '.unstripped' 1025 1026 targets = new_env.Program(progname, bin_objs + static_objs) 1027 1028 if strip: 1029 if sys.platform == 'sunos5': 1030 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 1031 else: 1032 cmd = 'strip $SOURCE -o $TARGET' 1033 targets = new_env.Command(exename, progname, cmd) 1034 1035 new_env.M5Binary = targets[0] 1036 envList.append(new_env) 1037 1038# Debug binary 1039ccflags = {} 1040if env['GCC']: 1041 if sys.platform == 'sunos5': 1042 ccflags['debug'] = '-gstabs+' 1043 else: 1044 ccflags['debug'] = '-ggdb3' 1045 ccflags['opt'] = '-g -O3' 1046 ccflags['fast'] = '-O3' 1047 ccflags['prof'] = '-O3 -g -pg' 1048elif env['SUNCC']: 1049 ccflags['debug'] = '-g0' 1050 ccflags['opt'] = '-g -O' 1051 ccflags['fast'] = '-fast' 1052 ccflags['prof'] = '-fast -g -pg' 1053elif env['ICC']: 1054 ccflags['debug'] = '-g -O0' 1055 ccflags['opt'] = '-g -O' 1056 ccflags['fast'] = '-fast' 1057 ccflags['prof'] = '-fast -g -pg' 1058else: 1059 print 'Unknown compiler, please fix compiler options' 1060 Exit(1) 1061 1062makeEnv('debug', '.do', 1063 CCFLAGS = Split(ccflags['debug']), 1064 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 1065 1066# Optimized binary 1067makeEnv('opt', '.o', 1068 CCFLAGS = Split(ccflags['opt']), 1069 CPPDEFINES = ['TRACING_ON=1']) 1070 1071# "Fast" binary 1072makeEnv('fast', '.fo', strip = True, 1073 CCFLAGS = Split(ccflags['fast']), 1074 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 1075 1076# Profiled binary 1077makeEnv('prof', '.po', 1078 CCFLAGS = Split(ccflags['prof']), 1079 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1080 LINKFLAGS = '-pg') 1081 1082Return('envList') 1083