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