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