SConscript revision 8242
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 bisect 33import imp 34import marshal 35import os 36import re 37import sys 38import zlib 39 40from os.path import basename, dirname, exists, isdir, isfile, join as joinpath 41 42import SCons 43 44# This file defines how to build a particular configuration of M5 45# based on variable settings in the 'env' build environment. 46 47Import('*') 48 49# Children need to see the environment 50Export('env') 51 52build_env = [(opt, env[opt]) for opt in export_vars] 53 54from m5.util import code_formatter 55 56######################################################################## 57# Code for adding source files of various types 58# 59# When specifying a source file of some type, a set of guards can be 60# specified for that file. When get() is used to find the files, if 61# get specifies a set of filters, only files that match those filters 62# will be accepted (unspecified filters on files are assumed to be 63# false). Current filters are: 64# main -- specifies the m5 main() function 65# skip_lib -- do not put this file into the m5 library 66# <unittest> -- unit tests use filters based on the unit test name 67# 68# A parent can now be specified for a source file and default filter 69# values will be retrieved recursively from parents (children override 70# parents). 71# 72class SourceMeta(type): 73 '''Meta class for source files that keeps track of all files of a 74 particular type and has a get function for finding all functions 75 of a certain type that match a set of guards''' 76 def __init__(cls, name, bases, dict): 77 super(SourceMeta, cls).__init__(name, bases, dict) 78 cls.all = [] 79 80 def get(cls, **guards): 81 '''Find all files that match the specified guards. If a source 82 file does not specify a flag, the default is False''' 83 for src in cls.all: 84 for flag,value in guards.iteritems(): 85 # if the flag is found and has a different value, skip 86 # this file 87 if src.all_guards.get(flag, False) != value: 88 break 89 else: 90 yield src 91 92class SourceFile(object): 93 '''Base object that encapsulates the notion of a source file. 94 This includes, the source node, target node, various manipulations 95 of those. A source file also specifies a set of guards which 96 describing which builds the source file applies to. A parent can 97 also be specified to get default guards from''' 98 __metaclass__ = SourceMeta 99 def __init__(self, source, parent=None, **guards): 100 self.guards = guards 101 self.parent = parent 102 103 tnode = source 104 if not isinstance(source, SCons.Node.FS.File): 105 tnode = File(source) 106 107 self.tnode = tnode 108 self.snode = tnode.srcnode() 109 110 for base in type(self).__mro__: 111 if issubclass(base, SourceFile): 112 base.all.append(self) 113 114 @property 115 def filename(self): 116 return str(self.tnode) 117 118 @property 119 def dirname(self): 120 return dirname(self.filename) 121 122 @property 123 def basename(self): 124 return basename(self.filename) 125 126 @property 127 def extname(self): 128 index = self.basename.rfind('.') 129 if index <= 0: 130 # dot files aren't extensions 131 return self.basename, None 132 133 return self.basename[:index], self.basename[index+1:] 134 135 @property 136 def all_guards(self): 137 '''find all guards for this object getting default values 138 recursively from its parents''' 139 guards = {} 140 if self.parent: 141 guards.update(self.parent.guards) 142 guards.update(self.guards) 143 return guards 144 145 def __lt__(self, other): return self.filename < other.filename 146 def __le__(self, other): return self.filename <= other.filename 147 def __gt__(self, other): return self.filename > other.filename 148 def __ge__(self, other): return self.filename >= other.filename 149 def __eq__(self, other): return self.filename == other.filename 150 def __ne__(self, other): return self.filename != other.filename 151 152class Source(SourceFile): 153 '''Add a c/c++ source file to the build''' 154 def __init__(self, source, Werror=True, swig=False, **guards): 155 '''specify the source file, and any guards''' 156 super(Source, self).__init__(source, **guards) 157 158 self.Werror = Werror 159 self.swig = swig 160 161class PySource(SourceFile): 162 '''Add a python source file to the named package''' 163 invalid_sym_char = re.compile('[^A-z0-9_]') 164 modules = {} 165 tnodes = {} 166 symnames = {} 167 168 def __init__(self, package, source, **guards): 169 '''specify the python package, the source file, and any guards''' 170 super(PySource, self).__init__(source, **guards) 171 172 modname,ext = self.extname 173 assert ext == 'py' 174 175 if package: 176 path = package.split('.') 177 else: 178 path = [] 179 180 modpath = path[:] 181 if modname != '__init__': 182 modpath += [ modname ] 183 modpath = '.'.join(modpath) 184 185 arcpath = path + [ self.basename ] 186 abspath = self.snode.abspath 187 if not exists(abspath): 188 abspath = self.tnode.abspath 189 190 self.package = package 191 self.modname = modname 192 self.modpath = modpath 193 self.arcname = joinpath(*arcpath) 194 self.abspath = abspath 195 self.compiled = File(self.filename + 'c') 196 self.cpp = File(self.filename + '.cc') 197 self.symname = PySource.invalid_sym_char.sub('_', modpath) 198 199 PySource.modules[modpath] = self 200 PySource.tnodes[self.tnode] = self 201 PySource.symnames[self.symname] = self 202 203class SimObject(PySource): 204 '''Add a SimObject python file as a python source object and add 205 it to a list of sim object modules''' 206 207 fixed = False 208 modnames = [] 209 210 def __init__(self, source, **guards): 211 '''Specify the source file and any guards (automatically in 212 the m5.objects package)''' 213 super(SimObject, self).__init__('m5.objects', source, **guards) 214 if self.fixed: 215 raise AttributeError, "Too late to call SimObject now." 216 217 bisect.insort_right(SimObject.modnames, self.modname) 218 219class SwigSource(SourceFile): 220 '''Add a swig file to build''' 221 222 def __init__(self, package, source, **guards): 223 '''Specify the python package, the source file, and any guards''' 224 super(SwigSource, self).__init__(source, **guards) 225 226 modname,ext = self.extname 227 assert ext == 'i' 228 229 self.module = modname 230 cc_file = joinpath(self.dirname, modname + '_wrap.cc') 231 py_file = joinpath(self.dirname, modname + '.py') 232 233 self.cc_source = Source(cc_file, swig=True, parent=self) 234 self.py_source = PySource(package, py_file, parent=self) 235 236class UnitTest(object): 237 '''Create a UnitTest''' 238 239 all = [] 240 def __init__(self, target, *sources): 241 '''Specify the target name and any sources. Sources that are 242 not SourceFiles are evalued with Source(). All files are 243 guarded with a guard of the same name as the UnitTest 244 target.''' 245 246 srcs = [] 247 for src in sources: 248 if not isinstance(src, SourceFile): 249 src = Source(src, skip_lib=True) 250 src.guards[target] = True 251 srcs.append(src) 252 253 self.sources = srcs 254 self.target = target 255 UnitTest.all.append(self) 256 257# Children should have access 258Export('Source') 259Export('PySource') 260Export('SimObject') 261Export('SwigSource') 262Export('UnitTest') 263 264######################################################################## 265# 266# Debug Flags 267# 268debug_flags = {} 269def DebugFlag(name, desc=None): 270 if name in debug_flags: 271 raise AttributeError, "Flag %s already specified" % name 272 debug_flags[name] = (name, (), desc) 273TraceFlag = DebugFlag 274 275def CompoundFlag(name, flags, desc=None): 276 if name in debug_flags: 277 raise AttributeError, "Flag %s already specified" % name 278 279 compound = tuple(flags) 280 debug_flags[name] = (name, compound, desc) 281 282Export('DebugFlag') 283Export('TraceFlag') 284Export('CompoundFlag') 285 286######################################################################## 287# 288# Set some compiler variables 289# 290 291# Include file paths are rooted in this directory. SCons will 292# automatically expand '.' to refer to both the source directory and 293# the corresponding build directory to pick up generated include 294# files. 295env.Append(CPPPATH=Dir('.')) 296 297for extra_dir in extras_dir_list: 298 env.Append(CPPPATH=Dir(extra_dir)) 299 300# Workaround for bug in SCons version > 0.97d20071212 301# Scons bug id: 2006 M5 Bug id: 308 302for root, dirs, files in os.walk(base_dir, topdown=True): 303 Dir(root[len(base_dir) + 1:]) 304 305######################################################################## 306# 307# Walk the tree and execute all SConscripts in subdirectories 308# 309 310here = Dir('.').srcnode().abspath 311for root, dirs, files in os.walk(base_dir, topdown=True): 312 if root == here: 313 # we don't want to recurse back into this SConscript 314 continue 315 316 if 'SConscript' in files: 317 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 318 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 319 320for extra_dir in extras_dir_list: 321 prefix_len = len(dirname(extra_dir)) + 1 322 for root, dirs, files in os.walk(extra_dir, topdown=True): 323 # if build lives in the extras directory, don't walk down it 324 if 'build' in dirs: 325 dirs.remove('build') 326 327 if 'SConscript' in files: 328 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 329 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 330 331for opt in export_vars: 332 env.ConfigFile(opt) 333 334def makeTheISA(source, target, env): 335 isas = [ src.get_contents() for src in source ] 336 target_isa = env['TARGET_ISA'] 337 def define(isa): 338 return isa.upper() + '_ISA' 339 340 def namespace(isa): 341 return isa[0].upper() + isa[1:].lower() + 'ISA' 342 343 344 code = code_formatter() 345 code('''\ 346#ifndef __CONFIG_THE_ISA_HH__ 347#define __CONFIG_THE_ISA_HH__ 348 349''') 350 351 for i,isa in enumerate(isas): 352 code('#define $0 $1', define(isa), i + 1) 353 354 code(''' 355 356#define THE_ISA ${{define(target_isa)}} 357#define TheISA ${{namespace(target_isa)}} 358 359#endif // __CONFIG_THE_ISA_HH__''') 360 361 code.write(str(target[0])) 362 363env.Command('config/the_isa.hh', map(Value, all_isa_list), 364 MakeAction(makeTheISA, Transform("CFG ISA", 0))) 365 366######################################################################## 367# 368# Prevent any SimObjects from being added after this point, they 369# should all have been added in the SConscripts above 370# 371SimObject.fixed = True 372 373class DictImporter(object): 374 '''This importer takes a dictionary of arbitrary module names that 375 map to arbitrary filenames.''' 376 def __init__(self, modules): 377 self.modules = modules 378 self.installed = set() 379 380 def __del__(self): 381 self.unload() 382 383 def unload(self): 384 import sys 385 for module in self.installed: 386 del sys.modules[module] 387 self.installed = set() 388 389 def find_module(self, fullname, path): 390 if fullname == 'm5.defines': 391 return self 392 393 if fullname == 'm5.objects': 394 return self 395 396 if fullname.startswith('m5.internal'): 397 return None 398 399 source = self.modules.get(fullname, None) 400 if source is not None and fullname.startswith('m5.objects'): 401 return self 402 403 return None 404 405 def load_module(self, fullname): 406 mod = imp.new_module(fullname) 407 sys.modules[fullname] = mod 408 self.installed.add(fullname) 409 410 mod.__loader__ = self 411 if fullname == 'm5.objects': 412 mod.__path__ = fullname.split('.') 413 return mod 414 415 if fullname == 'm5.defines': 416 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 417 return mod 418 419 source = self.modules[fullname] 420 if source.modname == '__init__': 421 mod.__path__ = source.modpath 422 mod.__file__ = source.abspath 423 424 exec file(source.abspath, 'r') in mod.__dict__ 425 426 return mod 427 428import m5.SimObject 429import m5.params 430from m5.util import code_formatter 431 432m5.SimObject.clear() 433m5.params.clear() 434 435# install the python importer so we can grab stuff from the source 436# tree itself. We can't have SimObjects added after this point or 437# else we won't know about them for the rest of the stuff. 438importer = DictImporter(PySource.modules) 439sys.meta_path[0:0] = [ importer ] 440 441# import all sim objects so we can populate the all_objects list 442# make sure that we're working with a list, then let's sort it 443for modname in SimObject.modnames: 444 exec('from m5.objects import %s' % modname) 445 446# we need to unload all of the currently imported modules so that they 447# will be re-imported the next time the sconscript is run 448importer.unload() 449sys.meta_path.remove(importer) 450 451sim_objects = m5.SimObject.allClasses 452all_enums = m5.params.allEnums 453 454all_params = {} 455for name,obj in sorted(sim_objects.iteritems()): 456 for param in obj._params.local.values(): 457 # load the ptype attribute now because it depends on the 458 # current version of SimObject.allClasses, but when scons 459 # actually uses the value, all versions of 460 # SimObject.allClasses will have been loaded 461 param.ptype 462 463 if not hasattr(param, 'swig_decl'): 464 continue 465 pname = param.ptype_str 466 if pname not in all_params: 467 all_params[pname] = param 468 469######################################################################## 470# 471# calculate extra dependencies 472# 473module_depends = ["m5", "m5.SimObject", "m5.params"] 474depends = [ PySource.modules[dep].snode for dep in module_depends ] 475 476######################################################################## 477# 478# Commands for the basic automatically generated python files 479# 480 481# Generate Python file containing a dict specifying the current 482# buildEnv flags. 483def makeDefinesPyFile(target, source, env): 484 build_env = source[0].get_contents() 485 486 code = code_formatter() 487 code(""" 488import m5.internal 489import m5.util 490 491buildEnv = m5.util.SmartDict($build_env) 492 493compileDate = m5.internal.core.compileDate 494_globals = globals() 495for key,val in m5.internal.core.__dict__.iteritems(): 496 if key.startswith('flag_'): 497 flag = key[5:] 498 _globals[flag] = val 499del _globals 500""") 501 code.write(target[0].abspath) 502 503defines_info = Value(build_env) 504# Generate a file with all of the compile options in it 505env.Command('python/m5/defines.py', defines_info, 506 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 507PySource('m5', 'python/m5/defines.py') 508 509# Generate python file containing info about the M5 source code 510def makeInfoPyFile(target, source, env): 511 code = code_formatter() 512 for src in source: 513 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 514 code('$src = ${{repr(data)}}') 515 code.write(str(target[0])) 516 517# Generate a file that wraps the basic top level files 518env.Command('python/m5/info.py', 519 [ '#/AUTHORS', '#/LICENSE', '#/README', ], 520 MakeAction(makeInfoPyFile, Transform("INFO"))) 521PySource('m5', 'python/m5/info.py') 522 523######################################################################## 524# 525# Create all of the SimObject param headers and enum headers 526# 527 528def createSimObjectParam(target, source, env): 529 assert len(target) == 1 and len(source) == 1 530 531 name = str(source[0].get_contents()) 532 obj = sim_objects[name] 533 534 code = code_formatter() 535 obj.cxx_decl(code) 536 code.write(target[0].abspath) 537 538def createSwigParam(target, source, env): 539 assert len(target) == 1 and len(source) == 1 540 541 name = str(source[0].get_contents()) 542 param = all_params[name] 543 544 code = code_formatter() 545 code('%module(package="m5.internal") $0_${name}', param.file_ext) 546 param.swig_decl(code) 547 code.write(target[0].abspath) 548 549def createEnumStrings(target, source, env): 550 assert len(target) == 1 and len(source) == 1 551 552 name = str(source[0].get_contents()) 553 obj = all_enums[name] 554 555 code = code_formatter() 556 obj.cxx_def(code) 557 code.write(target[0].abspath) 558 559def createEnumParam(target, source, env): 560 assert len(target) == 1 and len(source) == 1 561 562 name = str(source[0].get_contents()) 563 obj = all_enums[name] 564 565 code = code_formatter() 566 obj.cxx_decl(code) 567 code.write(target[0].abspath) 568 569def createEnumSwig(target, source, env): 570 assert len(target) == 1 and len(source) == 1 571 572 name = str(source[0].get_contents()) 573 obj = all_enums[name] 574 575 code = code_formatter() 576 code('''\ 577%module(package="m5.internal") enum_$name 578 579%{ 580#include "enums/$name.hh" 581%} 582 583%include "enums/$name.hh" 584''') 585 code.write(target[0].abspath) 586 587# Generate all of the SimObject param struct header files 588params_hh_files = [] 589for name,simobj in sorted(sim_objects.iteritems()): 590 py_source = PySource.modules[simobj.__module__] 591 extra_deps = [ py_source.tnode ] 592 593 hh_file = File('params/%s.hh' % name) 594 params_hh_files.append(hh_file) 595 env.Command(hh_file, Value(name), 596 MakeAction(createSimObjectParam, Transform("SO PARAM"))) 597 env.Depends(hh_file, depends + extra_deps) 598 599# Generate any parameter header files needed 600params_i_files = [] 601for name,param in all_params.iteritems(): 602 i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name)) 603 params_i_files.append(i_file) 604 env.Command(i_file, Value(name), 605 MakeAction(createSwigParam, Transform("SW PARAM"))) 606 env.Depends(i_file, depends) 607 SwigSource('m5.internal', i_file) 608 609# Generate all enum header files 610for name,enum in sorted(all_enums.iteritems()): 611 py_source = PySource.modules[enum.__module__] 612 extra_deps = [ py_source.tnode ] 613 614 cc_file = File('enums/%s.cc' % name) 615 env.Command(cc_file, Value(name), 616 MakeAction(createEnumStrings, Transform("ENUM STR"))) 617 env.Depends(cc_file, depends + extra_deps) 618 Source(cc_file) 619 620 hh_file = File('enums/%s.hh' % name) 621 env.Command(hh_file, Value(name), 622 MakeAction(createEnumParam, Transform("EN PARAM"))) 623 env.Depends(hh_file, depends + extra_deps) 624 625 i_file = File('python/m5/internal/enum_%s.i' % name) 626 env.Command(i_file, Value(name), 627 MakeAction(createEnumSwig, Transform("ENUMSWIG"))) 628 env.Depends(i_file, depends + extra_deps) 629 SwigSource('m5.internal', i_file) 630 631def buildParam(target, source, env): 632 name = source[0].get_contents() 633 obj = sim_objects[name] 634 class_path = obj.cxx_class.split('::') 635 classname = class_path[-1] 636 namespaces = class_path[:-1] 637 params = obj._params.local.values() 638 639 code = code_formatter() 640 641 code('%module(package="m5.internal") param_$name') 642 code() 643 code('%{') 644 code('#include "params/$obj.hh"') 645 for param in params: 646 param.cxx_predecls(code) 647 code('%}') 648 code() 649 650 for param in params: 651 param.swig_predecls(code) 652 653 code() 654 if obj._base: 655 code('%import "python/m5/internal/param_${{obj._base}}.i"') 656 code() 657 obj.swig_objdecls(code) 658 code() 659 660 code('%include "params/$obj.hh"') 661 662 code.write(target[0].abspath) 663 664for name in sim_objects.iterkeys(): 665 params_file = File('python/m5/internal/param_%s.i' % name) 666 env.Command(params_file, Value(name), 667 MakeAction(buildParam, Transform("BLDPARAM"))) 668 env.Depends(params_file, depends) 669 SwigSource('m5.internal', params_file) 670 671# Generate the main swig init file 672def makeEmbeddedSwigInit(target, source, env): 673 code = code_formatter() 674 module = source[0].get_contents() 675 code('''\ 676#include "sim/init.hh" 677 678extern "C" { 679 void init_${module}(); 680} 681 682EmbeddedSwig embed_swig_${module}(init_${module}); 683''') 684 code.write(str(target[0])) 685 686# Build all swig modules 687for swig in SwigSource.all: 688 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 689 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 690 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG"))) 691 cc_file = str(swig.tnode) 692 init_file = '%s/init_%s.cc' % (dirname(cc_file), basename(cc_file)) 693 env.Command(init_file, Value(swig.module), 694 MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW"))) 695 Source(init_file, **swig.guards) 696 697# 698# Handle debug flags 699# 700def makeDebugFlagCC(target, source, env): 701 assert(len(target) == 1 and len(source) == 1) 702 703 val = eval(source[0].get_contents()) 704 name, compound, desc = val 705 compound = list(sorted(compound)) 706 707 code = code_formatter() 708 709 # file header 710 code(''' 711/* 712 * DO NOT EDIT THIS FILE! Automatically generated 713 */ 714 715#include "base/debug.hh" 716''') 717 718 for flag in compound: 719 code('#include "debug/$flag.hh"') 720 code() 721 code('namespace Debug {') 722 code() 723 724 if not compound: 725 code('SimpleFlag $name("$name", "$desc");') 726 else: 727 code('CompoundFlag $name("$name", "$desc",') 728 code.indent() 729 last = len(compound) - 1 730 for i,flag in enumerate(compound): 731 if i != last: 732 code('$flag,') 733 else: 734 code('$flag);') 735 code.dedent() 736 737 code() 738 code('} // namespace Debug') 739 740 code.write(str(target[0])) 741 742def makeDebugFlagHH(target, source, env): 743 assert(len(target) == 1 and len(source) == 1) 744 745 val = eval(source[0].get_contents()) 746 name, compound, desc = val 747 748 code = code_formatter() 749 750 # file header boilerplate 751 code('''\ 752/* 753 * DO NOT EDIT THIS FILE! 754 * 755 * Automatically generated by SCons 756 */ 757 758#ifndef __DEBUG_${name}_HH__ 759#define __DEBUG_${name}_HH__ 760 761namespace Debug { 762''') 763 764 if compound: 765 code('class CompoundFlag;') 766 code('class SimpleFlag;') 767 768 if compound: 769 code('extern CompoundFlag $name;') 770 for flag in compound: 771 code('extern SimpleFlag $flag;') 772 else: 773 code('extern SimpleFlag $name;') 774 775 code(''' 776} 777 778#endif // __DEBUG_${name}_HH__ 779''') 780 781 code.write(str(target[0])) 782 783for name,flag in sorted(debug_flags.iteritems()): 784 n, compound, desc = flag 785 assert n == name 786 787 env.Command('debug/%s.hh' % name, Value(flag), 788 MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) 789 env.Command('debug/%s.cc' % name, Value(flag), 790 MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) 791 Source('debug/%s.cc' % name) 792 793# Embed python files. All .py files that have been indicated by a 794# PySource() call in a SConscript need to be embedded into the M5 795# library. To do that, we compile the file to byte code, marshal the 796# byte code, compress it, and then generate a c++ file that 797# inserts the result into an array. 798def embedPyFile(target, source, env): 799 def c_str(string): 800 if string is None: 801 return "0" 802 return '"%s"' % string 803 804 '''Action function to compile a .py into a code object, marshal 805 it, compress it, and stick it into an asm file so the code appears 806 as just bytes with a label in the data section''' 807 808 src = file(str(source[0]), 'r').read() 809 810 pysource = PySource.tnodes[source[0]] 811 compiled = compile(src, pysource.abspath, 'exec') 812 marshalled = marshal.dumps(compiled) 813 compressed = zlib.compress(marshalled) 814 data = compressed 815 sym = pysource.symname 816 817 code = code_formatter() 818 code('''\ 819#include "sim/init.hh" 820 821namespace { 822 823const char data_${sym}[] = { 824''') 825 code.indent() 826 step = 16 827 for i in xrange(0, len(data), step): 828 x = array.array('B', data[i:i+step]) 829 code(''.join('%d,' % d for d in x)) 830 code.dedent() 831 832 code('''}; 833 834EmbeddedPython embedded_${sym}( 835 ${{c_str(pysource.arcname)}}, 836 ${{c_str(pysource.abspath)}}, 837 ${{c_str(pysource.modpath)}}, 838 data_${sym}, 839 ${{len(data)}}, 840 ${{len(marshalled)}}); 841 842} // anonymous namespace 843''') 844 code.write(str(target[0])) 845 846for source in PySource.all: 847 env.Command(source.cpp, source.tnode, 848 MakeAction(embedPyFile, Transform("EMBED PY"))) 849 Source(source.cpp) 850 851######################################################################## 852# 853# Define binaries. Each different build type (debug, opt, etc.) gets 854# a slightly different build environment. 855# 856 857# List of constructed environments to pass back to SConstruct 858envList = [] 859 860date_source = Source('base/date.cc', skip_lib=True) 861 862# Function to create a new build environment as clone of current 863# environment 'env' with modified object suffix and optional stripped 864# binary. Additional keyword arguments are appended to corresponding 865# build environment vars. 866def makeEnv(label, objsfx, strip = False, **kwargs): 867 # SCons doesn't know to append a library suffix when there is a '.' in the 868 # name. Use '_' instead. 869 libname = 'm5_' + label 870 exename = 'm5.' + label 871 872 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 873 new_env.Label = label 874 new_env.Append(**kwargs) 875 876 swig_env = new_env.Clone() 877 swig_env.Append(CCFLAGS='-Werror') 878 if env['GCC']: 879 swig_env.Append(CCFLAGS='-Wno-uninitialized') 880 swig_env.Append(CCFLAGS='-Wno-sign-compare') 881 swig_env.Append(CCFLAGS='-Wno-parentheses') 882 883 werror_env = new_env.Clone() 884 werror_env.Append(CCFLAGS='-Werror') 885 886 def make_obj(source, static, extra_deps = None): 887 '''This function adds the specified source to the correct 888 build environment, and returns the corresponding SCons Object 889 nodes''' 890 891 if source.swig: 892 env = swig_env 893 elif source.Werror: 894 env = werror_env 895 else: 896 env = new_env 897 898 if static: 899 obj = env.StaticObject(source.tnode) 900 else: 901 obj = env.SharedObject(source.tnode) 902 903 if extra_deps: 904 env.Depends(obj, extra_deps) 905 906 return obj 907 908 sources = Source.get(main=False, skip_lib=False) 909 static_objs = [ make_obj(s, True) for s in sources ] 910 shared_objs = [ make_obj(s, False) for s in sources ] 911 912 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 913 static_objs.append(static_date) 914 915 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 916 shared_objs.append(shared_date) 917 918 # First make a library of everything but main() so other programs can 919 # link against m5. 920 static_lib = new_env.StaticLibrary(libname, static_objs) 921 shared_lib = new_env.SharedLibrary(libname, shared_objs) 922 923 # Now link a stub with main() and the static library. 924 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ] 925 926 for test in UnitTest.all: 927 flags = { test.target : True } 928 test_sources = Source.get(**flags) 929 test_objs = [ make_obj(s, static=True) for s in test_sources ] 930 testname = "unittest/%s.%s" % (test.target, label) 931 new_env.Program(testname, main_objs + test_objs + static_objs) 932 933 progname = exename 934 if strip: 935 progname += '.unstripped' 936 937 targets = new_env.Program(progname, main_objs + static_objs) 938 939 if strip: 940 if sys.platform == 'sunos5': 941 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 942 else: 943 cmd = 'strip $SOURCE -o $TARGET' 944 targets = new_env.Command(exename, progname, 945 MakeAction(cmd, Transform("STRIP"))) 946 947 new_env.M5Binary = targets[0] 948 envList.append(new_env) 949 950# Debug binary 951ccflags = {} 952if env['GCC']: 953 if sys.platform == 'sunos5': 954 ccflags['debug'] = '-gstabs+' 955 else: 956 ccflags['debug'] = '-ggdb3' 957 ccflags['opt'] = '-g -O3' 958 ccflags['fast'] = '-O3' 959 ccflags['prof'] = '-O3 -g -pg' 960elif env['SUNCC']: 961 ccflags['debug'] = '-g0' 962 ccflags['opt'] = '-g -O' 963 ccflags['fast'] = '-fast' 964 ccflags['prof'] = '-fast -g -pg' 965elif env['ICC']: 966 ccflags['debug'] = '-g -O0' 967 ccflags['opt'] = '-g -O' 968 ccflags['fast'] = '-fast' 969 ccflags['prof'] = '-fast -g -pg' 970else: 971 print 'Unknown compiler, please fix compiler options' 972 Exit(1) 973 974makeEnv('debug', '.do', 975 CCFLAGS = Split(ccflags['debug']), 976 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 977 978# Optimized binary 979makeEnv('opt', '.o', 980 CCFLAGS = Split(ccflags['opt']), 981 CPPDEFINES = ['TRACING_ON=1']) 982 983# "Fast" binary 984makeEnv('fast', '.fo', strip = True, 985 CCFLAGS = Split(ccflags['fast']), 986 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 987 988# Profiled binary 989makeEnv('prof', '.po', 990 CCFLAGS = Split(ccflags['prof']), 991 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 992 LINKFLAGS = '-pg') 993 994Return('envList') 995