SConscript revision 8282
12817Sksewell@umich.edu# -*- mode:python -*- 22817Sksewell@umich.edu 32817Sksewell@umich.edu# Copyright (c) 2004-2005 The Regents of The University of Michigan 42817Sksewell@umich.edu# All rights reserved. 52817Sksewell@umich.edu# 62817Sksewell@umich.edu# Redistribution and use in source and binary forms, with or without 72817Sksewell@umich.edu# modification, are permitted provided that the following conditions are 82817Sksewell@umich.edu# met: redistributions of source code must retain the above copyright 92817Sksewell@umich.edu# notice, this list of conditions and the following disclaimer; 102817Sksewell@umich.edu# redistributions in binary form must reproduce the above copyright 112817Sksewell@umich.edu# notice, this list of conditions and the following disclaimer in the 122817Sksewell@umich.edu# documentation and/or other materials provided with the distribution; 132817Sksewell@umich.edu# neither the name of the copyright holders nor the names of its 142817Sksewell@umich.edu# contributors may be used to endorse or promote products derived from 152817Sksewell@umich.edu# this software without specific prior written permission. 162817Sksewell@umich.edu# 172817Sksewell@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 182817Sksewell@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 192817Sksewell@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 202817Sksewell@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 212817Sksewell@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 222817Sksewell@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 232817Sksewell@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 242817Sksewell@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 252817Sksewell@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 262817Sksewell@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 272817Sksewell@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 282817Sksewell@umich.edu# 294202Sbinkertn@umich.edu# Authors: Nathan Binkert 302817Sksewell@umich.edu 312817Sksewell@umich.eduimport array 322817Sksewell@umich.eduimport bisect 334202Sbinkertn@umich.eduimport imp 342817Sksewell@umich.eduimport marshal 354202Sbinkertn@umich.eduimport os 364486Sbinkertn@umich.eduimport re 374486Sbinkertn@umich.eduimport sys 384486Sbinkertn@umich.eduimport zlib 394486Sbinkertn@umich.edu 404202Sbinkertn@umich.edufrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath 414202Sbinkertn@umich.edu 424202Sbinkertn@umich.eduimport SCons 434202Sbinkertn@umich.edu 444202Sbinkertn@umich.edu# This file defines how to build a particular configuration of M5 454202Sbinkertn@umich.edu# based on variable settings in the 'env' build environment. 464202Sbinkertn@umich.edu 474202Sbinkertn@umich.eduImport('*') 484202Sbinkertn@umich.edu 494202Sbinkertn@umich.edu# Children need to see the environment 504202Sbinkertn@umich.eduExport('env') 514202Sbinkertn@umich.edu 524202Sbinkertn@umich.edubuild_env = [(opt, env[opt]) for opt in export_vars] 534202Sbinkertn@umich.edu 544202Sbinkertn@umich.edufrom m5.util import code_formatter 554202Sbinkertn@umich.edu 564202Sbinkertn@umich.edu######################################################################## 574202Sbinkertn@umich.edu# Code for adding source files of various types 582817Sksewell@umich.edu# 594202Sbinkertn@umich.edu# When specifying a source file of some type, a set of guards can be 604202Sbinkertn@umich.edu# specified for that file. When get() is used to find the files, if 614202Sbinkertn@umich.edu# get specifies a set of filters, only files that match those filters 624202Sbinkertn@umich.edu# will be accepted (unspecified filters on files are assumed to be 634202Sbinkertn@umich.edu# false). Current filters are: 644202Sbinkertn@umich.edu# main -- specifies the m5 main() function 654202Sbinkertn@umich.edu# skip_lib -- do not put this file into the m5 library 664202Sbinkertn@umich.edu# <unittest> -- unit tests use filters based on the unit test name 674202Sbinkertn@umich.edu# 684202Sbinkertn@umich.edu# A parent can now be specified for a source file and default filter 694202Sbinkertn@umich.edu# values will be retrieved recursively from parents (children override 704202Sbinkertn@umich.edu# parents). 714202Sbinkertn@umich.edu# 724202Sbinkertn@umich.educlass SourceMeta(type): 734202Sbinkertn@umich.edu '''Meta class for source files that keeps track of all files of a 744202Sbinkertn@umich.edu particular type and has a get function for finding all functions 754202Sbinkertn@umich.edu of a certain type that match a set of guards''' 762817Sksewell@umich.edu def __init__(cls, name, bases, dict): 774202Sbinkertn@umich.edu super(SourceMeta, cls).__init__(name, bases, dict) 784486Sbinkertn@umich.edu cls.all = [] 794202Sbinkertn@umich.edu 802817Sksewell@umich.edu def get(cls, **guards): 814202Sbinkertn@umich.edu '''Find all files that match the specified guards. If a source 824202Sbinkertn@umich.edu file does not specify a flag, the default is False''' 834202Sbinkertn@umich.edu for src in cls.all: 844202Sbinkertn@umich.edu for flag,value in guards.iteritems(): 854202Sbinkertn@umich.edu # if the flag is found and has a different value, skip 862817Sksewell@umich.edu # 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