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