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