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