SConscript revision 11984
14202Sbinkertn@umich.edu# -*- mode:python -*- 24202Sbinkertn@umich.edu 34202Sbinkertn@umich.edu# Copyright (c) 2004-2005 The Regents of The University of Michigan 44202Sbinkertn@umich.edu# All rights reserved. 54202Sbinkertn@umich.edu# 64202Sbinkertn@umich.edu# Redistribution and use in source and binary forms, with or without 74202Sbinkertn@umich.edu# modification, are permitted provided that the following conditions are 84202Sbinkertn@umich.edu# met: redistributions of source code must retain the above copyright 94202Sbinkertn@umich.edu# notice, this list of conditions and the following disclaimer; 104202Sbinkertn@umich.edu# redistributions in binary form must reproduce the above copyright 114202Sbinkertn@umich.edu# notice, this list of conditions and the following disclaimer in the 124202Sbinkertn@umich.edu# documentation and/or other materials provided with the distribution; 134202Sbinkertn@umich.edu# neither the name of the copyright holders nor the names of its 144202Sbinkertn@umich.edu# contributors may be used to endorse or promote products derived from 154202Sbinkertn@umich.edu# this software without specific prior written permission. 164202Sbinkertn@umich.edu# 174202Sbinkertn@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 184202Sbinkertn@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 194202Sbinkertn@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 204202Sbinkertn@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 214202Sbinkertn@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 224202Sbinkertn@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 234202Sbinkertn@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 244202Sbinkertn@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 254202Sbinkertn@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 264202Sbinkertn@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 274202Sbinkertn@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 284202Sbinkertn@umich.edu# 294202Sbinkertn@umich.edu# Authors: Nathan Binkert 304202Sbinkertn@umich.edu 314202Sbinkertn@umich.eduimport array 324202Sbinkertn@umich.eduimport bisect 335952Ssaidi@eecs.umich.eduimport imp 345952Ssaidi@eecs.umich.eduimport marshal 355952Ssaidi@eecs.umich.eduimport os 365548Snate@binkert.orgimport re 374202Sbinkertn@umich.eduimport subprocess 387067Snate@binkert.orgimport sys 394202Sbinkertn@umich.eduimport zlib 404202Sbinkertn@umich.edu 414202Sbinkertn@umich.edufrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath 425882Snate@binkert.org 434202Sbinkertn@umich.eduimport SCons 444550Sbinkertn@umich.edu 454550Sbinkertn@umich.edu# This file defines how to build a particular configuration of gem5 464202Sbinkertn@umich.edu# based on variable settings in the 'env' build environment. 474202Sbinkertn@umich.edu 484202Sbinkertn@umich.eduImport('*') 494202Sbinkertn@umich.edu 504202Sbinkertn@umich.edu# Children need to see the environment 514202Sbinkertn@umich.eduExport('env') 524202Sbinkertn@umich.edu 534202Sbinkertn@umich.edubuild_env = [(opt, env[opt]) for opt in export_vars] 544202Sbinkertn@umich.edu 554202Sbinkertn@umich.edufrom m5.util import code_formatter, compareVersions 564202Sbinkertn@umich.edu 575190Ssaidi@eecs.umich.edu######################################################################## 584202Sbinkertn@umich.edu# Code for adding source files of various types 597768SAli.Saidi@ARM.com# 607768SAli.Saidi@ARM.com# When specifying a source file of some type, a set of guards can be 614202Sbinkertn@umich.edu# specified for that file. When get() is used to find the files, if 624202Sbinkertn@umich.edu# get specifies a set of filters, only files that match those filters 634202Sbinkertn@umich.edu# will be accepted (unspecified filters on files are assumed to be 644202Sbinkertn@umich.edu# false). Current filters are: 654202Sbinkertn@umich.edu# main -- specifies the gem5 main() function 664202Sbinkertn@umich.edu# skip_lib -- do not put this file into the gem5 library 674202Sbinkertn@umich.edu# skip_no_python -- do not put this file into a no_python library 684202Sbinkertn@umich.edu# as it embeds compiled Python 694202Sbinkertn@umich.edu# <unittest> -- unit tests use filters based on the unit test name 704202Sbinkertn@umich.edu# 714202Sbinkertn@umich.edu# A parent can now be specified for a source file and default filter 724202Sbinkertn@umich.edu# values will be retrieved recursively from parents (children override 734202Sbinkertn@umich.edu# parents). 745222Sksewell@umich.edu# 754202Sbinkertn@umich.edudef guarded_source_iterator(sources, **guards): 764202Sbinkertn@umich.edu '''Iterate over a set of sources, gated by a set of guards.''' 774202Sbinkertn@umich.edu for src in sources: 784202Sbinkertn@umich.edu for flag,value in guards.iteritems(): 794202Sbinkertn@umich.edu # if the flag is found and has a different value, skip 804202Sbinkertn@umich.edu # this file 814202Sbinkertn@umich.edu if src.all_guards.get(flag, False) != value: 824202Sbinkertn@umich.edu break 834202Sbinkertn@umich.edu else: 844202Sbinkertn@umich.edu yield src 854202Sbinkertn@umich.edu 864382Sbinkertn@umich.educlass SourceMeta(type): 875800Snate@binkert.org '''Meta class for source files that keeps track of all files of a 885952Ssaidi@eecs.umich.edu particular type and has a get function for finding all functions 895952Ssaidi@eecs.umich.edu of a certain type that match a set of guards''' 905800Snate@binkert.org def __init__(cls, name, bases, dict): 915800Snate@binkert.org super(SourceMeta, cls).__init__(name, bases, dict) 925800Snate@binkert.org cls.all = [] 935800Snate@binkert.org 945800Snate@binkert.org def get(cls, **guards): 955800Snate@binkert.org '''Find all files that match the specified guards. If a source 965800Snate@binkert.org file does not specify a flag, the default is False''' 975800Snate@binkert.org for s in guarded_source_iterator(cls.all, **guards): 985800Snate@binkert.org yield s 995192Ssaidi@eecs.umich.edu 1005800Snate@binkert.orgclass SourceFile(object): 1015800Snate@binkert.org '''Base object that encapsulates the notion of a source file. 1025800Snate@binkert.org This includes, the source node, target node, various manipulations 1035800Snate@binkert.org of those. A source file also specifies a set of guards which 1045952Ssaidi@eecs.umich.edu describing which builds the source file applies to. A parent can 1055952Ssaidi@eecs.umich.edu also be specified to get default guards from''' 1065952Ssaidi@eecs.umich.edu __metaclass__ = SourceMeta 107 def __init__(self, source, parent=None, **guards): 108 self.guards = guards 109 self.parent = parent 110 111 tnode = source 112 if not isinstance(source, SCons.Node.FS.File): 113 tnode = File(source) 114 115 self.tnode = tnode 116 self.snode = tnode.srcnode() 117 118 for base in type(self).__mro__: 119 if issubclass(base, SourceFile): 120 base.all.append(self) 121 122 @property 123 def filename(self): 124 return str(self.tnode) 125 126 @property 127 def dirname(self): 128 return dirname(self.filename) 129 130 @property 131 def basename(self): 132 return basename(self.filename) 133 134 @property 135 def extname(self): 136 index = self.basename.rfind('.') 137 if index <= 0: 138 # dot files aren't extensions 139 return self.basename, None 140 141 return self.basename[:index], self.basename[index+1:] 142 143 @property 144 def all_guards(self): 145 '''find all guards for this object getting default values 146 recursively from its parents''' 147 guards = {} 148 if self.parent: 149 guards.update(self.parent.guards) 150 guards.update(self.guards) 151 return guards 152 153 def __lt__(self, other): return self.filename < other.filename 154 def __le__(self, other): return self.filename <= other.filename 155 def __gt__(self, other): return self.filename > other.filename 156 def __ge__(self, other): return self.filename >= other.filename 157 def __eq__(self, other): return self.filename == other.filename 158 def __ne__(self, other): return self.filename != other.filename 159 160 @staticmethod 161 def done(): 162 def disabled(cls, name, *ignored): 163 raise RuntimeError("Additional SourceFile '%s'" % name,\ 164 "declared, but targets deps are already fixed.") 165 SourceFile.__init__ = disabled 166 167 168class Source(SourceFile): 169 current_group = None 170 source_groups = { None : [] } 171 172 @classmethod 173 def set_group(cls, group): 174 if not group in Source.source_groups: 175 Source.source_groups[group] = [] 176 Source.current_group = group 177 178 '''Add a c/c++ source file to the build''' 179 def __init__(self, source, Werror=True, swig=False, **guards): 180 '''specify the source file, and any guards''' 181 super(Source, self).__init__(source, **guards) 182 183 self.Werror = Werror 184 self.swig = swig 185 186 Source.source_groups[Source.current_group].append(self) 187 188class PySource(SourceFile): 189 '''Add a python source file to the named package''' 190 invalid_sym_char = re.compile('[^A-z0-9_]') 191 modules = {} 192 tnodes = {} 193 symnames = {} 194 195 def __init__(self, package, source, **guards): 196 '''specify the python package, the source file, and any guards''' 197 super(PySource, self).__init__(source, **guards) 198 199 modname,ext = self.extname 200 assert ext == 'py' 201 202 if package: 203 path = package.split('.') 204 else: 205 path = [] 206 207 modpath = path[:] 208 if modname != '__init__': 209 modpath += [ modname ] 210 modpath = '.'.join(modpath) 211 212 arcpath = path + [ self.basename ] 213 abspath = self.snode.abspath 214 if not exists(abspath): 215 abspath = self.tnode.abspath 216 217 self.package = package 218 self.modname = modname 219 self.modpath = modpath 220 self.arcname = joinpath(*arcpath) 221 self.abspath = abspath 222 self.compiled = File(self.filename + 'c') 223 self.cpp = File(self.filename + '.cc') 224 self.symname = PySource.invalid_sym_char.sub('_', modpath) 225 226 PySource.modules[modpath] = self 227 PySource.tnodes[self.tnode] = self 228 PySource.symnames[self.symname] = self 229 230class SimObject(PySource): 231 '''Add a SimObject python file as a python source object and add 232 it to a list of sim object modules''' 233 234 fixed = False 235 modnames = [] 236 237 def __init__(self, source, **guards): 238 '''Specify the source file and any guards (automatically in 239 the m5.objects package)''' 240 super(SimObject, self).__init__('m5.objects', source, **guards) 241 if self.fixed: 242 raise AttributeError, "Too late to call SimObject now." 243 244 bisect.insort_right(SimObject.modnames, self.modname) 245 246class SwigSource(SourceFile): 247 '''Add a swig file to build''' 248 249 def __init__(self, package, source, **guards): 250 '''Specify the python package, the source file, and any guards''' 251 super(SwigSource, self).__init__(source, skip_no_python=True, **guards) 252 253 modname,ext = self.extname 254 assert ext == 'i' 255 256 self.package = package 257 self.module = modname 258 cc_file = joinpath(self.dirname, modname + '_wrap.cc') 259 py_file = joinpath(self.dirname, modname + '.py') 260 261 self.cc_source = Source(cc_file, swig=True, parent=self, **guards) 262 self.py_source = PySource(package, py_file, parent=self, **guards) 263 264class ProtoBuf(SourceFile): 265 '''Add a Protocol Buffer to build''' 266 267 def __init__(self, source, **guards): 268 '''Specify the source file, and any guards''' 269 super(ProtoBuf, self).__init__(source, **guards) 270 271 # Get the file name and the extension 272 modname,ext = self.extname 273 assert ext == 'proto' 274 275 # Currently, we stick to generating the C++ headers, so we 276 # only need to track the source and header. 277 self.cc_file = File(modname + '.pb.cc') 278 self.hh_file = File(modname + '.pb.h') 279 280class UnitTest(object): 281 '''Create a UnitTest''' 282 283 all = [] 284 def __init__(self, target, *sources, **kwargs): 285 '''Specify the target name and any sources. Sources that are 286 not SourceFiles are evalued with Source(). All files are 287 guarded with a guard of the same name as the UnitTest 288 target.''' 289 290 srcs = [] 291 for src in sources: 292 if not isinstance(src, SourceFile): 293 src = Source(src, skip_lib=True) 294 src.guards[target] = True 295 srcs.append(src) 296 297 self.sources = srcs 298 self.target = target 299 self.main = kwargs.get('main', False) 300 UnitTest.all.append(self) 301 302# Children should have access 303Export('Source') 304Export('PySource') 305Export('SimObject') 306Export('SwigSource') 307Export('ProtoBuf') 308Export('UnitTest') 309 310######################################################################## 311# 312# Debug Flags 313# 314debug_flags = {} 315def DebugFlag(name, desc=None): 316 if name in debug_flags: 317 raise AttributeError, "Flag %s already specified" % name 318 debug_flags[name] = (name, (), desc) 319 320def CompoundFlag(name, flags, desc=None): 321 if name in debug_flags: 322 raise AttributeError, "Flag %s already specified" % name 323 324 compound = tuple(flags) 325 debug_flags[name] = (name, compound, desc) 326 327Export('DebugFlag') 328Export('CompoundFlag') 329 330######################################################################## 331# 332# Set some compiler variables 333# 334 335# Include file paths are rooted in this directory. SCons will 336# automatically expand '.' to refer to both the source directory and 337# the corresponding build directory to pick up generated include 338# files. 339env.Append(CPPPATH=Dir('.')) 340 341for extra_dir in extras_dir_list: 342 env.Append(CPPPATH=Dir(extra_dir)) 343 344# Workaround for bug in SCons version > 0.97d20071212 345# Scons bug id: 2006 gem5 Bug id: 308 346for root, dirs, files in os.walk(base_dir, topdown=True): 347 Dir(root[len(base_dir) + 1:]) 348 349######################################################################## 350# 351# Walk the tree and execute all SConscripts in subdirectories 352# 353 354here = Dir('.').srcnode().abspath 355for root, dirs, files in os.walk(base_dir, topdown=True): 356 if root == here: 357 # we don't want to recurse back into this SConscript 358 continue 359 360 if 'SConscript' in files: 361 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 362 Source.set_group(build_dir) 363 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 364 365for extra_dir in extras_dir_list: 366 prefix_len = len(dirname(extra_dir)) + 1 367 368 # Also add the corresponding build directory to pick up generated 369 # include files. 370 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:]))) 371 372 for root, dirs, files in os.walk(extra_dir, topdown=True): 373 # if build lives in the extras directory, don't walk down it 374 if 'build' in dirs: 375 dirs.remove('build') 376 377 if 'SConscript' in files: 378 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 379 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 380 381for opt in export_vars: 382 env.ConfigFile(opt) 383 384def makeTheISA(source, target, env): 385 isas = [ src.get_contents() for src in source ] 386 target_isa = env['TARGET_ISA'] 387 def define(isa): 388 return isa.upper() + '_ISA' 389 390 def namespace(isa): 391 return isa[0].upper() + isa[1:].lower() + 'ISA' 392 393 394 code = code_formatter() 395 code('''\ 396#ifndef __CONFIG_THE_ISA_HH__ 397#define __CONFIG_THE_ISA_HH__ 398 399''') 400 401 # create defines for the preprocessing and compile-time determination 402 for i,isa in enumerate(isas): 403 code('#define $0 $1', define(isa), i + 1) 404 code() 405 406 # create an enum for any run-time determination of the ISA, we 407 # reuse the same name as the namespaces 408 code('enum class Arch {') 409 for i,isa in enumerate(isas): 410 if i + 1 == len(isas): 411 code(' $0 = $1', namespace(isa), define(isa)) 412 else: 413 code(' $0 = $1,', namespace(isa), define(isa)) 414 code('};') 415 416 code(''' 417 418#define THE_ISA ${{define(target_isa)}} 419#define TheISA ${{namespace(target_isa)}} 420#define THE_ISA_STR "${{target_isa}}" 421 422#endif // __CONFIG_THE_ISA_HH__''') 423 424 code.write(str(target[0])) 425 426env.Command('config/the_isa.hh', map(Value, all_isa_list), 427 MakeAction(makeTheISA, Transform("CFG ISA", 0))) 428 429def makeTheGPUISA(source, target, env): 430 isas = [ src.get_contents() for src in source ] 431 target_gpu_isa = env['TARGET_GPU_ISA'] 432 def define(isa): 433 return isa.upper() + '_ISA' 434 435 def namespace(isa): 436 return isa[0].upper() + isa[1:].lower() + 'ISA' 437 438 439 code = code_formatter() 440 code('''\ 441#ifndef __CONFIG_THE_GPU_ISA_HH__ 442#define __CONFIG_THE_GPU_ISA_HH__ 443 444''') 445 446 # create defines for the preprocessing and compile-time determination 447 for i,isa in enumerate(isas): 448 code('#define $0 $1', define(isa), i + 1) 449 code() 450 451 # create an enum for any run-time determination of the ISA, we 452 # reuse the same name as the namespaces 453 code('enum class GPUArch {') 454 for i,isa in enumerate(isas): 455 if i + 1 == len(isas): 456 code(' $0 = $1', namespace(isa), define(isa)) 457 else: 458 code(' $0 = $1,', namespace(isa), define(isa)) 459 code('};') 460 461 code(''' 462 463#define THE_GPU_ISA ${{define(target_gpu_isa)}} 464#define TheGpuISA ${{namespace(target_gpu_isa)}} 465#define THE_GPU_ISA_STR "${{target_gpu_isa}}" 466 467#endif // __CONFIG_THE_GPU_ISA_HH__''') 468 469 code.write(str(target[0])) 470 471env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list), 472 MakeAction(makeTheGPUISA, Transform("CFG ISA", 0))) 473 474######################################################################## 475# 476# Prevent any SimObjects from being added after this point, they 477# should all have been added in the SConscripts above 478# 479SimObject.fixed = True 480 481class DictImporter(object): 482 '''This importer takes a dictionary of arbitrary module names that 483 map to arbitrary filenames.''' 484 def __init__(self, modules): 485 self.modules = modules 486 self.installed = set() 487 488 def __del__(self): 489 self.unload() 490 491 def unload(self): 492 import sys 493 for module in self.installed: 494 del sys.modules[module] 495 self.installed = set() 496 497 def find_module(self, fullname, path): 498 if fullname == 'm5.defines': 499 return self 500 501 if fullname == 'm5.objects': 502 return self 503 504 if fullname.startswith('_m5'): 505 return None 506 507 source = self.modules.get(fullname, None) 508 if source is not None and fullname.startswith('m5.objects'): 509 return self 510 511 return None 512 513 def load_module(self, fullname): 514 mod = imp.new_module(fullname) 515 sys.modules[fullname] = mod 516 self.installed.add(fullname) 517 518 mod.__loader__ = self 519 if fullname == 'm5.objects': 520 mod.__path__ = fullname.split('.') 521 return mod 522 523 if fullname == 'm5.defines': 524 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 525 return mod 526 527 source = self.modules[fullname] 528 if source.modname == '__init__': 529 mod.__path__ = source.modpath 530 mod.__file__ = source.abspath 531 532 exec file(source.abspath, 'r') in mod.__dict__ 533 534 return mod 535 536import m5.SimObject 537import m5.params 538from m5.util import code_formatter 539 540m5.SimObject.clear() 541m5.params.clear() 542 543# install the python importer so we can grab stuff from the source 544# tree itself. We can't have SimObjects added after this point or 545# else we won't know about them for the rest of the stuff. 546importer = DictImporter(PySource.modules) 547sys.meta_path[0:0] = [ importer ] 548 549# import all sim objects so we can populate the all_objects list 550# make sure that we're working with a list, then let's sort it 551for modname in SimObject.modnames: 552 exec('from m5.objects import %s' % modname) 553 554# we need to unload all of the currently imported modules so that they 555# will be re-imported the next time the sconscript is run 556importer.unload() 557sys.meta_path.remove(importer) 558 559sim_objects = m5.SimObject.allClasses 560all_enums = m5.params.allEnums 561 562if m5.SimObject.noCxxHeader: 563 print >> sys.stderr, \ 564 "warning: At least one SimObject lacks a header specification. " \ 565 "This can cause unexpected results in the generated SWIG " \ 566 "wrappers." 567 568# Find param types that need to be explicitly wrapped with swig. 569# These will be recognized because the ParamDesc will have a 570# swig_decl() method. Most param types are based on types that don't 571# need this, either because they're based on native types (like Int) 572# or because they're SimObjects (which get swigged independently). 573# For now the only things handled here are VectorParam types. 574params_to_swig = {} 575for name,obj in sorted(sim_objects.iteritems()): 576 for param in obj._params.local.values(): 577 # load the ptype attribute now because it depends on the 578 # current version of SimObject.allClasses, but when scons 579 # actually uses the value, all versions of 580 # SimObject.allClasses will have been loaded 581 param.ptype 582 583 if not hasattr(param, 'swig_decl'): 584 continue 585 pname = param.ptype_str 586 if pname not in params_to_swig: 587 params_to_swig[pname] = param 588 589######################################################################## 590# 591# calculate extra dependencies 592# 593module_depends = ["m5", "m5.SimObject", "m5.params"] 594depends = [ PySource.modules[dep].snode for dep in module_depends ] 595depends.sort(key = lambda x: x.name) 596 597######################################################################## 598# 599# Commands for the basic automatically generated python files 600# 601 602# Generate Python file containing a dict specifying the current 603# buildEnv flags. 604def makeDefinesPyFile(target, source, env): 605 build_env = source[0].get_contents() 606 607 code = code_formatter() 608 code(""" 609import _m5.core 610import m5.util 611 612buildEnv = m5.util.SmartDict($build_env) 613 614compileDate = _m5.core.compileDate 615_globals = globals() 616for key,val in _m5.core.__dict__.iteritems(): 617 if key.startswith('flag_'): 618 flag = key[5:] 619 _globals[flag] = val 620del _globals 621""") 622 code.write(target[0].abspath) 623 624defines_info = Value(build_env) 625# Generate a file with all of the compile options in it 626env.Command('python/m5/defines.py', defines_info, 627 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 628PySource('m5', 'python/m5/defines.py') 629 630# Generate python file containing info about the M5 source code 631def makeInfoPyFile(target, source, env): 632 code = code_formatter() 633 for src in source: 634 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 635 code('$src = ${{repr(data)}}') 636 code.write(str(target[0])) 637 638# Generate a file that wraps the basic top level files 639env.Command('python/m5/info.py', 640 [ '#/COPYING', '#/LICENSE', '#/README', ], 641 MakeAction(makeInfoPyFile, Transform("INFO"))) 642PySource('m5', 'python/m5/info.py') 643 644######################################################################## 645# 646# Create all of the SimObject param headers and enum headers 647# 648 649def createSimObjectParamStruct(target, source, env): 650 assert len(target) == 1 and len(source) == 1 651 652 name = str(source[0].get_contents()) 653 obj = sim_objects[name] 654 655 code = code_formatter() 656 obj.cxx_param_decl(code) 657 code.write(target[0].abspath) 658 659def createSimObjectCxxConfig(is_header): 660 def body(target, source, env): 661 assert len(target) == 1 and len(source) == 1 662 663 name = str(source[0].get_contents()) 664 obj = sim_objects[name] 665 666 code = code_formatter() 667 obj.cxx_config_param_file(code, is_header) 668 code.write(target[0].abspath) 669 return body 670 671def createParamSwigWrapper(target, source, env): 672 assert len(target) == 1 and len(source) == 1 673 674 name = str(source[0].get_contents()) 675 param = params_to_swig[name] 676 677 code = code_formatter() 678 param.swig_decl(code) 679 code.write(target[0].abspath) 680 681def createEnumStrings(target, source, env): 682 assert len(target) == 1 and len(source) == 1 683 684 name = str(source[0].get_contents()) 685 obj = all_enums[name] 686 687 code = code_formatter() 688 obj.cxx_def(code) 689 code.write(target[0].abspath) 690 691def createEnumDecls(target, source, env): 692 assert len(target) == 1 and len(source) == 1 693 694 name = str(source[0].get_contents()) 695 obj = all_enums[name] 696 697 code = code_formatter() 698 obj.cxx_decl(code) 699 code.write(target[0].abspath) 700 701def createEnumSwigWrapper(target, source, env): 702 assert len(target) == 1 and len(source) == 1 703 704 name = str(source[0].get_contents()) 705 obj = all_enums[name] 706 707 code = code_formatter() 708 obj.swig_decl(code) 709 code.write(target[0].abspath) 710 711def createSimObjectSwigWrapper(target, source, env): 712 name = source[0].get_contents() 713 obj = sim_objects[name] 714 715 code = code_formatter() 716 obj.swig_decl(code) 717 code.write(target[0].abspath) 718 719# dummy target for generated code 720# we start out with all the Source files so they get copied to build/*/ also. 721SWIG = env.Dummy('swig', [s.tnode for s in Source.get()]) 722 723# Generate all of the SimObject param C++ struct header files 724params_hh_files = [] 725for name,simobj in sorted(sim_objects.iteritems()): 726 py_source = PySource.modules[simobj.__module__] 727 extra_deps = [ py_source.tnode ] 728 729 hh_file = File('params/%s.hh' % name) 730 params_hh_files.append(hh_file) 731 env.Command(hh_file, Value(name), 732 MakeAction(createSimObjectParamStruct, Transform("SO PARAM"))) 733 env.Depends(hh_file, depends + extra_deps) 734 env.Depends(SWIG, hh_file) 735 736# C++ parameter description files 737if GetOption('with_cxx_config'): 738 for name,simobj in sorted(sim_objects.iteritems()): 739 py_source = PySource.modules[simobj.__module__] 740 extra_deps = [ py_source.tnode ] 741 742 cxx_config_hh_file = File('cxx_config/%s.hh' % name) 743 cxx_config_cc_file = File('cxx_config/%s.cc' % name) 744 env.Command(cxx_config_hh_file, Value(name), 745 MakeAction(createSimObjectCxxConfig(True), 746 Transform("CXXCPRHH"))) 747 env.Command(cxx_config_cc_file, Value(name), 748 MakeAction(createSimObjectCxxConfig(False), 749 Transform("CXXCPRCC"))) 750 env.Depends(cxx_config_hh_file, depends + extra_deps + 751 [File('params/%s.hh' % name), File('sim/cxx_config.hh')]) 752 env.Depends(cxx_config_cc_file, depends + extra_deps + 753 [cxx_config_hh_file]) 754 Source(cxx_config_cc_file) 755 756 cxx_config_init_cc_file = File('cxx_config/init.cc') 757 758 def createCxxConfigInitCC(target, source, env): 759 assert len(target) == 1 and len(source) == 1 760 761 code = code_formatter() 762 763 for name,simobj in sorted(sim_objects.iteritems()): 764 if not hasattr(simobj, 'abstract') or not simobj.abstract: 765 code('#include "cxx_config/${name}.hh"') 766 code() 767 code('void cxxConfigInit()') 768 code('{') 769 code.indent() 770 for name,simobj in sorted(sim_objects.iteritems()): 771 not_abstract = not hasattr(simobj, 'abstract') or \ 772 not simobj.abstract 773 if not_abstract and 'type' in simobj.__dict__: 774 code('cxx_config_directory["${name}"] = ' 775 '${name}CxxConfigParams::makeDirectoryEntry();') 776 code.dedent() 777 code('}') 778 code.write(target[0].abspath) 779 780 py_source = PySource.modules[simobj.__module__] 781 extra_deps = [ py_source.tnode ] 782 env.Command(cxx_config_init_cc_file, Value(name), 783 MakeAction(createCxxConfigInitCC, Transform("CXXCINIT"))) 784 cxx_param_hh_files = ["cxx_config/%s.hh" % simobj 785 for name,simobj in sorted(sim_objects.iteritems()) 786 if not hasattr(simobj, 'abstract') or not simobj.abstract] 787 Depends(cxx_config_init_cc_file, cxx_param_hh_files + 788 [File('sim/cxx_config.hh')]) 789 Source(cxx_config_init_cc_file) 790 791# Generate any needed param SWIG wrapper files 792params_i_files = [] 793for name,param in sorted(params_to_swig.iteritems()): 794 i_file = File('python/_m5/%s.i' % (param.swig_module_name())) 795 params_i_files.append(i_file) 796 env.Command(i_file, Value(name), 797 MakeAction(createParamSwigWrapper, Transform("SW PARAM"))) 798 env.Depends(i_file, depends) 799 env.Depends(SWIG, i_file) 800 SwigSource('_m5', i_file) 801 802# Generate all enum header files 803for name,enum in sorted(all_enums.iteritems()): 804 py_source = PySource.modules[enum.__module__] 805 extra_deps = [ py_source.tnode ] 806 807 cc_file = File('enums/%s.cc' % name) 808 env.Command(cc_file, Value(name), 809 MakeAction(createEnumStrings, Transform("ENUM STR"))) 810 env.Depends(cc_file, depends + extra_deps) 811 env.Depends(SWIG, cc_file) 812 Source(cc_file) 813 814 hh_file = File('enums/%s.hh' % name) 815 env.Command(hh_file, Value(name), 816 MakeAction(createEnumDecls, Transform("ENUMDECL"))) 817 env.Depends(hh_file, depends + extra_deps) 818 env.Depends(SWIG, hh_file) 819 820 i_file = File('python/_m5/enum_%s.i' % name) 821 env.Command(i_file, Value(name), 822 MakeAction(createEnumSwigWrapper, Transform("ENUMSWIG"))) 823 env.Depends(i_file, depends + extra_deps) 824 env.Depends(SWIG, i_file) 825 SwigSource('_m5', i_file) 826 827# Generate SimObject SWIG wrapper files 828for name,simobj in sorted(sim_objects.iteritems()): 829 py_source = PySource.modules[simobj.__module__] 830 extra_deps = [ py_source.tnode ] 831 i_file = File('python/_m5/param_%s.i' % name) 832 env.Command(i_file, Value(name), 833 MakeAction(createSimObjectSwigWrapper, Transform("SO SWIG"))) 834 env.Depends(i_file, depends + extra_deps) 835 SwigSource('_m5', i_file) 836 837# Generate the main swig init file 838def makeEmbeddedSwigInit(package): 839 def body(target, source, env): 840 assert len(target) == 1 and len(source) == 1 841 842 code = code_formatter() 843 module = source[0].get_contents() 844 # Provide the full context so that the swig-generated call to 845 # Py_InitModule ends up placing the embedded module in the 846 # right package. 847 context = str(package) + "._" + str(module) 848 code('''\ 849 #include "sim/init.hh" 850 851 extern "C" { 852 void init_${module}(); 853 } 854 855 EmbeddedSwig embed_swig_${module}(init_${module}, "${context}"); 856 ''') 857 code.write(str(target[0])) 858 return body 859 860# Build all swig modules 861for swig in SwigSource.all: 862 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 863 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 864 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG"))) 865 cc_file = str(swig.tnode) 866 init_file = '%s/%s_init.cc' % (dirname(cc_file), basename(cc_file)) 867 env.Command(init_file, Value(swig.module), 868 MakeAction(makeEmbeddedSwigInit(swig.package), 869 Transform("EMBED SW"))) 870 env.Depends(SWIG, init_file) 871 Source(init_file, **swig.guards) 872 873# Build all protocol buffers if we have got protoc and protobuf available 874if env['HAVE_PROTOBUF']: 875 for proto in ProtoBuf.all: 876 # Use both the source and header as the target, and the .proto 877 # file as the source. When executing the protoc compiler, also 878 # specify the proto_path to avoid having the generated files 879 # include the path. 880 env.Command([proto.cc_file, proto.hh_file], proto.tnode, 881 MakeAction('$PROTOC --cpp_out ${TARGET.dir} ' 882 '--proto_path ${SOURCE.dir} $SOURCE', 883 Transform("PROTOC"))) 884 885 env.Depends(SWIG, [proto.cc_file, proto.hh_file]) 886 # Add the C++ source file 887 Source(proto.cc_file, **proto.guards) 888elif ProtoBuf.all: 889 print 'Got protobuf to build, but lacks support!' 890 Exit(1) 891 892# 893# Handle debug flags 894# 895def makeDebugFlagCC(target, source, env): 896 assert(len(target) == 1 and len(source) == 1) 897 898 code = code_formatter() 899 900 # delay definition of CompoundFlags until after all the definition 901 # of all constituent SimpleFlags 902 comp_code = code_formatter() 903 904 # file header 905 code(''' 906/* 907 * DO NOT EDIT THIS FILE! Automatically generated by SCons. 908 */ 909 910#include "base/debug.hh" 911 912namespace Debug { 913 914''') 915 916 for name, flag in sorted(source[0].read().iteritems()): 917 n, compound, desc = flag 918 assert n == name 919 920 if not compound: 921 code('SimpleFlag $name("$name", "$desc");') 922 else: 923 comp_code('CompoundFlag $name("$name", "$desc",') 924 comp_code.indent() 925 last = len(compound) - 1 926 for i,flag in enumerate(compound): 927 if i != last: 928 comp_code('&$flag,') 929 else: 930 comp_code('&$flag);') 931 comp_code.dedent() 932 933 code.append(comp_code) 934 code() 935 code('} // namespace Debug') 936 937 code.write(str(target[0])) 938 939def makeDebugFlagHH(target, source, env): 940 assert(len(target) == 1 and len(source) == 1) 941 942 val = eval(source[0].get_contents()) 943 name, compound, desc = val 944 945 code = code_formatter() 946 947 # file header boilerplate 948 code('''\ 949/* 950 * DO NOT EDIT THIS FILE! Automatically generated by SCons. 951 */ 952 953#ifndef __DEBUG_${name}_HH__ 954#define __DEBUG_${name}_HH__ 955 956namespace Debug { 957''') 958 959 if compound: 960 code('class CompoundFlag;') 961 code('class SimpleFlag;') 962 963 if compound: 964 code('extern CompoundFlag $name;') 965 for flag in compound: 966 code('extern SimpleFlag $flag;') 967 else: 968 code('extern SimpleFlag $name;') 969 970 code(''' 971} 972 973#endif // __DEBUG_${name}_HH__ 974''') 975 976 code.write(str(target[0])) 977 978for name,flag in sorted(debug_flags.iteritems()): 979 n, compound, desc = flag 980 assert n == name 981 982 hh_file = 'debug/%s.hh' % name 983 env.Command(hh_file, Value(flag), 984 MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) 985 env.Depends(SWIG, hh_file) 986 987env.Command('debug/flags.cc', Value(debug_flags), 988 MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) 989env.Depends(SWIG, 'debug/flags.cc') 990Source('debug/flags.cc') 991 992# version tags 993tags = \ 994env.Command('sim/tags.cc', None, 995 MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET', 996 Transform("VER TAGS"))) 997env.AlwaysBuild(tags) 998 999# Embed python files. All .py files that have been indicated by a 1000# PySource() call in a SConscript need to be embedded into the M5 1001# library. To do that, we compile the file to byte code, marshal the 1002# byte code, compress it, and then generate a c++ file that 1003# inserts the result into an array. 1004def embedPyFile(target, source, env): 1005 def c_str(string): 1006 if string is None: 1007 return "0" 1008 return '"%s"' % string 1009 1010 '''Action function to compile a .py into a code object, marshal 1011 it, compress it, and stick it into an asm file so the code appears 1012 as just bytes with a label in the data section''' 1013 1014 src = file(str(source[0]), 'r').read() 1015 1016 pysource = PySource.tnodes[source[0]] 1017 compiled = compile(src, pysource.abspath, 'exec') 1018 marshalled = marshal.dumps(compiled) 1019 compressed = zlib.compress(marshalled) 1020 data = compressed 1021 sym = pysource.symname 1022 1023 code = code_formatter() 1024 code('''\ 1025#include "sim/init.hh" 1026 1027namespace { 1028 1029const uint8_t data_${sym}[] = { 1030''') 1031 code.indent() 1032 step = 16 1033 for i in xrange(0, len(data), step): 1034 x = array.array('B', data[i:i+step]) 1035 code(''.join('%d,' % d for d in x)) 1036 code.dedent() 1037 1038 code('''}; 1039 1040EmbeddedPython embedded_${sym}( 1041 ${{c_str(pysource.arcname)}}, 1042 ${{c_str(pysource.abspath)}}, 1043 ${{c_str(pysource.modpath)}}, 1044 data_${sym}, 1045 ${{len(data)}}, 1046 ${{len(marshalled)}}); 1047 1048} // anonymous namespace 1049''') 1050 code.write(str(target[0])) 1051 1052for source in PySource.all: 1053 env.Command(source.cpp, source.tnode, 1054 MakeAction(embedPyFile, Transform("EMBED PY"))) 1055 env.Depends(SWIG, source.cpp) 1056 Source(source.cpp, skip_no_python=True) 1057 1058######################################################################## 1059# 1060# Define binaries. Each different build type (debug, opt, etc.) gets 1061# a slightly different build environment. 1062# 1063 1064# List of constructed environments to pass back to SConstruct 1065date_source = Source('base/date.cc', skip_lib=True) 1066 1067# Capture this directory for the closure makeEnv, otherwise when it is 1068# called, it won't know what directory it should use. 1069variant_dir = Dir('.').path 1070def variant(*path): 1071 return os.path.join(variant_dir, *path) 1072def variantd(*path): 1073 return variant(*path)+'/' 1074 1075# Function to create a new build environment as clone of current 1076# environment 'env' with modified object suffix and optional stripped 1077# binary. Additional keyword arguments are appended to corresponding 1078# build environment vars. 1079def makeEnv(env, label, objsfx, strip = False, **kwargs): 1080 # SCons doesn't know to append a library suffix when there is a '.' in the 1081 # name. Use '_' instead. 1082 libname = variant('gem5_' + label) 1083 exename = variant('gem5.' + label) 1084 secondary_exename = variant('m5.' + label) 1085 1086 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 1087 new_env.Label = label 1088 new_env.Append(**kwargs) 1089 1090 swig_env = new_env.Clone() 1091 1092 # Both gcc and clang have issues with unused labels and values in 1093 # the SWIG generated code 1094 swig_env.Append(CCFLAGS=['-Wno-unused-label', '-Wno-unused-value']) 1095 1096 if env['GCC']: 1097 # Depending on the SWIG version, we also need to supress 1098 # warnings about uninitialized variables and missing field 1099 # initializers. 1100 swig_env.Append(CCFLAGS=['-Wno-uninitialized', 1101 '-Wno-missing-field-initializers', 1102 '-Wno-unused-but-set-variable', 1103 '-Wno-maybe-uninitialized', 1104 '-Wno-type-limits']) 1105 1106 1107 # The address sanitizer is available for gcc >= 4.8 1108 if GetOption('with_asan'): 1109 if GetOption('with_ubsan') and \ 1110 compareVersions(env['GCC_VERSION'], '4.9') >= 0: 1111 new_env.Append(CCFLAGS=['-fsanitize=address,undefined', 1112 '-fno-omit-frame-pointer']) 1113 new_env.Append(LINKFLAGS='-fsanitize=address,undefined') 1114 else: 1115 new_env.Append(CCFLAGS=['-fsanitize=address', 1116 '-fno-omit-frame-pointer']) 1117 new_env.Append(LINKFLAGS='-fsanitize=address') 1118 # Only gcc >= 4.9 supports UBSan, so check both the version 1119 # and the command-line option before adding the compiler and 1120 # linker flags. 1121 elif GetOption('with_ubsan') and \ 1122 compareVersions(env['GCC_VERSION'], '4.9') >= 0: 1123 new_env.Append(CCFLAGS='-fsanitize=undefined') 1124 new_env.Append(LINKFLAGS='-fsanitize=undefined') 1125 1126 1127 if env['CLANG']: 1128 swig_env.Append(CCFLAGS=['-Wno-sometimes-uninitialized', 1129 '-Wno-deprecated-register', 1130 '-Wno-tautological-compare']) 1131 1132 # We require clang >= 3.1, so there is no need to check any 1133 # versions here. 1134 if GetOption('with_ubsan'): 1135 if GetOption('with_asan'): 1136 new_env.Append(CCFLAGS=['-fsanitize=address,undefined', 1137 '-fno-omit-frame-pointer']) 1138 new_env.Append(LINKFLAGS='-fsanitize=address,undefined') 1139 else: 1140 new_env.Append(CCFLAGS='-fsanitize=undefined') 1141 new_env.Append(LINKFLAGS='-fsanitize=undefined') 1142 1143 elif GetOption('with_asan'): 1144 new_env.Append(CCFLAGS=['-fsanitize=address', 1145 '-fno-omit-frame-pointer']) 1146 new_env.Append(LINKFLAGS='-fsanitize=address') 1147 1148 werror_env = new_env.Clone() 1149 # Treat warnings as errors but white list some warnings that we 1150 # want to allow (e.g., deprecation warnings). 1151 werror_env.Append(CCFLAGS=['-Werror', 1152 '-Wno-error=deprecated-declarations', 1153 '-Wno-error=deprecated', 1154 ]) 1155 1156 def make_obj(source, static, extra_deps = None): 1157 '''This function adds the specified source to the correct 1158 build environment, and returns the corresponding SCons Object 1159 nodes''' 1160 1161 if source.swig: 1162 env = swig_env 1163 elif source.Werror: 1164 env = werror_env 1165 else: 1166 env = new_env 1167 1168 if static: 1169 obj = env.StaticObject(source.tnode) 1170 else: 1171 obj = env.SharedObject(source.tnode) 1172 1173 if extra_deps: 1174 env.Depends(obj, extra_deps) 1175 1176 return obj 1177 1178 lib_guards = {'main': False, 'skip_lib': False} 1179 1180 # Without Python, leave out all SWIG and Python content from the 1181 # library builds. The option doesn't affect gem5 built as a program 1182 if GetOption('without_python'): 1183 lib_guards['skip_no_python'] = False 1184 1185 static_objs = [] 1186 shared_objs = [] 1187 for s in guarded_source_iterator(Source.source_groups[None], **lib_guards): 1188 static_objs.append(make_obj(s, True)) 1189 shared_objs.append(make_obj(s, False)) 1190 1191 partial_objs = [] 1192 for group, all_srcs in Source.source_groups.iteritems(): 1193 # If these are the ungrouped source files, skip them. 1194 if not group: 1195 continue 1196 1197 # Get a list of the source files compatible with the current guards. 1198 srcs = [ s for s in guarded_source_iterator(all_srcs, **lib_guards) ] 1199 # If there aren't any left, skip this group. 1200 if not srcs: 1201 continue 1202 1203 # Set up the static partially linked objects. 1204 source_objs = [ make_obj(s, True) for s in srcs ] 1205 file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial") 1206 target = File(joinpath(group, file_name)) 1207 partial = env.PartialStatic(target=target, source=source_objs) 1208 static_objs.append(partial) 1209 1210 # Set up the shared partially linked objects. 1211 source_objs = [ make_obj(s, False) for s in srcs ] 1212 file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial") 1213 target = File(joinpath(group, file_name)) 1214 partial = env.PartialShared(target=target, source=source_objs) 1215 shared_objs.append(partial) 1216 1217 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 1218 static_objs.append(static_date) 1219 1220 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 1221 shared_objs.append(shared_date) 1222 1223 # First make a library of everything but main() so other programs can 1224 # link against m5. 1225 static_lib = new_env.StaticLibrary(libname, static_objs) 1226 shared_lib = new_env.SharedLibrary(libname, shared_objs) 1227 1228 # Now link a stub with main() and the static library. 1229 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ] 1230 1231 for test in UnitTest.all: 1232 flags = { test.target : True } 1233 test_sources = Source.get(**flags) 1234 test_objs = [ make_obj(s, static=True) for s in test_sources ] 1235 if test.main: 1236 test_objs += main_objs 1237 path = variant('unittest/%s.%s' % (test.target, label)) 1238 new_env.Program(path, test_objs + static_objs) 1239 1240 progname = exename 1241 if strip: 1242 progname += '.unstripped' 1243 1244 # When linking the gem5 binary, the command line can be too big for the 1245 # shell to handle. Use "subprocess" to spawn processes without passing 1246 # through the shell to avoid this problem. That means we also can't use 1247 # shell syntax in any of the commands this will run, but that isn't 1248 # currently an issue. 1249 def spawn_with_subprocess(sh, escape, cmd, args, env): 1250 return subprocess.call(args, env=env) 1251 1252 # Since we're not running through a shell, no escaping is necessary either. 1253 targets = new_env.Program(progname, main_objs + static_objs, 1254 SPAWN=spawn_with_subprocess, 1255 ESCAPE=lambda x: x) 1256 1257 if strip: 1258 if sys.platform == 'sunos5': 1259 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 1260 else: 1261 cmd = 'strip $SOURCE -o $TARGET' 1262 targets = new_env.Command(exename, progname, 1263 MakeAction(cmd, Transform("STRIP"))) 1264 1265 new_env.Command(secondary_exename, exename, 1266 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK"))) 1267 1268 new_env.M5Binary = targets[0] 1269 return new_env 1270 1271# Start out with the compiler flags common to all compilers, 1272# i.e. they all use -g for opt and -g -pg for prof 1273ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'], 1274 'perf' : ['-g']} 1275 1276# Start out with the linker flags common to all linkers, i.e. -pg for 1277# prof, and -lprofiler for perf. The -lprofile flag is surrounded by 1278# no-as-needed and as-needed as the binutils linker is too clever and 1279# simply doesn't link to the library otherwise. 1280ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'], 1281 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']} 1282 1283# For Link Time Optimization, the optimisation flags used to compile 1284# individual files are decoupled from those used at link time 1285# (i.e. you can compile with -O3 and perform LTO with -O0), so we need 1286# to also update the linker flags based on the target. 1287if env['GCC']: 1288 if sys.platform == 'sunos5': 1289 ccflags['debug'] += ['-gstabs+'] 1290 else: 1291 ccflags['debug'] += ['-ggdb3'] 1292 ldflags['debug'] += ['-O0'] 1293 # opt, fast, prof and perf all share the same cc flags, also add 1294 # the optimization to the ldflags as LTO defers the optimization 1295 # to link time 1296 for target in ['opt', 'fast', 'prof', 'perf']: 1297 ccflags[target] += ['-O3'] 1298 ldflags[target] += ['-O3'] 1299 1300 ccflags['fast'] += env['LTO_CCFLAGS'] 1301 ldflags['fast'] += env['LTO_LDFLAGS'] 1302elif env['CLANG']: 1303 ccflags['debug'] += ['-g', '-O0'] 1304 # opt, fast, prof and perf all share the same cc flags 1305 for target in ['opt', 'fast', 'prof', 'perf']: 1306 ccflags[target] += ['-O3'] 1307else: 1308 print 'Unknown compiler, please fix compiler options' 1309 Exit(1) 1310 1311 1312# To speed things up, we only instantiate the build environments we 1313# need. We try to identify the needed environment for each target; if 1314# we can't, we fall back on instantiating all the environments just to 1315# be safe. 1316target_types = ['debug', 'opt', 'fast', 'prof', 'perf'] 1317obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof', 1318 'gpo' : 'perf'} 1319 1320def identifyTarget(t): 1321 ext = t.split('.')[-1] 1322 if ext in target_types: 1323 return ext 1324 if obj2target.has_key(ext): 1325 return obj2target[ext] 1326 match = re.search(r'/tests/([^/]+)/', t) 1327 if match and match.group(1) in target_types: 1328 return match.group(1) 1329 return 'all' 1330 1331needed_envs = [identifyTarget(target) for target in BUILD_TARGETS] 1332if 'all' in needed_envs: 1333 needed_envs += target_types 1334 1335def makeEnvirons(target, source, env): 1336 # cause any later Source() calls to be fatal, as a diagnostic. 1337 Source.done() 1338 1339 envList = [] 1340 1341 # Debug binary 1342 if 'debug' in needed_envs: 1343 envList.append( 1344 makeEnv(env, 'debug', '.do', 1345 CCFLAGS = Split(ccflags['debug']), 1346 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'], 1347 LINKFLAGS = Split(ldflags['debug']))) 1348 1349 # Optimized binary 1350 if 'opt' in needed_envs: 1351 envList.append( 1352 makeEnv(env, 'opt', '.o', 1353 CCFLAGS = Split(ccflags['opt']), 1354 CPPDEFINES = ['TRACING_ON=1'], 1355 LINKFLAGS = Split(ldflags['opt']))) 1356 1357 # "Fast" binary 1358 if 'fast' in needed_envs: 1359 envList.append( 1360 makeEnv(env, 'fast', '.fo', strip = True, 1361 CCFLAGS = Split(ccflags['fast']), 1362 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1363 LINKFLAGS = Split(ldflags['fast']))) 1364 1365 # Profiled binary using gprof 1366 if 'prof' in needed_envs: 1367 envList.append( 1368 makeEnv(env, 'prof', '.po', 1369 CCFLAGS = Split(ccflags['prof']), 1370 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1371 LINKFLAGS = Split(ldflags['prof']))) 1372 1373 # Profiled binary using google-pprof 1374 if 'perf' in needed_envs: 1375 envList.append( 1376 makeEnv(env, 'perf', '.gpo', 1377 CCFLAGS = Split(ccflags['perf']), 1378 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1379 LINKFLAGS = Split(ldflags['perf']))) 1380 1381 # Set up the regression tests for each build. 1382 for e in envList: 1383 SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'), 1384 variant_dir = variantd('tests', e.Label), 1385 exports = { 'env' : e }, duplicate = False) 1386 1387# The MakeEnvirons Builder defers the full dependency collection until 1388# after processing the ISA definition (due to dynamically generated 1389# source files). Add this dependency to all targets so they will wait 1390# until the environments are completely set up. Otherwise, a second 1391# process (e.g. -j2 or higher) will try to compile the requested target, 1392# not know how, and fail. 1393env.Append(BUILDERS = {'MakeEnvirons' : 1394 Builder(action=MakeAction(makeEnvirons, 1395 Transform("ENVIRONS", 1)))}) 1396 1397isa_target = env['PHONY_BASE'] + '-deps' 1398environs = env['PHONY_BASE'] + '-environs' 1399env.Depends('#all-deps', isa_target) 1400env.Depends('#all-environs', environs) 1401env.ScanISA(isa_target, File('arch/%s/generated/inc.d' % env['TARGET_ISA'])) 1402envSetup = env.MakeEnvirons(environs, isa_target) 1403 1404# make sure no -deps targets occur before all ISAs are complete 1405env.Depends(isa_target, '#all-isas') 1406# likewise for -environs targets and all the -deps targets 1407env.Depends(environs, '#all-deps') 1408