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