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