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