SConscript revision 5784
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.ExportOptions]) 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# 178all_flags = {} 179trace_flags = [] 180def TraceFlag(name, desc=''): 181 if name in all_flags: 182 raise AttributeError, "Flag %s already specified" % name 183 flag = (name, (), desc) 184 trace_flags.append(flag) 185 all_flags[name] = () 186 187def CompoundFlag(name, flags, desc=''): 188 if name in all_flags: 189 raise AttributeError, "Flag %s already specified" % name 190 191 compound = tuple(flags) 192 for flag in compound: 193 if flag not in all_flags: 194 raise AttributeError, "Trace flag %s not found" % flag 195 if all_flags[flag]: 196 raise AttributeError, \ 197 "Compound flag can't point to another compound flag" 198 199 flag = (name, compound, desc) 200 trace_flags.append(flag) 201 all_flags[name] = compound 202 203Export('TraceFlag') 204Export('CompoundFlag') 205 206######################################################################## 207# 208# Set some compiler variables 209# 210 211# Include file paths are rooted in this directory. SCons will 212# automatically expand '.' to refer to both the source directory and 213# the corresponding build directory to pick up generated include 214# files. 215env.Append(CPPPATH=Dir('.')) 216 217for extra_dir in extras_dir_list: 218 env.Append(CPPPATH=Dir(extra_dir)) 219 220# Add a flag defining what THE_ISA should be for all compilation 221env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) 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.ExportOptions: 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 == '__scons': 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 == '__scons': 295 mod.__dict__['m5_build_env'] = 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 print >>f, "m5_build_env = ", source[0] 361 f.close() 362 363# Generate python file containing info about the M5 source code 364def makeInfoPyFile(target, source, env): 365 f = file(str(target[0]), 'w') 366 for src in source: 367 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 368 print >>f, "%s = %s" % (src, repr(data)) 369 f.close() 370 371# Generate the __init__.py file for m5.objects 372def makeObjectsInitFile(target, source, env): 373 f = file(str(target[0]), 'w') 374 print >>f, 'from params import *' 375 print >>f, 'from m5.SimObject import *' 376 for module in source: 377 print >>f, 'from %s import *' % module.get_contents() 378 f.close() 379 380# Generate a file with all of the compile options in it 381env.Command('python/m5/defines.py', Value(build_env), makeDefinesPyFile) 382PySource('m5', 'python/m5/defines.py') 383 384# Generate a file that wraps the basic top level files 385env.Command('python/m5/info.py', 386 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], 387 makeInfoPyFile) 388PySource('m5', 'python/m5/info.py') 389 390# Generate an __init__.py file for the objects package 391env.Command('python/m5/objects/__init__.py', 392 [ Value(o) for o in sort_list(sim_object_modfiles) ], 393 makeObjectsInitFile) 394PySource('m5.objects', 'python/m5/objects/__init__.py') 395 396######################################################################## 397# 398# Create all of the SimObject param headers and enum headers 399# 400 401def createSimObjectParam(target, source, env): 402 assert len(target) == 1 and len(source) == 1 403 404 hh_file = file(target[0].abspath, 'w') 405 name = str(source[0].get_contents()) 406 obj = sim_objects[name] 407 408 print >>hh_file, obj.cxx_decl() 409 410def createSwigParam(target, source, env): 411 assert len(target) == 1 and len(source) == 1 412 413 i_file = file(target[0].abspath, 'w') 414 name = str(source[0].get_contents()) 415 param = all_params[name] 416 417 for line in param.swig_decl(): 418 print >>i_file, line 419 420def createEnumStrings(target, source, env): 421 assert len(target) == 1 and len(source) == 1 422 423 cc_file = file(target[0].abspath, 'w') 424 name = str(source[0].get_contents()) 425 obj = all_enums[name] 426 427 print >>cc_file, obj.cxx_def() 428 cc_file.close() 429 430def createEnumParam(target, source, env): 431 assert len(target) == 1 and len(source) == 1 432 433 hh_file = file(target[0].abspath, 'w') 434 name = str(source[0].get_contents()) 435 obj = all_enums[name] 436 437 print >>hh_file, obj.cxx_decl() 438 439# Generate all of the SimObject param struct header files 440params_hh_files = [] 441for name,simobj in sim_objects.iteritems(): 442 extra_deps = [ File(py_modules[simobj.__module__]) ] 443 444 hh_file = File('params/%s.hh' % name) 445 params_hh_files.append(hh_file) 446 env.Command(hh_file, Value(name), createSimObjectParam) 447 env.Depends(hh_file, depends + extra_deps) 448 449# Generate any parameter header files needed 450params_i_files = [] 451for name,param in all_params.iteritems(): 452 if isinstance(param, m5.params.VectorParamDesc): 453 ext = 'vptype' 454 else: 455 ext = 'ptype' 456 457 i_file = File('params/%s_%s.i' % (name, ext)) 458 params_i_files.append(i_file) 459 env.Command(i_file, Value(name), createSwigParam) 460 env.Depends(i_file, depends) 461 462# Generate all enum header files 463for name,enum in all_enums.iteritems(): 464 extra_deps = [ File(py_modules[enum.__module__]) ] 465 466 cc_file = File('enums/%s.cc' % name) 467 env.Command(cc_file, Value(name), createEnumStrings) 468 env.Depends(cc_file, depends + extra_deps) 469 Source(cc_file) 470 471 hh_file = File('enums/%s.hh' % name) 472 env.Command(hh_file, Value(name), createEnumParam) 473 env.Depends(hh_file, depends + extra_deps) 474 475# Build the big monolithic swigged params module (wraps all SimObject 476# param structs and enum structs) 477def buildParams(target, source, env): 478 names = [ s.get_contents() for s in source ] 479 objs = [ sim_objects[name] for name in names ] 480 out = file(target[0].abspath, 'w') 481 482 ordered_objs = [] 483 obj_seen = set() 484 def order_obj(obj): 485 name = str(obj) 486 if name in obj_seen: 487 return 488 489 obj_seen.add(name) 490 if str(obj) != 'SimObject': 491 order_obj(obj.__bases__[0]) 492 493 ordered_objs.append(obj) 494 495 for obj in objs: 496 order_obj(obj) 497 498 enums = set() 499 predecls = [] 500 pd_seen = set() 501 502 def add_pds(*pds): 503 for pd in pds: 504 if pd not in pd_seen: 505 predecls.append(pd) 506 pd_seen.add(pd) 507 508 for obj in ordered_objs: 509 params = obj._params.local.values() 510 for param in params: 511 ptype = param.ptype 512 if issubclass(ptype, m5.params.Enum): 513 if ptype not in enums: 514 enums.add(ptype) 515 pds = param.swig_predecls() 516 if isinstance(pds, (list, tuple)): 517 add_pds(*pds) 518 else: 519 add_pds(pds) 520 521 print >>out, '%module params' 522 523 print >>out, '%{' 524 for obj in ordered_objs: 525 print >>out, '#include "params/%s.hh"' % obj 526 print >>out, '%}' 527 528 for pd in predecls: 529 print >>out, pd 530 531 enums = list(enums) 532 enums.sort() 533 for enum in enums: 534 print >>out, '%%include "enums/%s.hh"' % enum.__name__ 535 print >>out 536 537 for obj in ordered_objs: 538 if obj.swig_objdecls: 539 for decl in obj.swig_objdecls: 540 print >>out, decl 541 continue 542 543 class_path = obj.cxx_class.split('::') 544 classname = class_path[-1] 545 namespaces = class_path[:-1] 546 namespaces.reverse() 547 548 code = '' 549 550 if namespaces: 551 code += '// avoid name conflicts\n' 552 sep_string = '_COLONS_' 553 flat_name = sep_string.join(class_path) 554 code += '%%rename(%s) %s;\n' % (flat_name, classname) 555 556 code += '// stop swig from creating/wrapping default ctor/dtor\n' 557 code += '%%nodefault %s;\n' % classname 558 code += 'class %s ' % classname 559 if obj._base: 560 code += ': public %s' % obj._base.cxx_class 561 code += ' {};\n' 562 563 for ns in namespaces: 564 new_code = 'namespace %s {\n' % ns 565 new_code += code 566 new_code += '}\n' 567 code = new_code 568 569 print >>out, code 570 571 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj 572 for obj in ordered_objs: 573 print >>out, '%%include "params/%s.hh"' % obj 574 575params_file = File('params/params.i') 576names = sort_list(sim_objects.keys()) 577env.Command(params_file, [ Value(v) for v in names ], buildParams) 578env.Depends(params_file, params_hh_files + params_i_files + depends) 579SwigSource('m5.objects', params_file) 580 581# Build all swig modules 582swig_modules = [] 583cc_swig_sources = [] 584for source,package in swig_sources: 585 filename = str(source) 586 assert filename.endswith('.i') 587 588 base = '.'.join(filename.split('.')[:-1]) 589 module = basename(base) 590 cc_file = base + '_wrap.cc' 591 py_file = base + '.py' 592 593 env.Command([cc_file, py_file], source, 594 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 595 '-o ${TARGETS[0]} $SOURCES') 596 env.Depends(py_file, source) 597 env.Depends(cc_file, source) 598 599 swig_modules.append(Value(module)) 600 cc_swig_sources.append(File(cc_file)) 601 PySource(package, py_file) 602 603# Generate the main swig init file 604def makeSwigInit(target, source, env): 605 f = file(str(target[0]), 'w') 606 print >>f, 'extern "C" {' 607 for module in source: 608 print >>f, ' void init_%s();' % module.get_contents() 609 print >>f, '}' 610 print >>f, 'void initSwig() {' 611 for module in source: 612 print >>f, ' init_%s();' % module.get_contents() 613 print >>f, '}' 614 f.close() 615 616env.Command('python/swig/init.cc', swig_modules, makeSwigInit) 617Source('python/swig/init.cc') 618 619# Generate traceflags.py 620def traceFlagsPy(target, source, env): 621 assert(len(target) == 1) 622 623 f = file(str(target[0]), 'w') 624 625 allFlags = [] 626 for s in source: 627 val = eval(s.get_contents()) 628 allFlags.append(val) 629 630 print >>f, 'baseFlags = [' 631 for flag, compound, desc in allFlags: 632 if not compound: 633 print >>f, " '%s'," % flag 634 print >>f, " ]" 635 print >>f 636 637 print >>f, 'compoundFlags = [' 638 print >>f, " 'All'," 639 for flag, compound, desc in allFlags: 640 if compound: 641 print >>f, " '%s'," % flag 642 print >>f, " ]" 643 print >>f 644 645 print >>f, "allFlags = frozenset(baseFlags + compoundFlags)" 646 print >>f 647 648 print >>f, 'compoundFlagMap = {' 649 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 650 print >>f, " 'All' : %s," % (all, ) 651 for flag, compound, desc in allFlags: 652 if compound: 653 print >>f, " '%s' : %s," % (flag, compound) 654 print >>f, " }" 655 print >>f 656 657 print >>f, 'flagDescriptions = {' 658 print >>f, " 'All' : 'All flags'," 659 for flag, compound, desc in allFlags: 660 print >>f, " '%s' : '%s'," % (flag, desc) 661 print >>f, " }" 662 663 f.close() 664 665def traceFlagsCC(target, source, env): 666 assert(len(target) == 1) 667 668 f = file(str(target[0]), 'w') 669 670 allFlags = [] 671 for s in source: 672 val = eval(s.get_contents()) 673 allFlags.append(val) 674 675 # file header 676 print >>f, ''' 677/* 678 * DO NOT EDIT THIS FILE! Automatically generated 679 */ 680 681#include "base/traceflags.hh" 682 683using namespace Trace; 684 685const char *Trace::flagStrings[] = 686{''' 687 688 # The string array is used by SimpleEnumParam to map the strings 689 # provided by the user to enum values. 690 for flag, compound, desc in allFlags: 691 if not compound: 692 print >>f, ' "%s",' % flag 693 694 print >>f, ' "All",' 695 for flag, compound, desc in allFlags: 696 if compound: 697 print >>f, ' "%s",' % flag 698 699 print >>f, '};' 700 print >>f 701 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1) 702 print >>f 703 704 # 705 # Now define the individual compound flag arrays. There is an array 706 # for each compound flag listing the component base flags. 707 # 708 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 709 print >>f, 'static const Flags AllMap[] = {' 710 for flag, compound, desc in allFlags: 711 if not compound: 712 print >>f, " %s," % flag 713 print >>f, '};' 714 print >>f 715 716 for flag, compound, desc in allFlags: 717 if not compound: 718 continue 719 print >>f, 'static const Flags %sMap[] = {' % flag 720 for flag in compound: 721 print >>f, " %s," % flag 722 print >>f, " (Flags)-1" 723 print >>f, '};' 724 print >>f 725 726 # 727 # Finally the compoundFlags[] array maps the compound flags 728 # to their individual arrays/ 729 # 730 print >>f, 'const Flags *Trace::compoundFlags[] =' 731 print >>f, '{' 732 print >>f, ' AllMap,' 733 for flag, compound, desc in allFlags: 734 if compound: 735 print >>f, ' %sMap,' % flag 736 # file trailer 737 print >>f, '};' 738 739 f.close() 740 741def traceFlagsHH(target, source, env): 742 assert(len(target) == 1) 743 744 f = file(str(target[0]), 'w') 745 746 allFlags = [] 747 for s in source: 748 val = eval(s.get_contents()) 749 allFlags.append(val) 750 751 # file header boilerplate 752 print >>f, ''' 753/* 754 * DO NOT EDIT THIS FILE! 755 * 756 * Automatically generated from traceflags.py 757 */ 758 759#ifndef __BASE_TRACE_FLAGS_HH__ 760#define __BASE_TRACE_FLAGS_HH__ 761 762namespace Trace { 763 764enum Flags {''' 765 766 # Generate the enum. Base flags come first, then compound flags. 767 idx = 0 768 for flag, compound, desc in allFlags: 769 if not compound: 770 print >>f, ' %s = %d,' % (flag, idx) 771 idx += 1 772 773 numBaseFlags = idx 774 print >>f, ' NumFlags = %d,' % idx 775 776 # put a comment in here to separate base from compound flags 777 print >>f, ''' 778// The remaining enum values are *not* valid indices for Trace::flags. 779// They are "compound" flags, which correspond to sets of base 780// flags, and are used by changeFlag.''' 781 782 print >>f, ' All = %d,' % idx 783 idx += 1 784 for flag, compound, desc in allFlags: 785 if compound: 786 print >>f, ' %s = %d,' % (flag, idx) 787 idx += 1 788 789 numCompoundFlags = idx - numBaseFlags 790 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags 791 792 # trailer boilerplate 793 print >>f, '''\ 794}; // enum Flags 795 796// Array of strings for SimpleEnumParam 797extern const char *flagStrings[]; 798extern const int numFlagStrings; 799 800// Array of arraay pointers: for each compound flag, gives the list of 801// base flags to set. Inidividual flag arrays are terminated by -1. 802extern const Flags *compoundFlags[]; 803 804/* namespace Trace */ } 805 806#endif // __BASE_TRACE_FLAGS_HH__ 807''' 808 809 f.close() 810 811flags = [ Value(f) for f in trace_flags ] 812env.Command('base/traceflags.py', flags, traceFlagsPy) 813PySource('m5', 'base/traceflags.py') 814 815env.Command('base/traceflags.hh', flags, traceFlagsHH) 816env.Command('base/traceflags.cc', flags, traceFlagsCC) 817Source('base/traceflags.cc') 818 819# Generate program_info.cc 820def programInfo(target, source, env): 821 def gen_file(target, rev, node, date): 822 pi_stats = file(target, 'w') 823 print >>pi_stats, 'const char *hgRev = "%s:%s";' % (rev, node) 824 print >>pi_stats, 'const char *hgDate = "%s";' % date 825 pi_stats.close() 826 827 target = str(target[0]) 828 scons_dir = str(source[0].get_contents()) 829 try: 830 import mercurial.demandimport, mercurial.hg, mercurial.ui 831 import mercurial.util, mercurial.node 832 if not exists(scons_dir) or not isdir(scons_dir) or \ 833 not exists(joinpath(scons_dir, ".hg")): 834 raise ValueError 835 repo = mercurial.hg.repository(mercurial.ui.ui(), scons_dir) 836 rev = mercurial.node.nullrev + repo.changelog.count() 837 changenode = repo.changelog.node(rev) 838 changes = repo.changelog.read(changenode) 839 date = mercurial.util.datestr(changes[2]) 840 841 gen_file(target, rev, mercurial.node.hex(changenode), date) 842 843 mercurial.demandimport.disable() 844 except ImportError: 845 gen_file(target, "Unknown", "Unknown", "Unknown") 846 847 except: 848 print "in except" 849 gen_file(target, "Unknown", "Unknown", "Unknown") 850 mercurial.demandimport.disable() 851 852env.Command('base/program_info.cc', 853 Value(str(SCons.Node.FS.default_fs.SConstruct_dir)), 854 programInfo) 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 an assembly file that 860# inserts the result into the data section with symbols indicating the 861# beginning, and end (and with the size at the end) 862py_sources_tnodes = {} 863for pysource in py_sources: 864 py_sources_tnodes[pysource.tnode] = pysource 865 866def objectifyPyFile(target, source, env): 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 dst = file(str(target[0]), 'w') 873 874 pysource = py_sources_tnodes[source[0]] 875 compiled = compile(src, pysource.debugname, 'exec') 876 marshalled = marshal.dumps(compiled) 877 compressed = zlib.compress(marshalled) 878 data = compressed 879 880 # Some C/C++ compilers prepend an underscore to global symbol 881 # names, so if they're going to do that, we need to prepend that 882 # leading underscore to globals in the assembly file. 883 if env['LEADING_UNDERSCORE']: 884 sym = '_' + pysource.symname 885 else: 886 sym = pysource.symname 887 888 step = 16 889 print >>dst, ".data" 890 print >>dst, ".globl %s_beg" % sym 891 print >>dst, ".globl %s_end" % sym 892 print >>dst, "%s_beg:" % sym 893 for i in xrange(0, len(data), step): 894 x = array.array('B', data[i:i+step]) 895 print >>dst, ".byte", ','.join([str(d) for d in x]) 896 print >>dst, "%s_end:" % sym 897 print >>dst, ".long %d" % len(marshalled) 898 899for source in py_sources: 900 env.Command(source.assembly, source.tnode, objectifyPyFile) 901 Source(source.assembly) 902 903# Generate init_python.cc which creates a bunch of EmbeddedPyModule 904# structs that describe the embedded python code. One such struct 905# contains information about the importer that python uses to get at 906# the embedded files, and then there's a list of all of the rest that 907# the importer uses to load the rest on demand. 908py_sources_symbols = {} 909for pysource in py_sources: 910 py_sources_symbols[pysource.symname] = pysource 911def pythonInit(target, source, env): 912 dst = file(str(target[0]), 'w') 913 914 def dump_mod(sym, endchar=','): 915 pysource = py_sources_symbols[sym] 916 print >>dst, ' { "%s",' % pysource.arcname 917 print >>dst, ' "%s",' % pysource.modpath 918 print >>dst, ' %s_beg, %s_end,' % (sym, sym) 919 print >>dst, ' %s_end - %s_beg,' % (sym, sym) 920 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar) 921 922 print >>dst, '#include "sim/init.hh"' 923 924 for sym in source: 925 sym = sym.get_contents() 926 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym) 927 928 print >>dst, "const EmbeddedPyModule embeddedPyImporter = " 929 dump_mod("PyEMB_importer", endchar=';'); 930 print >>dst 931 932 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {" 933 for i,sym in enumerate(source): 934 sym = sym.get_contents() 935 if sym == "PyEMB_importer": 936 # Skip the importer since we've already exported it 937 continue 938 dump_mod(sym) 939 print >>dst, " { 0, 0, 0, 0, 0, 0 }" 940 print >>dst, "};" 941 942symbols = [Value(s.symname) for s in py_sources] 943env.Command('sim/init_python.cc', symbols, pythonInit) 944Source('sim/init_python.cc') 945 946######################################################################## 947# 948# Define binaries. Each different build type (debug, opt, etc.) gets 949# a slightly different build environment. 950# 951 952# List of constructed environments to pass back to SConstruct 953envList = [] 954 955# This function adds the specified sources to the given build 956# environment, and returns a list of all the corresponding SCons 957# Object nodes (including an extra one for date.cc). We explicitly 958# add the Object nodes so we can set up special dependencies for 959# date.cc. 960def make_objs(sources, env, static): 961 if static: 962 XObject = env.StaticObject 963 else: 964 XObject = env.SharedObject 965 966 objs = [ XObject(s) for s in sources ] 967 968 # make date.cc depend on all other objects so it always gets 969 # recompiled whenever anything else does 970 date_obj = XObject('base/date.cc') 971 972 # Make the generation of program_info.cc dependend on all 973 # the other cc files and the compiling of program_info.cc 974 # dependent on all the objects but program_info.o 975 pinfo_obj = XObject('base/program_info.cc') 976 env.Depends('base/program_info.cc', sources) 977 env.Depends(date_obj, objs) 978 env.Depends(pinfo_obj, objs) 979 objs.extend([date_obj, pinfo_obj]) 980 return objs 981 982# Function to create a new build environment as clone of current 983# environment 'env' with modified object suffix and optional stripped 984# binary. Additional keyword arguments are appended to corresponding 985# build environment vars. 986def makeEnv(label, objsfx, strip = False, **kwargs): 987 # SCons doesn't know to append a library suffix when there is a '.' in the 988 # name. Use '_' instead. 989 libname = 'm5_' + label 990 exename = 'm5.' + label 991 992 new_env = env.Copy(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 993 new_env.Label = label 994 new_env.Append(**kwargs) 995 996 swig_env = new_env.Copy() 997 if env['GCC']: 998 swig_env.Append(CCFLAGS='-Wno-uninitialized') 999 swig_env.Append(CCFLAGS='-Wno-sign-compare') 1000 swig_env.Append(CCFLAGS='-Wno-parentheses') 1001 1002 static_objs = make_objs(cc_lib_sources, new_env, static=True) 1003 shared_objs = make_objs(cc_lib_sources, new_env, static=False) 1004 static_objs += [ swig_env.StaticObject(s) for s in cc_swig_sources ] 1005 shared_objs += [ swig_env.SharedObject(s) for s in cc_swig_sources ] 1006 1007 # First make a library of everything but main() so other programs can 1008 # link against m5. 1009 static_lib = new_env.StaticLibrary(libname, static_objs + static_objs) 1010 shared_lib = new_env.SharedLibrary(libname, shared_objs + shared_objs) 1011 1012 for target, sources in unit_tests: 1013 objs = [ new_env.StaticObject(s) for s in sources ] 1014 new_env.Program("unittest/%s.%s" % (target, label), objs + static_lib) 1015 1016 # Now link a stub with main() and the static library. 1017 objects = [new_env.Object(s) for s in cc_bin_sources] + static_lib 1018 if strip: 1019 unstripped_exe = exename + '.unstripped' 1020 new_env.Program(unstripped_exe, objects) 1021 if sys.platform == 'sunos5': 1022 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 1023 else: 1024 cmd = 'strip $SOURCE -o $TARGET' 1025 targets = new_env.Command(exename, unstripped_exe, cmd) 1026 else: 1027 targets = new_env.Program(exename, objects) 1028 1029 new_env.M5Binary = targets[0] 1030 envList.append(new_env) 1031 1032# Debug binary 1033ccflags = {} 1034if env['GCC']: 1035 if sys.platform == 'sunos5': 1036 ccflags['debug'] = '-gstabs+' 1037 else: 1038 ccflags['debug'] = '-ggdb3' 1039 ccflags['opt'] = '-g -O3' 1040 ccflags['fast'] = '-O3' 1041 ccflags['prof'] = '-O3 -g -pg' 1042elif env['SUNCC']: 1043 ccflags['debug'] = '-g0' 1044 ccflags['opt'] = '-g -O' 1045 ccflags['fast'] = '-fast' 1046 ccflags['prof'] = '-fast -g -pg' 1047elif env['ICC']: 1048 ccflags['debug'] = '-g -O0' 1049 ccflags['opt'] = '-g -O' 1050 ccflags['fast'] = '-fast' 1051 ccflags['prof'] = '-fast -g -pg' 1052else: 1053 print 'Unknown compiler, please fix compiler options' 1054 Exit(1) 1055 1056makeEnv('debug', '.do', 1057 CCFLAGS = Split(ccflags['debug']), 1058 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 1059 1060# Optimized binary 1061makeEnv('opt', '.o', 1062 CCFLAGS = Split(ccflags['opt']), 1063 CPPDEFINES = ['TRACING_ON=1']) 1064 1065# "Fast" binary 1066makeEnv('fast', '.fo', strip = True, 1067 CCFLAGS = Split(ccflags['fast']), 1068 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 1069 1070# Profiled binary 1071makeEnv('prof', '.po', 1072 CCFLAGS = Split(ccflags['prof']), 1073 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1074 LINKFLAGS = '-pg') 1075 1076Return('envList') 1077