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