SConscript revision 5522
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 = [] 546for source,package in swig_sources: 547 filename = str(source) 548 assert filename.endswith('.i') 549 550 base = '.'.join(filename.split('.')[:-1]) 551 module = basename(base) 552 cc_file = base + '_wrap.cc' 553 py_file = base + '.py' 554 555 env.Command([cc_file, py_file], source, 556 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 557 '-o ${TARGETS[0]} $SOURCES') 558 env.Depends(py_file, source) 559 env.Depends(cc_file, source) 560 561 swig_modules.append(Value(module)) 562 Source(cc_file) 563 PySource(package, py_file) 564 565# Generate the main swig init file 566def makeSwigInit(target, source, env): 567 f = file(str(target[0]), 'w') 568 print >>f, 'extern "C" {' 569 for module in source: 570 print >>f, ' void init_%s();' % module.get_contents() 571 print >>f, '}' 572 print >>f, 'void initSwig() {' 573 for module in source: 574 print >>f, ' init_%s();' % module.get_contents() 575 print >>f, '}' 576 f.close() 577 578env.Command('python/swig/init.cc', swig_modules, makeSwigInit) 579Source('python/swig/init.cc') 580 581# Generate traceflags.py 582def traceFlagsPy(target, source, env): 583 assert(len(target) == 1) 584 585 f = file(str(target[0]), 'w') 586 587 allFlags = [] 588 for s in source: 589 val = eval(s.get_contents()) 590 allFlags.append(val) 591 592 print >>f, 'baseFlags = [' 593 for flag, compound, desc in allFlags: 594 if not compound: 595 print >>f, " '%s'," % flag 596 print >>f, " ]" 597 print >>f 598 599 print >>f, 'compoundFlags = [' 600 print >>f, " 'All'," 601 for flag, compound, desc in allFlags: 602 if compound: 603 print >>f, " '%s'," % flag 604 print >>f, " ]" 605 print >>f 606 607 print >>f, "allFlags = frozenset(baseFlags + compoundFlags)" 608 print >>f 609 610 print >>f, 'compoundFlagMap = {' 611 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 612 print >>f, " 'All' : %s," % (all, ) 613 for flag, compound, desc in allFlags: 614 if compound: 615 print >>f, " '%s' : %s," % (flag, compound) 616 print >>f, " }" 617 print >>f 618 619 print >>f, 'flagDescriptions = {' 620 print >>f, " 'All' : 'All flags'," 621 for flag, compound, desc in allFlags: 622 print >>f, " '%s' : '%s'," % (flag, desc) 623 print >>f, " }" 624 625 f.close() 626 627def traceFlagsCC(target, source, env): 628 assert(len(target) == 1) 629 630 f = file(str(target[0]), 'w') 631 632 allFlags = [] 633 for s in source: 634 val = eval(s.get_contents()) 635 allFlags.append(val) 636 637 # file header 638 print >>f, ''' 639/* 640 * DO NOT EDIT THIS FILE! Automatically generated 641 */ 642 643#include "base/traceflags.hh" 644 645using namespace Trace; 646 647const char *Trace::flagStrings[] = 648{''' 649 650 # The string array is used by SimpleEnumParam to map the strings 651 # provided by the user to enum values. 652 for flag, compound, desc in allFlags: 653 if not compound: 654 print >>f, ' "%s",' % flag 655 656 print >>f, ' "All",' 657 for flag, compound, desc in allFlags: 658 if compound: 659 print >>f, ' "%s",' % flag 660 661 print >>f, '};' 662 print >>f 663 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1) 664 print >>f 665 666 # 667 # Now define the individual compound flag arrays. There is an array 668 # for each compound flag listing the component base flags. 669 # 670 all = tuple([flag for flag,compound,desc in allFlags if not compound]) 671 print >>f, 'static const Flags AllMap[] = {' 672 for flag, compound, desc in allFlags: 673 if not compound: 674 print >>f, " %s," % flag 675 print >>f, '};' 676 print >>f 677 678 for flag, compound, desc in allFlags: 679 if not compound: 680 continue 681 print >>f, 'static const Flags %sMap[] = {' % flag 682 for flag in compound: 683 print >>f, " %s," % flag 684 print >>f, " (Flags)-1" 685 print >>f, '};' 686 print >>f 687 688 # 689 # Finally the compoundFlags[] array maps the compound flags 690 # to their individual arrays/ 691 # 692 print >>f, 'const Flags *Trace::compoundFlags[] =' 693 print >>f, '{' 694 print >>f, ' AllMap,' 695 for flag, compound, desc in allFlags: 696 if compound: 697 print >>f, ' %sMap,' % flag 698 # file trailer 699 print >>f, '};' 700 701 f.close() 702 703def traceFlagsHH(target, source, env): 704 assert(len(target) == 1) 705 706 f = file(str(target[0]), 'w') 707 708 allFlags = [] 709 for s in source: 710 val = eval(s.get_contents()) 711 allFlags.append(val) 712 713 # file header boilerplate 714 print >>f, ''' 715/* 716 * DO NOT EDIT THIS FILE! 717 * 718 * Automatically generated from traceflags.py 719 */ 720 721#ifndef __BASE_TRACE_FLAGS_HH__ 722#define __BASE_TRACE_FLAGS_HH__ 723 724namespace Trace { 725 726enum Flags {''' 727 728 # Generate the enum. Base flags come first, then compound flags. 729 idx = 0 730 for flag, compound, desc in allFlags: 731 if not compound: 732 print >>f, ' %s = %d,' % (flag, idx) 733 idx += 1 734 735 numBaseFlags = idx 736 print >>f, ' NumFlags = %d,' % idx 737 738 # put a comment in here to separate base from compound flags 739 print >>f, ''' 740// The remaining enum values are *not* valid indices for Trace::flags. 741// They are "compound" flags, which correspond to sets of base 742// flags, and are used by changeFlag.''' 743 744 print >>f, ' All = %d,' % idx 745 idx += 1 746 for flag, compound, desc in allFlags: 747 if compound: 748 print >>f, ' %s = %d,' % (flag, idx) 749 idx += 1 750 751 numCompoundFlags = idx - numBaseFlags 752 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags 753 754 # trailer boilerplate 755 print >>f, '''\ 756}; // enum Flags 757 758// Array of strings for SimpleEnumParam 759extern const char *flagStrings[]; 760extern const int numFlagStrings; 761 762// Array of arraay pointers: for each compound flag, gives the list of 763// base flags to set. Inidividual flag arrays are terminated by -1. 764extern const Flags *compoundFlags[]; 765 766/* namespace Trace */ } 767 768#endif // __BASE_TRACE_FLAGS_HH__ 769''' 770 771 f.close() 772 773flags = [ Value(f) for f in trace_flags ] 774env.Command('base/traceflags.py', flags, traceFlagsPy) 775PySource('m5', 'base/traceflags.py') 776 777env.Command('base/traceflags.hh', flags, traceFlagsHH) 778env.Command('base/traceflags.cc', flags, traceFlagsCC) 779Source('base/traceflags.cc') 780 781# Generate program_info.cc 782def programInfo(target, source, env): 783 def gen_file(target, rev, node, date): 784 pi_stats = file(target, 'w') 785 print >>pi_stats, 'const char *hgRev = "%s:%s";' % (rev, node) 786 print >>pi_stats, 'const char *hgDate = "%s";' % date 787 pi_stats.close() 788 789 target = str(target[0]) 790 scons_dir = str(source[0].get_contents()) 791 try: 792 import mercurial.demandimport, mercurial.hg, mercurial.ui 793 import mercurial.util, mercurial.node 794 if not exists(scons_dir) or not isdir(scons_dir) or \ 795 not exists(joinpath(scons_dir, ".hg")): 796 raise ValueError 797 repo = mercurial.hg.repository(mercurial.ui.ui(), scons_dir) 798 rev = mercurial.node.nullrev + repo.changelog.count() 799 changenode = repo.changelog.node(rev) 800 changes = repo.changelog.read(changenode) 801 date = mercurial.util.datestr(changes[2]) 802 803 gen_file(target, rev, mercurial.node.hex(changenode), date) 804 805 mercurial.demandimport.disable() 806 except ImportError: 807 gen_file(target, "Unknown", "Unknown", "Unknown") 808 809 except: 810 print "in except" 811 gen_file(target, "Unknown", "Unknown", "Unknown") 812 mercurial.demandimport.disable() 813 814env.Command('base/program_info.cc', 815 Value(str(SCons.Node.FS.default_fs.SConstruct_dir)), 816 programInfo) 817 818# embed python files. All .py files that have been indicated by a 819# PySource() call in a SConscript need to be embedded into the M5 820# library. To do that, we compile the file to byte code, marshal the 821# byte code, compress it, and then generate an assembly file that 822# inserts the result into the data section with symbols indicating the 823# beginning, and end (and with the size at the end) 824py_sources_tnodes = {} 825for pysource in py_sources: 826 py_sources_tnodes[pysource.tnode] = pysource 827 828def objectifyPyFile(target, source, env): 829 '''Action function to compile a .py into a code object, marshal 830 it, compress it, and stick it into an asm file so the code appears 831 as just bytes with a label in the data section''' 832 833 src = file(str(source[0]), 'r').read() 834 dst = file(str(target[0]), 'w') 835 836 pysource = py_sources_tnodes[source[0]] 837 compiled = compile(src, pysource.snode.path, 'exec') 838 marshalled = marshal.dumps(compiled) 839 compressed = zlib.compress(marshalled) 840 data = compressed 841 842 # Some C/C++ compilers prepend an underscore to global symbol 843 # names, so if they're going to do that, we need to prepend that 844 # leading underscore to globals in the assembly file. 845 if env['LEADING_UNDERSCORE']: 846 sym = '_' + pysource.symname 847 else: 848 sym = pysource.symname 849 850 step = 16 851 print >>dst, ".data" 852 print >>dst, ".globl %s_beg" % sym 853 print >>dst, ".globl %s_end" % sym 854 print >>dst, "%s_beg:" % sym 855 for i in xrange(0, len(data), step): 856 x = array.array('B', data[i:i+step]) 857 print >>dst, ".byte", ','.join([str(d) for d in x]) 858 print >>dst, "%s_end:" % sym 859 print >>dst, ".long %d" % len(marshalled) 860 861for source in py_sources: 862 env.Command(source.assembly, source.tnode, objectifyPyFile) 863 Source(source.assembly) 864 865# Generate init_python.cc which creates a bunch of EmbeddedPyModule 866# structs that describe the embedded python code. One such struct 867# contains information about the importer that python uses to get at 868# the embedded files, and then there's a list of all of the rest that 869# the importer uses to load the rest on demand. 870py_sources_symbols = {} 871for pysource in py_sources: 872 py_sources_symbols[pysource.symname] = pysource 873def pythonInit(target, source, env): 874 dst = file(str(target[0]), 'w') 875 876 def dump_mod(sym, endchar=','): 877 pysource = py_sources_symbols[sym] 878 print >>dst, ' { "%s",' % pysource.arcname 879 print >>dst, ' "%s",' % pysource.modpath 880 print >>dst, ' %s_beg, %s_end,' % (sym, sym) 881 print >>dst, ' %s_end - %s_beg,' % (sym, sym) 882 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar) 883 884 print >>dst, '#include "sim/init.hh"' 885 886 for sym in source: 887 sym = sym.get_contents() 888 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym) 889 890 print >>dst, "const EmbeddedPyModule embeddedPyImporter = " 891 dump_mod("PyEMB_importer", endchar=';'); 892 print >>dst 893 894 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {" 895 for i,sym in enumerate(source): 896 sym = sym.get_contents() 897 if sym == "PyEMB_importer": 898 # Skip the importer since we've already exported it 899 continue 900 dump_mod(sym) 901 print >>dst, " { 0, 0, 0, 0, 0, 0 }" 902 print >>dst, "};" 903 904symbols = [Value(s.symname) for s in py_sources] 905env.Command('sim/init_python.cc', symbols, pythonInit) 906Source('sim/init_python.cc') 907 908######################################################################## 909# 910# Define binaries. Each different build type (debug, opt, etc.) gets 911# a slightly different build environment. 912# 913 914# List of constructed environments to pass back to SConstruct 915envList = [] 916 917# This function adds the specified sources to the given build 918# environment, and returns a list of all the corresponding SCons 919# Object nodes (including an extra one for date.cc). We explicitly 920# add the Object nodes so we can set up special dependencies for 921# date.cc. 922def make_objs(sources, env): 923 objs = [env.Object(s) for s in sources] 924 925 # make date.cc depend on all other objects so it always gets 926 # recompiled whenever anything else does 927 date_obj = env.Object('base/date.cc') 928 929 # Make the generation of program_info.cc dependend on all 930 # the other cc files and the compiling of program_info.cc 931 # dependent on all the objects but program_info.o 932 pinfo_obj = env.Object('base/program_info.cc') 933 env.Depends('base/program_info.cc', sources) 934 env.Depends(date_obj, objs) 935 env.Depends(pinfo_obj, objs) 936 objs.extend([date_obj,pinfo_obj]) 937 return objs 938 939# Function to create a new build environment as clone of current 940# environment 'env' with modified object suffix and optional stripped 941# binary. Additional keyword arguments are appended to corresponding 942# build environment vars. 943def makeEnv(label, objsfx, strip = False, **kwargs): 944 newEnv = env.Copy(OBJSUFFIX=objsfx) 945 newEnv.Label = label 946 newEnv.Append(**kwargs) 947 948 # First make a library of everything but main() so other programs can 949 # link against m5. 950 # 951 # SCons doesn't know to append a library suffix when there is a '.' in the 952 # name. Use '_' instead. 953 m5lib = newEnv.Library('m5_' + label, make_objs(cc_lib_sources, newEnv)) 954 955 # Now link a stub with main() and the library. 956 exe = 'm5.' + label # final executable 957 objects = [newEnv.Object(s) for s in cc_bin_sources] + m5lib 958 if strip: 959 unstripped_exe = exe + '.unstripped' 960 newEnv.Program(unstripped_exe, objects) 961 if sys.platform == 'sunos5': 962 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 963 else: 964 cmd = 'strip $SOURCE -o $TARGET' 965 targets = newEnv.Command(exe, unstripped_exe, cmd) 966 else: 967 targets = newEnv.Program(exe, objects) 968 969 newEnv.M5Binary = targets[0] 970 envList.append(newEnv) 971 972# Debug binary 973ccflags = {} 974if env['GCC']: 975 if sys.platform == 'sunos5': 976 ccflags['debug'] = '-gstabs+' 977 else: 978 ccflags['debug'] = '-ggdb3' 979 ccflags['opt'] = '-g -O3' 980 ccflags['fast'] = '-O3' 981 ccflags['prof'] = '-O3 -g -pg' 982elif env['SUNCC']: 983 ccflags['debug'] = '-g0' 984 ccflags['opt'] = '-g -O' 985 ccflags['fast'] = '-fast' 986 ccflags['prof'] = '-fast -g -pg' 987elif env['ICC']: 988 ccflags['debug'] = '-g -O0' 989 ccflags['opt'] = '-g -O' 990 ccflags['fast'] = '-fast' 991 ccflags['prof'] = '-fast -g -pg' 992else: 993 print 'Unknown compiler, please fix compiler options' 994 Exit(1) 995 996makeEnv('debug', '.do', 997 CCFLAGS = Split(ccflags['debug']), 998 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 999 1000# Optimized binary 1001makeEnv('opt', '.o', 1002 CCFLAGS = Split(ccflags['opt']), 1003 CPPDEFINES = ['TRACING_ON=1']) 1004 1005# "Fast" binary 1006makeEnv('fast', '.fo', strip = True, 1007 CCFLAGS = Split(ccflags['fast']), 1008 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 1009 1010# Profiled binary 1011makeEnv('prof', '.po', 1012 CCFLAGS = Split(ccflags['prof']), 1013 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1014 LINKFLAGS = '-pg') 1015 1016Return('envList') 1017