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