SConscript revision 5793
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# Workaround for bug in SCons version > 0.97d20071212 224# Scons bug id: 2006 M5 Bug id: 308 225for root, dirs, files in os.walk(base_dir, topdown=True): 226 Dir(root[len(base_dir) + 1:]) 227 228######################################################################## 229# 230# Walk the tree and execute all SConscripts in subdirectories 231# 232 233here = Dir('.').srcnode().abspath 234for root, dirs, files in os.walk(base_dir, topdown=True): 235 if root == here: 236 # we don't want to recurse back into this SConscript 237 continue 238 239 if 'SConscript' in files: 240 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 241 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir) 242 243for extra_dir in extras_dir_list: 244 prefix_len = len(dirname(extra_dir)) + 1 245 for root, dirs, files in os.walk(extra_dir, topdown=True): 246 if 'SConscript' in files: 247 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 248 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir) 249 250for opt in env.ExportOptions: 251 env.ConfigFile(opt) 252 253######################################################################## 254# 255# Prevent any SimObjects from being added after this point, they 256# should all have been added in the SConscripts above 257# 258class DictImporter(object): 259 '''This importer takes a dictionary of arbitrary module names that 260 map to arbitrary filenames.''' 261 def __init__(self, modules): 262 self.modules = modules 263 self.installed = set() 264 265 def __del__(self): 266 self.unload() 267 268 def unload(self): 269 import sys 270 for module in self.installed: 271 del sys.modules[module] 272 self.installed = set() 273 274 def find_module(self, fullname, path): 275 if fullname == '__scons': 276 return self 277 278 if fullname == 'm5.objects': 279 return self 280 281 if fullname.startswith('m5.internal'): 282 return None 283 284 if fullname in self.modules and exists(self.modules[fullname]): 285 return self 286 287 return None 288 289 def load_module(self, fullname): 290 mod = imp.new_module(fullname) 291 sys.modules[fullname] = mod 292 self.installed.add(fullname) 293 294 mod.__loader__ = self 295 if fullname == 'm5.objects': 296 mod.__path__ = fullname.split('.') 297 return mod 298 299 if fullname == '__scons': 300 mod.__dict__['m5_build_env'] = build_env 301 return mod 302 303 srcfile = self.modules[fullname] 304 if basename(srcfile) == '__init__.py': 305 mod.__path__ = fullname.split('.') 306 mod.__file__ = srcfile 307 308 exec file(srcfile, 'r') in mod.__dict__ 309 310 return mod 311 312py_modules = {} 313for source in py_sources: 314 py_modules[source.modpath] = source.snode.abspath 315 316# install the python importer so we can grab stuff from the source 317# tree itself. We can't have SimObjects added after this point or 318# else we won't know about them for the rest of the stuff. 319sim_objects_fixed = True 320importer = DictImporter(py_modules) 321sys.meta_path[0:0] = [ importer ] 322 323import m5 324 325# import all sim objects so we can populate the all_objects list 326# make sure that we're working with a list, then let's sort it 327sim_objects = list(sim_object_modfiles) 328sim_objects.sort() 329for simobj in sim_objects: 330 exec('from m5.objects import %s' % simobj) 331 332# we need to unload all of the currently imported modules so that they 333# will be re-imported the next time the sconscript is run 334importer.unload() 335sys.meta_path.remove(importer) 336 337sim_objects = m5.SimObject.allClasses 338all_enums = m5.params.allEnums 339 340all_params = {} 341for name,obj in sim_objects.iteritems(): 342 for param in obj._params.local.values(): 343 if not hasattr(param, 'swig_decl'): 344 continue 345 pname = param.ptype_str 346 if pname not in all_params: 347 all_params[pname] = param 348 349######################################################################## 350# 351# calculate extra dependencies 352# 353module_depends = ["m5", "m5.SimObject", "m5.params"] 354depends = [ File(py_modules[dep]) for dep in module_depends ] 355 356######################################################################## 357# 358# Commands for the basic automatically generated python files 359# 360 361# Generate Python file containing a dict specifying the current 362# build_env flags. 363def makeDefinesPyFile(target, source, env): 364 f = file(str(target[0]), 'w') 365 print >>f, "m5_build_env = ", source[0] 366 f.close() 367 368# Generate python file containing info about the M5 source code 369def makeInfoPyFile(target, source, env): 370 f = file(str(target[0]), 'w') 371 for src in source: 372 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 373 print >>f, "%s = %s" % (src, repr(data)) 374 f.close() 375 376# Generate the __init__.py file for m5.objects 377def makeObjectsInitFile(target, source, env): 378 f = file(str(target[0]), 'w') 379 print >>f, 'from params import *' 380 print >>f, 'from m5.SimObject import *' 381 for module in source: 382 print >>f, 'from %s import *' % module.get_contents() 383 f.close() 384 385# Generate a file with all of the compile options in it 386env.Command('python/m5/defines.py', Value(build_env), makeDefinesPyFile) 387PySource('m5', 'python/m5/defines.py') 388 389# Generate a file that wraps the basic top level files 390env.Command('python/m5/info.py', 391 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], 392 makeInfoPyFile) 393PySource('m5', 'python/m5/info.py') 394 395# Generate an __init__.py file for the objects package 396env.Command('python/m5/objects/__init__.py', 397 [ Value(o) for o in sort_list(sim_object_modfiles) ], 398 makeObjectsInitFile) 399PySource('m5.objects', 'python/m5/objects/__init__.py') 400 401######################################################################## 402# 403# Create all of the SimObject param headers and enum headers 404# 405 406def createSimObjectParam(target, source, env): 407 assert len(target) == 1 and len(source) == 1 408 409 hh_file = file(target[0].abspath, 'w') 410 name = str(source[0].get_contents()) 411 obj = sim_objects[name] 412 413 print >>hh_file, obj.cxx_decl() 414 415def createSwigParam(target, source, env): 416 assert len(target) == 1 and len(source) == 1 417 418 i_file = file(target[0].abspath, 'w') 419 name = str(source[0].get_contents()) 420 param = all_params[name] 421 422 for line in param.swig_decl(): 423 print >>i_file, line 424 425def createEnumStrings(target, source, env): 426 assert len(target) == 1 and len(source) == 1 427 428 cc_file = file(target[0].abspath, 'w') 429 name = str(source[0].get_contents()) 430 obj = all_enums[name] 431 432 print >>cc_file, obj.cxx_def() 433 cc_file.close() 434 435def createEnumParam(target, source, env): 436 assert len(target) == 1 and len(source) == 1 437 438 hh_file = file(target[0].abspath, 'w') 439 name = str(source[0].get_contents()) 440 obj = all_enums[name] 441 442 print >>hh_file, obj.cxx_decl() 443 444# Generate all of the SimObject param struct header files 445params_hh_files = [] 446for name,simobj in sim_objects.iteritems(): 447 extra_deps = [ File(py_modules[simobj.__module__]) ] 448 449 hh_file = File('params/%s.hh' % name) 450 params_hh_files.append(hh_file) 451 env.Command(hh_file, Value(name), createSimObjectParam) 452 env.Depends(hh_file, depends + extra_deps) 453 454# Generate any parameter header files needed 455params_i_files = [] 456for name,param in all_params.iteritems(): 457 if isinstance(param, m5.params.VectorParamDesc): 458 ext = 'vptype' 459 else: 460 ext = 'ptype' 461 462 i_file = File('params/%s_%s.i' % (name, ext)) 463 params_i_files.append(i_file) 464 env.Command(i_file, Value(name), createSwigParam) 465 env.Depends(i_file, depends) 466 467# Generate all enum header files 468for name,enum in all_enums.iteritems(): 469 extra_deps = [ File(py_modules[enum.__module__]) ] 470 471 cc_file = File('enums/%s.cc' % name) 472 env.Command(cc_file, Value(name), createEnumStrings) 473 env.Depends(cc_file, depends + extra_deps) 474 Source(cc_file) 475 476 hh_file = File('enums/%s.hh' % name) 477 env.Command(hh_file, Value(name), createEnumParam) 478 env.Depends(hh_file, depends + extra_deps) 479 480# Build the big monolithic swigged params module (wraps all SimObject 481# param structs and enum structs) 482def buildParams(target, source, env): 483 names = [ s.get_contents() for s in source ] 484 objs = [ sim_objects[name] for name in names ] 485 out = file(target[0].abspath, 'w') 486 487 ordered_objs = [] 488 obj_seen = set() 489 def order_obj(obj): 490 name = str(obj) 491 if name in obj_seen: 492 return 493 494 obj_seen.add(name) 495 if str(obj) != 'SimObject': 496 order_obj(obj.__bases__[0]) 497 498 ordered_objs.append(obj) 499 500 for obj in objs: 501 order_obj(obj) 502 503 enums = set() 504 predecls = [] 505 pd_seen = set() 506 507 def add_pds(*pds): 508 for pd in pds: 509 if pd not in pd_seen: 510 predecls.append(pd) 511 pd_seen.add(pd) 512 513 for obj in ordered_objs: 514 params = obj._params.local.values() 515 for param in params: 516 ptype = param.ptype 517 if issubclass(ptype, m5.params.Enum): 518 if ptype not in enums: 519 enums.add(ptype) 520 pds = param.swig_predecls() 521 if isinstance(pds, (list, tuple)): 522 add_pds(*pds) 523 else: 524 add_pds(pds) 525 526 print >>out, '%module params' 527 528 print >>out, '%{' 529 for obj in ordered_objs: 530 print >>out, '#include "params/%s.hh"' % obj 531 print >>out, '%}' 532 533 for pd in predecls: 534 print >>out, pd 535 536 enums = list(enums) 537 enums.sort() 538 for enum in enums: 539 print >>out, '%%include "enums/%s.hh"' % enum.__name__ 540 print >>out 541 542 for obj in ordered_objs: 543 if obj.swig_objdecls: 544 for decl in obj.swig_objdecls: 545 print >>out, decl 546 continue 547 548 class_path = obj.cxx_class.split('::') 549 classname = class_path[-1] 550 namespaces = class_path[:-1] 551 namespaces.reverse() 552 553 code = '' 554 555 if namespaces: 556 code += '// avoid name conflicts\n' 557 sep_string = '_COLONS_' 558 flat_name = sep_string.join(class_path) 559 code += '%%rename(%s) %s;\n' % (flat_name, classname) 560 561 code += '// stop swig from creating/wrapping default ctor/dtor\n' 562 code += '%%nodefault %s;\n' % classname 563 code += 'class %s ' % classname 564 if obj._base: 565 code += ': public %s' % obj._base.cxx_class 566 code += ' {};\n' 567 568 for ns in namespaces: 569 new_code = 'namespace %s {\n' % ns 570 new_code += code 571 new_code += '}\n' 572 code = new_code 573 574 print >>out, code 575 576 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj 577 for obj in ordered_objs: 578 print >>out, '%%include "params/%s.hh"' % obj 579 580params_file = File('params/params.i') 581names = sort_list(sim_objects.keys()) 582env.Command(params_file, [ Value(v) for v in names ], buildParams) 583env.Depends(params_file, params_hh_files + params_i_files + depends) 584SwigSource('m5.objects', params_file) 585 586# Build all swig modules 587swig_modules = [] 588cc_swig_sources = [] 589for source,package in swig_sources: 590 filename = str(source) 591 assert filename.endswith('.i') 592 593 base = '.'.join(filename.split('.')[:-1]) 594 module = basename(base) 595 cc_file = base + '_wrap.cc' 596 py_file = base + '.py' 597 598 env.Command([cc_file, py_file], source, 599 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 600 '-o ${TARGETS[0]} $SOURCES') 601 env.Depends(py_file, source) 602 env.Depends(cc_file, source) 603 604 swig_modules.append(Value(module)) 605 cc_swig_sources.append(File(cc_file)) 606 PySource(package, py_file) 607 608# Generate the main swig init file 609def makeSwigInit(target, source, env): 610 f = file(str(target[0]), 'w') 611 print >>f, 'extern "C" {' 612 for module in source: 613 print >>f, ' void init_%s();' % module.get_contents() 614 print >>f, '}' 615 print >>f, 'void initSwig() {' 616 for module in source: 617 print >>f, ' init_%s();' % module.get_contents() 618 print >>f, '}' 619 f.close() 620 621env.Command('python/swig/init.cc', swig_modules, makeSwigInit) 622Source('python/swig/init.cc') 623 624# Generate traceflags.py 625def traceFlagsPy(target, source, env): 626 assert(len(target) == 1) 627 628 f = file(str(target[0]), 'w') 629 630 allFlags = [] 631 for s in source: 632 val = eval(s.get_contents()) 633 allFlags.append(val) 634 635 print >>f, 'baseFlags = [' 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, 'compoundFlags = [' 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, "allFlags = frozenset(baseFlags + compoundFlags)" 651 print >>f 652 653 print >>f, 'compoundFlagMap = {' 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, 'flagDescriptions = {' 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 ] 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# Generate program_info.cc 825def programInfo(target, source, env): 826 def gen_file(target, rev, node, date): 827 pi_stats = file(target, 'w') 828 print >>pi_stats, 'const char *hgRev = "%s:%s";' % (rev, node) 829 print >>pi_stats, 'const char *hgDate = "%s";' % date 830 pi_stats.close() 831 832 target = str(target[0]) 833 scons_dir = str(source[0].get_contents()) 834 try: 835 import mercurial.demandimport, mercurial.hg, mercurial.ui 836 import mercurial.util, mercurial.node 837 if not exists(scons_dir) or not isdir(scons_dir) or \ 838 not exists(joinpath(scons_dir, ".hg")): 839 raise ValueError 840 repo = mercurial.hg.repository(mercurial.ui.ui(), scons_dir) 841 rev = mercurial.node.nullrev + repo.changelog.count() 842 changenode = repo.changelog.node(rev) 843 changes = repo.changelog.read(changenode) 844 date = mercurial.util.datestr(changes[2]) 845 846 gen_file(target, rev, mercurial.node.hex(changenode), date) 847 848 mercurial.demandimport.disable() 849 except ImportError: 850 gen_file(target, "Unknown", "Unknown", "Unknown") 851 852 except: 853 print "in except" 854 gen_file(target, "Unknown", "Unknown", "Unknown") 855 mercurial.demandimport.disable() 856 857env.Command('base/program_info.cc', 858 Value(str(SCons.Node.FS.default_fs.SConstruct_dir)), 859 programInfo) 860 861# embed python files. All .py files that have been indicated by a 862# PySource() call in a SConscript need to be embedded into the M5 863# library. To do that, we compile the file to byte code, marshal the 864# byte code, compress it, and then generate an assembly file that 865# inserts the result into the data section with symbols indicating the 866# beginning, and end (and with the size at the end) 867py_sources_tnodes = {} 868for pysource in py_sources: 869 py_sources_tnodes[pysource.tnode] = pysource 870 871def objectifyPyFile(target, source, env): 872 '''Action function to compile a .py into a code object, marshal 873 it, compress it, and stick it into an asm file so the code appears 874 as just bytes with a label in the data section''' 875 876 src = file(str(source[0]), 'r').read() 877 dst = file(str(target[0]), 'w') 878 879 pysource = py_sources_tnodes[source[0]] 880 compiled = compile(src, pysource.debugname, 'exec') 881 marshalled = marshal.dumps(compiled) 882 compressed = zlib.compress(marshalled) 883 data = compressed 884 885 # Some C/C++ compilers prepend an underscore to global symbol 886 # names, so if they're going to do that, we need to prepend that 887 # leading underscore to globals in the assembly file. 888 if env['LEADING_UNDERSCORE']: 889 sym = '_' + pysource.symname 890 else: 891 sym = pysource.symname 892 893 step = 16 894 print >>dst, ".data" 895 print >>dst, ".globl %s_beg" % sym 896 print >>dst, ".globl %s_end" % sym 897 print >>dst, "%s_beg:" % sym 898 for i in xrange(0, len(data), step): 899 x = array.array('B', data[i:i+step]) 900 print >>dst, ".byte", ','.join([str(d) for d in x]) 901 print >>dst, "%s_end:" % sym 902 print >>dst, ".long %d" % len(marshalled) 903 904for source in py_sources: 905 env.Command(source.assembly, source.tnode, objectifyPyFile) 906 Source(source.assembly) 907 908# Generate init_python.cc which creates a bunch of EmbeddedPyModule 909# structs that describe the embedded python code. One such struct 910# contains information about the importer that python uses to get at 911# the embedded files, and then there's a list of all of the rest that 912# the importer uses to load the rest on demand. 913py_sources_symbols = {} 914for pysource in py_sources: 915 py_sources_symbols[pysource.symname] = pysource 916def pythonInit(target, source, env): 917 dst = file(str(target[0]), 'w') 918 919 def dump_mod(sym, endchar=','): 920 pysource = py_sources_symbols[sym] 921 print >>dst, ' { "%s",' % pysource.arcname 922 print >>dst, ' "%s",' % pysource.modpath 923 print >>dst, ' %s_beg, %s_end,' % (sym, sym) 924 print >>dst, ' %s_end - %s_beg,' % (sym, sym) 925 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar) 926 927 print >>dst, '#include "sim/init.hh"' 928 929 for sym in source: 930 sym = sym.get_contents() 931 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym) 932 933 print >>dst, "const EmbeddedPyModule embeddedPyImporter = " 934 dump_mod("PyEMB_importer", endchar=';'); 935 print >>dst 936 937 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {" 938 for i,sym in enumerate(source): 939 sym = sym.get_contents() 940 if sym == "PyEMB_importer": 941 # Skip the importer since we've already exported it 942 continue 943 dump_mod(sym) 944 print >>dst, " { 0, 0, 0, 0, 0, 0 }" 945 print >>dst, "};" 946 947symbols = [Value(s.symname) for s in py_sources] 948env.Command('sim/init_python.cc', symbols, pythonInit) 949Source('sim/init_python.cc') 950 951######################################################################## 952# 953# Define binaries. Each different build type (debug, opt, etc.) gets 954# a slightly different build environment. 955# 956 957# List of constructed environments to pass back to SConstruct 958envList = [] 959 960# This function adds the specified sources to the given build 961# environment, and returns a list of all the corresponding SCons 962# Object nodes (including an extra one for date.cc). We explicitly 963# add the Object nodes so we can set up special dependencies for 964# date.cc. 965def make_objs(sources, env, static): 966 if static: 967 XObject = env.StaticObject 968 else: 969 XObject = env.SharedObject 970 971 objs = [ XObject(s) for s in sources ] 972 973 # make date.cc depend on all other objects so it always gets 974 # recompiled whenever anything else does 975 date_obj = XObject('base/date.cc') 976 977 # Make the generation of program_info.cc dependend on all 978 # the other cc files and the compiling of program_info.cc 979 # dependent on all the objects but program_info.o 980 pinfo_obj = XObject('base/program_info.cc') 981 env.Depends('base/program_info.cc', sources) 982 env.Depends(date_obj, objs) 983 env.Depends(pinfo_obj, objs) 984 objs.extend([date_obj, pinfo_obj]) 985 return objs 986 987# Function to create a new build environment as clone of current 988# environment 'env' with modified object suffix and optional stripped 989# binary. Additional keyword arguments are appended to corresponding 990# build environment vars. 991def makeEnv(label, objsfx, strip = False, **kwargs): 992 # SCons doesn't know to append a library suffix when there is a '.' in the 993 # name. Use '_' instead. 994 libname = 'm5_' + label 995 exename = 'm5.' + label 996 997 new_env = env.Copy(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 998 new_env.Label = label 999 new_env.Append(**kwargs) 1000 1001 swig_env = new_env.Copy() 1002 if env['GCC']: 1003 swig_env.Append(CCFLAGS='-Wno-uninitialized') 1004 swig_env.Append(CCFLAGS='-Wno-sign-compare') 1005 swig_env.Append(CCFLAGS='-Wno-parentheses') 1006 1007 static_objs = make_objs(cc_lib_sources, new_env, static=True) 1008 shared_objs = make_objs(cc_lib_sources, new_env, static=False) 1009 static_objs += [ swig_env.StaticObject(s) for s in cc_swig_sources ] 1010 shared_objs += [ swig_env.SharedObject(s) for s in cc_swig_sources ] 1011 1012 # First make a library of everything but main() so other programs can 1013 # link against m5. 1014 static_lib = new_env.StaticLibrary(libname, static_objs + static_objs) 1015 shared_lib = new_env.SharedLibrary(libname, shared_objs + shared_objs) 1016 1017 for target, sources in unit_tests: 1018 objs = [ new_env.StaticObject(s) for s in sources ] 1019 new_env.Program("unittest/%s.%s" % (target, label), objs + static_lib) 1020 1021 # Now link a stub with main() and the static library. 1022 objects = [new_env.Object(s) for s in cc_bin_sources] + static_lib 1023 if strip: 1024 unstripped_exe = exename + '.unstripped' 1025 new_env.Program(unstripped_exe, objects) 1026 if sys.platform == 'sunos5': 1027 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 1028 else: 1029 cmd = 'strip $SOURCE -o $TARGET' 1030 targets = new_env.Command(exename, unstripped_exe, cmd) 1031 else: 1032 targets = new_env.Program(exename, objects) 1033 1034 new_env.M5Binary = targets[0] 1035 envList.append(new_env) 1036 1037# Debug binary 1038ccflags = {} 1039if env['GCC']: 1040 if sys.platform == 'sunos5': 1041 ccflags['debug'] = '-gstabs+' 1042 else: 1043 ccflags['debug'] = '-ggdb3' 1044 ccflags['opt'] = '-g -O3' 1045 ccflags['fast'] = '-O3' 1046 ccflags['prof'] = '-O3 -g -pg' 1047elif env['SUNCC']: 1048 ccflags['debug'] = '-g0' 1049 ccflags['opt'] = '-g -O' 1050 ccflags['fast'] = '-fast' 1051 ccflags['prof'] = '-fast -g -pg' 1052elif env['ICC']: 1053 ccflags['debug'] = '-g -O0' 1054 ccflags['opt'] = '-g -O' 1055 ccflags['fast'] = '-fast' 1056 ccflags['prof'] = '-fast -g -pg' 1057else: 1058 print 'Unknown compiler, please fix compiler options' 1059 Exit(1) 1060 1061makeEnv('debug', '.do', 1062 CCFLAGS = Split(ccflags['debug']), 1063 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 1064 1065# Optimized binary 1066makeEnv('opt', '.o', 1067 CCFLAGS = Split(ccflags['opt']), 1068 CPPDEFINES = ['TRACING_ON=1']) 1069 1070# "Fast" binary 1071makeEnv('fast', '.fo', strip = True, 1072 CCFLAGS = Split(ccflags['fast']), 1073 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 1074 1075# Profiled binary 1076makeEnv('prof', '.po', 1077 CCFLAGS = Split(ccflags['prof']), 1078 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1079 LINKFLAGS = '-pg') 1080 1081Return('envList') 1082