SConscript revision 11983:40e0c3829cfe
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 subprocess 38import sys 39import zlib 40 41from os.path import basename, dirname, exists, isdir, isfile, join as joinpath 42 43import SCons 44 45# This file defines how to build a particular configuration of gem5 46# based on variable settings in the 'env' build environment. 47 48Import('*') 49 50# Children need to see the environment 51Export('env') 52 53build_env = [(opt, env[opt]) for opt in export_vars] 54 55from m5.util import code_formatter, compareVersions 56 57######################################################################## 58# Code for adding source files of various types 59# 60# When specifying a source file of some type, a set of guards can be 61# specified for that file. When get() is used to find the files, if 62# get specifies a set of filters, only files that match those filters 63# will be accepted (unspecified filters on files are assumed to be 64# false). Current filters are: 65# main -- specifies the gem5 main() function 66# skip_lib -- do not put this file into the gem5 library 67# skip_no_python -- do not put this file into a no_python library 68# as it embeds compiled Python 69# <unittest> -- unit tests use filters based on the unit test name 70# 71# A parent can now be specified for a source file and default filter 72# values will be retrieved recursively from parents (children override 73# parents). 74# 75def guarded_source_iterator(sources, **guards): 76 '''Iterate over a set of sources, gated by a set of guards.''' 77 for src in sources: 78 for flag,value in guards.iteritems(): 79 # if the flag is found and has a different value, skip 80 # this file 81 if src.all_guards.get(flag, False) != value: 82 break 83 else: 84 yield src 85 86class SourceMeta(type): 87 '''Meta class for source files that keeps track of all files of a 88 particular type and has a get function for finding all functions 89 of a certain type that match a set of guards''' 90 def __init__(cls, name, bases, dict): 91 super(SourceMeta, cls).__init__(name, bases, dict) 92 cls.all = [] 93 94 def get(cls, **guards): 95 '''Find all files that match the specified guards. If a source 96 file does not specify a flag, the default is False''' 97 for s in guarded_source_iterator(cls.all, **guards): 98 yield s 99 100class SourceFile(object): 101 '''Base object that encapsulates the notion of a source file. 102 This includes, the source node, target node, various manipulations 103 of those. A source file also specifies a set of guards which 104 describing which builds the source file applies to. A parent can 105 also be specified to get default guards from''' 106 __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 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 363 364for extra_dir in extras_dir_list: 365 prefix_len = len(dirname(extra_dir)) + 1 366 367 # Also add the corresponding build directory to pick up generated 368 # include files. 369 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:]))) 370 371 for root, dirs, files in os.walk(extra_dir, topdown=True): 372 # if build lives in the extras directory, don't walk down it 373 if 'build' in dirs: 374 dirs.remove('build') 375 376 if 'SConscript' in files: 377 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 378 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 379 380for opt in export_vars: 381 env.ConfigFile(opt) 382 383def makeTheISA(source, target, env): 384 isas = [ src.get_contents() for src in source ] 385 target_isa = env['TARGET_ISA'] 386 def define(isa): 387 return isa.upper() + '_ISA' 388 389 def namespace(isa): 390 return isa[0].upper() + isa[1:].lower() + 'ISA' 391 392 393 code = code_formatter() 394 code('''\ 395#ifndef __CONFIG_THE_ISA_HH__ 396#define __CONFIG_THE_ISA_HH__ 397 398''') 399 400 # create defines for the preprocessing and compile-time determination 401 for i,isa in enumerate(isas): 402 code('#define $0 $1', define(isa), i + 1) 403 code() 404 405 # create an enum for any run-time determination of the ISA, we 406 # reuse the same name as the namespaces 407 code('enum class Arch {') 408 for i,isa in enumerate(isas): 409 if i + 1 == len(isas): 410 code(' $0 = $1', namespace(isa), define(isa)) 411 else: 412 code(' $0 = $1,', namespace(isa), define(isa)) 413 code('};') 414 415 code(''' 416 417#define THE_ISA ${{define(target_isa)}} 418#define TheISA ${{namespace(target_isa)}} 419#define THE_ISA_STR "${{target_isa}}" 420 421#endif // __CONFIG_THE_ISA_HH__''') 422 423 code.write(str(target[0])) 424 425env.Command('config/the_isa.hh', map(Value, all_isa_list), 426 MakeAction(makeTheISA, Transform("CFG ISA", 0))) 427 428def makeTheGPUISA(source, target, env): 429 isas = [ src.get_contents() for src in source ] 430 target_gpu_isa = env['TARGET_GPU_ISA'] 431 def define(isa): 432 return isa.upper() + '_ISA' 433 434 def namespace(isa): 435 return isa[0].upper() + isa[1:].lower() + 'ISA' 436 437 438 code = code_formatter() 439 code('''\ 440#ifndef __CONFIG_THE_GPU_ISA_HH__ 441#define __CONFIG_THE_GPU_ISA_HH__ 442 443''') 444 445 # create defines for the preprocessing and compile-time determination 446 for i,isa in enumerate(isas): 447 code('#define $0 $1', define(isa), i + 1) 448 code() 449 450 # create an enum for any run-time determination of the ISA, we 451 # reuse the same name as the namespaces 452 code('enum class GPUArch {') 453 for i,isa in enumerate(isas): 454 if i + 1 == len(isas): 455 code(' $0 = $1', namespace(isa), define(isa)) 456 else: 457 code(' $0 = $1,', namespace(isa), define(isa)) 458 code('};') 459 460 code(''' 461 462#define THE_GPU_ISA ${{define(target_gpu_isa)}} 463#define TheGpuISA ${{namespace(target_gpu_isa)}} 464#define THE_GPU_ISA_STR "${{target_gpu_isa}}" 465 466#endif // __CONFIG_THE_GPU_ISA_HH__''') 467 468 code.write(str(target[0])) 469 470env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list), 471 MakeAction(makeTheGPUISA, Transform("CFG ISA", 0))) 472 473######################################################################## 474# 475# Prevent any SimObjects from being added after this point, they 476# should all have been added in the SConscripts above 477# 478SimObject.fixed = True 479 480class DictImporter(object): 481 '''This importer takes a dictionary of arbitrary module names that 482 map to arbitrary filenames.''' 483 def __init__(self, modules): 484 self.modules = modules 485 self.installed = set() 486 487 def __del__(self): 488 self.unload() 489 490 def unload(self): 491 import sys 492 for module in self.installed: 493 del sys.modules[module] 494 self.installed = set() 495 496 def find_module(self, fullname, path): 497 if fullname == 'm5.defines': 498 return self 499 500 if fullname == 'm5.objects': 501 return self 502 503 if fullname.startswith('_m5'): 504 return None 505 506 source = self.modules.get(fullname, None) 507 if source is not None and fullname.startswith('m5.objects'): 508 return self 509 510 return None 511 512 def load_module(self, fullname): 513 mod = imp.new_module(fullname) 514 sys.modules[fullname] = mod 515 self.installed.add(fullname) 516 517 mod.__loader__ = self 518 if fullname == 'm5.objects': 519 mod.__path__ = fullname.split('.') 520 return mod 521 522 if fullname == 'm5.defines': 523 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 524 return mod 525 526 source = self.modules[fullname] 527 if source.modname == '__init__': 528 mod.__path__ = source.modpath 529 mod.__file__ = source.abspath 530 531 exec file(source.abspath, 'r') in mod.__dict__ 532 533 return mod 534 535import m5.SimObject 536import m5.params 537from m5.util import code_formatter 538 539m5.SimObject.clear() 540m5.params.clear() 541 542# install the python importer so we can grab stuff from the source 543# tree itself. We can't have SimObjects added after this point or 544# else we won't know about them for the rest of the stuff. 545importer = DictImporter(PySource.modules) 546sys.meta_path[0:0] = [ importer ] 547 548# import all sim objects so we can populate the all_objects list 549# make sure that we're working with a list, then let's sort it 550for modname in SimObject.modnames: 551 exec('from m5.objects import %s' % modname) 552 553# we need to unload all of the currently imported modules so that they 554# will be re-imported the next time the sconscript is run 555importer.unload() 556sys.meta_path.remove(importer) 557 558sim_objects = m5.SimObject.allClasses 559all_enums = m5.params.allEnums 560 561if m5.SimObject.noCxxHeader: 562 print >> sys.stderr, \ 563 "warning: At least one SimObject lacks a header specification. " \ 564 "This can cause unexpected results in the generated SWIG " \ 565 "wrappers." 566 567# Find param types that need to be explicitly wrapped with swig. 568# These will be recognized because the ParamDesc will have a 569# swig_decl() method. Most param types are based on types that don't 570# need this, either because they're based on native types (like Int) 571# or because they're SimObjects (which get swigged independently). 572# For now the only things handled here are VectorParam types. 573params_to_swig = {} 574for name,obj in sorted(sim_objects.iteritems()): 575 for param in obj._params.local.values(): 576 # load the ptype attribute now because it depends on the 577 # current version of SimObject.allClasses, but when scons 578 # actually uses the value, all versions of 579 # SimObject.allClasses will have been loaded 580 param.ptype 581 582 if not hasattr(param, 'swig_decl'): 583 continue 584 pname = param.ptype_str 585 if pname not in params_to_swig: 586 params_to_swig[pname] = param 587 588######################################################################## 589# 590# calculate extra dependencies 591# 592module_depends = ["m5", "m5.SimObject", "m5.params"] 593depends = [ PySource.modules[dep].snode for dep in module_depends ] 594depends.sort(key = lambda x: x.name) 595 596######################################################################## 597# 598# Commands for the basic automatically generated python files 599# 600 601# Generate Python file containing a dict specifying the current 602# buildEnv flags. 603def makeDefinesPyFile(target, source, env): 604 build_env = source[0].get_contents() 605 606 code = code_formatter() 607 code(""" 608import _m5.core 609import m5.util 610 611buildEnv = m5.util.SmartDict($build_env) 612 613compileDate = _m5.core.compileDate 614_globals = globals() 615for key,val in _m5.core.__dict__.iteritems(): 616 if key.startswith('flag_'): 617 flag = key[5:] 618 _globals[flag] = val 619del _globals 620""") 621 code.write(target[0].abspath) 622 623defines_info = Value(build_env) 624# Generate a file with all of the compile options in it 625env.Command('python/m5/defines.py', defines_info, 626 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 627PySource('m5', 'python/m5/defines.py') 628 629# Generate python file containing info about the M5 source code 630def makeInfoPyFile(target, source, env): 631 code = code_formatter() 632 for src in source: 633 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 634 code('$src = ${{repr(data)}}') 635 code.write(str(target[0])) 636 637# Generate a file that wraps the basic top level files 638env.Command('python/m5/info.py', 639 [ '#/COPYING', '#/LICENSE', '#/README', ], 640 MakeAction(makeInfoPyFile, Transform("INFO"))) 641PySource('m5', 'python/m5/info.py') 642 643######################################################################## 644# 645# Create all of the SimObject param headers and enum headers 646# 647 648def createSimObjectParamStruct(target, source, env): 649 assert len(target) == 1 and len(source) == 1 650 651 name = str(source[0].get_contents()) 652 obj = sim_objects[name] 653 654 code = code_formatter() 655 obj.cxx_param_decl(code) 656 code.write(target[0].abspath) 657 658def createSimObjectCxxConfig(is_header): 659 def body(target, source, env): 660 assert len(target) == 1 and len(source) == 1 661 662 name = str(source[0].get_contents()) 663 obj = sim_objects[name] 664 665 code = code_formatter() 666 obj.cxx_config_param_file(code, is_header) 667 code.write(target[0].abspath) 668 return body 669 670def createParamSwigWrapper(target, source, env): 671 assert len(target) == 1 and len(source) == 1 672 673 name = str(source[0].get_contents()) 674 param = params_to_swig[name] 675 676 code = code_formatter() 677 param.swig_decl(code) 678 code.write(target[0].abspath) 679 680def createEnumStrings(target, source, env): 681 assert len(target) == 1 and len(source) == 1 682 683 name = str(source[0].get_contents()) 684 obj = all_enums[name] 685 686 code = code_formatter() 687 obj.cxx_def(code) 688 code.write(target[0].abspath) 689 690def createEnumDecls(target, source, env): 691 assert len(target) == 1 and len(source) == 1 692 693 name = str(source[0].get_contents()) 694 obj = all_enums[name] 695 696 code = code_formatter() 697 obj.cxx_decl(code) 698 code.write(target[0].abspath) 699 700def createEnumSwigWrapper(target, source, env): 701 assert len(target) == 1 and len(source) == 1 702 703 name = str(source[0].get_contents()) 704 obj = all_enums[name] 705 706 code = code_formatter() 707 obj.swig_decl(code) 708 code.write(target[0].abspath) 709 710def createSimObjectSwigWrapper(target, source, env): 711 name = source[0].get_contents() 712 obj = sim_objects[name] 713 714 code = code_formatter() 715 obj.swig_decl(code) 716 code.write(target[0].abspath) 717 718# dummy target for generated code 719# we start out with all the Source files so they get copied to build/*/ also. 720SWIG = env.Dummy('swig', [s.tnode for s in Source.get()]) 721 722# Generate all of the SimObject param C++ struct header files 723params_hh_files = [] 724for name,simobj in sorted(sim_objects.iteritems()): 725 py_source = PySource.modules[simobj.__module__] 726 extra_deps = [ py_source.tnode ] 727 728 hh_file = File('params/%s.hh' % name) 729 params_hh_files.append(hh_file) 730 env.Command(hh_file, Value(name), 731 MakeAction(createSimObjectParamStruct, Transform("SO PARAM"))) 732 env.Depends(hh_file, depends + extra_deps) 733 env.Depends(SWIG, hh_file) 734 735# C++ parameter description files 736if GetOption('with_cxx_config'): 737 for name,simobj in sorted(sim_objects.iteritems()): 738 py_source = PySource.modules[simobj.__module__] 739 extra_deps = [ py_source.tnode ] 740 741 cxx_config_hh_file = File('cxx_config/%s.hh' % name) 742 cxx_config_cc_file = File('cxx_config/%s.cc' % name) 743 env.Command(cxx_config_hh_file, Value(name), 744 MakeAction(createSimObjectCxxConfig(True), 745 Transform("CXXCPRHH"))) 746 env.Command(cxx_config_cc_file, Value(name), 747 MakeAction(createSimObjectCxxConfig(False), 748 Transform("CXXCPRCC"))) 749 env.Depends(cxx_config_hh_file, depends + extra_deps + 750 [File('params/%s.hh' % name), File('sim/cxx_config.hh')]) 751 env.Depends(cxx_config_cc_file, depends + extra_deps + 752 [cxx_config_hh_file]) 753 Source(cxx_config_cc_file) 754 755 cxx_config_init_cc_file = File('cxx_config/init.cc') 756 757 def createCxxConfigInitCC(target, source, env): 758 assert len(target) == 1 and len(source) == 1 759 760 code = code_formatter() 761 762 for name,simobj in sorted(sim_objects.iteritems()): 763 if not hasattr(simobj, 'abstract') or not simobj.abstract: 764 code('#include "cxx_config/${name}.hh"') 765 code() 766 code('void cxxConfigInit()') 767 code('{') 768 code.indent() 769 for name,simobj in sorted(sim_objects.iteritems()): 770 not_abstract = not hasattr(simobj, 'abstract') or \ 771 not simobj.abstract 772 if not_abstract and 'type' in simobj.__dict__: 773 code('cxx_config_directory["${name}"] = ' 774 '${name}CxxConfigParams::makeDirectoryEntry();') 775 code.dedent() 776 code('}') 777 code.write(target[0].abspath) 778 779 py_source = PySource.modules[simobj.__module__] 780 extra_deps = [ py_source.tnode ] 781 env.Command(cxx_config_init_cc_file, Value(name), 782 MakeAction(createCxxConfigInitCC, Transform("CXXCINIT"))) 783 cxx_param_hh_files = ["cxx_config/%s.hh" % simobj 784 for name,simobj in sorted(sim_objects.iteritems()) 785 if not hasattr(simobj, 'abstract') or not simobj.abstract] 786 Depends(cxx_config_init_cc_file, cxx_param_hh_files + 787 [File('sim/cxx_config.hh')]) 788 Source(cxx_config_init_cc_file) 789 790# Generate any needed param SWIG wrapper files 791params_i_files = [] 792for name,param in sorted(params_to_swig.iteritems()): 793 i_file = File('python/_m5/%s.i' % (param.swig_module_name())) 794 params_i_files.append(i_file) 795 env.Command(i_file, Value(name), 796 MakeAction(createParamSwigWrapper, Transform("SW PARAM"))) 797 env.Depends(i_file, depends) 798 env.Depends(SWIG, i_file) 799 SwigSource('_m5', i_file) 800 801# Generate all enum header files 802for name,enum in sorted(all_enums.iteritems()): 803 py_source = PySource.modules[enum.__module__] 804 extra_deps = [ py_source.tnode ] 805 806 cc_file = File('enums/%s.cc' % name) 807 env.Command(cc_file, Value(name), 808 MakeAction(createEnumStrings, Transform("ENUM STR"))) 809 env.Depends(cc_file, depends + extra_deps) 810 env.Depends(SWIG, cc_file) 811 Source(cc_file) 812 813 hh_file = File('enums/%s.hh' % name) 814 env.Command(hh_file, Value(name), 815 MakeAction(createEnumDecls, Transform("ENUMDECL"))) 816 env.Depends(hh_file, depends + extra_deps) 817 env.Depends(SWIG, hh_file) 818 819 i_file = File('python/_m5/enum_%s.i' % name) 820 env.Command(i_file, Value(name), 821 MakeAction(createEnumSwigWrapper, Transform("ENUMSWIG"))) 822 env.Depends(i_file, depends + extra_deps) 823 env.Depends(SWIG, i_file) 824 SwigSource('_m5', i_file) 825 826# Generate SimObject SWIG wrapper files 827for name,simobj in sorted(sim_objects.iteritems()): 828 py_source = PySource.modules[simobj.__module__] 829 extra_deps = [ py_source.tnode ] 830 i_file = File('python/_m5/param_%s.i' % name) 831 env.Command(i_file, Value(name), 832 MakeAction(createSimObjectSwigWrapper, Transform("SO SWIG"))) 833 env.Depends(i_file, depends + extra_deps) 834 SwigSource('_m5', i_file) 835 836# Generate the main swig init file 837def makeEmbeddedSwigInit(package): 838 def body(target, source, env): 839 assert len(target) == 1 and len(source) == 1 840 841 code = code_formatter() 842 module = source[0].get_contents() 843 # Provide the full context so that the swig-generated call to 844 # Py_InitModule ends up placing the embedded module in the 845 # right package. 846 context = str(package) + "._" + str(module) 847 code('''\ 848 #include "sim/init.hh" 849 850 extern "C" { 851 void init_${module}(); 852 } 853 854 EmbeddedSwig embed_swig_${module}(init_${module}, "${context}"); 855 ''') 856 code.write(str(target[0])) 857 return body 858 859# Build all swig modules 860for swig in SwigSource.all: 861 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 862 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 863 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG"))) 864 cc_file = str(swig.tnode) 865 init_file = '%s/%s_init.cc' % (dirname(cc_file), basename(cc_file)) 866 env.Command(init_file, Value(swig.module), 867 MakeAction(makeEmbeddedSwigInit(swig.package), 868 Transform("EMBED SW"))) 869 env.Depends(SWIG, init_file) 870 Source(init_file, **swig.guards) 871 872# Build all protocol buffers if we have got protoc and protobuf available 873if env['HAVE_PROTOBUF']: 874 for proto in ProtoBuf.all: 875 # Use both the source and header as the target, and the .proto 876 # file as the source. When executing the protoc compiler, also 877 # specify the proto_path to avoid having the generated files 878 # include the path. 879 env.Command([proto.cc_file, proto.hh_file], proto.tnode, 880 MakeAction('$PROTOC --cpp_out ${TARGET.dir} ' 881 '--proto_path ${SOURCE.dir} $SOURCE', 882 Transform("PROTOC"))) 883 884 env.Depends(SWIG, [proto.cc_file, proto.hh_file]) 885 # Add the C++ source file 886 Source(proto.cc_file, **proto.guards) 887elif ProtoBuf.all: 888 print 'Got protobuf to build, but lacks support!' 889 Exit(1) 890 891# 892# Handle debug flags 893# 894def makeDebugFlagCC(target, source, env): 895 assert(len(target) == 1 and len(source) == 1) 896 897 code = code_formatter() 898 899 # delay definition of CompoundFlags until after all the definition 900 # of all constituent SimpleFlags 901 comp_code = code_formatter() 902 903 # file header 904 code(''' 905/* 906 * DO NOT EDIT THIS FILE! Automatically generated by SCons. 907 */ 908 909#include "base/debug.hh" 910 911namespace Debug { 912 913''') 914 915 for name, flag in sorted(source[0].read().iteritems()): 916 n, compound, desc = flag 917 assert n == name 918 919 if not compound: 920 code('SimpleFlag $name("$name", "$desc");') 921 else: 922 comp_code('CompoundFlag $name("$name", "$desc",') 923 comp_code.indent() 924 last = len(compound) - 1 925 for i,flag in enumerate(compound): 926 if i != last: 927 comp_code('&$flag,') 928 else: 929 comp_code('&$flag);') 930 comp_code.dedent() 931 932 code.append(comp_code) 933 code() 934 code('} // namespace Debug') 935 936 code.write(str(target[0])) 937 938def makeDebugFlagHH(target, source, env): 939 assert(len(target) == 1 and len(source) == 1) 940 941 val = eval(source[0].get_contents()) 942 name, compound, desc = val 943 944 code = code_formatter() 945 946 # file header boilerplate 947 code('''\ 948/* 949 * DO NOT EDIT THIS FILE! Automatically generated by SCons. 950 */ 951 952#ifndef __DEBUG_${name}_HH__ 953#define __DEBUG_${name}_HH__ 954 955namespace Debug { 956''') 957 958 if compound: 959 code('class CompoundFlag;') 960 code('class SimpleFlag;') 961 962 if compound: 963 code('extern CompoundFlag $name;') 964 for flag in compound: 965 code('extern SimpleFlag $flag;') 966 else: 967 code('extern SimpleFlag $name;') 968 969 code(''' 970} 971 972#endif // __DEBUG_${name}_HH__ 973''') 974 975 code.write(str(target[0])) 976 977for name,flag in sorted(debug_flags.iteritems()): 978 n, compound, desc = flag 979 assert n == name 980 981 hh_file = 'debug/%s.hh' % name 982 env.Command(hh_file, Value(flag), 983 MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) 984 env.Depends(SWIG, hh_file) 985 986env.Command('debug/flags.cc', Value(debug_flags), 987 MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) 988env.Depends(SWIG, 'debug/flags.cc') 989Source('debug/flags.cc') 990 991# version tags 992tags = \ 993env.Command('sim/tags.cc', None, 994 MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET', 995 Transform("VER TAGS"))) 996env.AlwaysBuild(tags) 997 998# Embed python files. All .py files that have been indicated by a 999# PySource() call in a SConscript need to be embedded into the M5 1000# library. To do that, we compile the file to byte code, marshal the 1001# byte code, compress it, and then generate a c++ file that 1002# inserts the result into an array. 1003def embedPyFile(target, source, env): 1004 def c_str(string): 1005 if string is None: 1006 return "0" 1007 return '"%s"' % string 1008 1009 '''Action function to compile a .py into a code object, marshal 1010 it, compress it, and stick it into an asm file so the code appears 1011 as just bytes with a label in the data section''' 1012 1013 src = file(str(source[0]), 'r').read() 1014 1015 pysource = PySource.tnodes[source[0]] 1016 compiled = compile(src, pysource.abspath, 'exec') 1017 marshalled = marshal.dumps(compiled) 1018 compressed = zlib.compress(marshalled) 1019 data = compressed 1020 sym = pysource.symname 1021 1022 code = code_formatter() 1023 code('''\ 1024#include "sim/init.hh" 1025 1026namespace { 1027 1028const uint8_t data_${sym}[] = { 1029''') 1030 code.indent() 1031 step = 16 1032 for i in xrange(0, len(data), step): 1033 x = array.array('B', data[i:i+step]) 1034 code(''.join('%d,' % d for d in x)) 1035 code.dedent() 1036 1037 code('''}; 1038 1039EmbeddedPython embedded_${sym}( 1040 ${{c_str(pysource.arcname)}}, 1041 ${{c_str(pysource.abspath)}}, 1042 ${{c_str(pysource.modpath)}}, 1043 data_${sym}, 1044 ${{len(data)}}, 1045 ${{len(marshalled)}}); 1046 1047} // anonymous namespace 1048''') 1049 code.write(str(target[0])) 1050 1051for source in PySource.all: 1052 env.Command(source.cpp, source.tnode, 1053 MakeAction(embedPyFile, Transform("EMBED PY"))) 1054 env.Depends(SWIG, source.cpp) 1055 Source(source.cpp, skip_no_python=True) 1056 1057######################################################################## 1058# 1059# Define binaries. Each different build type (debug, opt, etc.) gets 1060# a slightly different build environment. 1061# 1062 1063# List of constructed environments to pass back to SConstruct 1064date_source = Source('base/date.cc', skip_lib=True) 1065 1066# Capture this directory for the closure makeEnv, otherwise when it is 1067# called, it won't know what directory it should use. 1068variant_dir = Dir('.').path 1069def variant(*path): 1070 return os.path.join(variant_dir, *path) 1071def variantd(*path): 1072 return variant(*path)+'/' 1073 1074# Function to create a new build environment as clone of current 1075# environment 'env' with modified object suffix and optional stripped 1076# binary. Additional keyword arguments are appended to corresponding 1077# build environment vars. 1078def makeEnv(env, label, objsfx, strip = False, **kwargs): 1079 # SCons doesn't know to append a library suffix when there is a '.' in the 1080 # name. Use '_' instead. 1081 libname = variant('gem5_' + label) 1082 exename = variant('gem5.' + label) 1083 secondary_exename = variant('m5.' + label) 1084 1085 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 1086 new_env.Label = label 1087 new_env.Append(**kwargs) 1088 1089 swig_env = new_env.Clone() 1090 1091 # Both gcc and clang have issues with unused labels and values in 1092 # the SWIG generated code 1093 swig_env.Append(CCFLAGS=['-Wno-unused-label', '-Wno-unused-value']) 1094 1095 if env['GCC']: 1096 # Depending on the SWIG version, we also need to supress 1097 # warnings about uninitialized variables and missing field 1098 # initializers. 1099 swig_env.Append(CCFLAGS=['-Wno-uninitialized', 1100 '-Wno-missing-field-initializers', 1101 '-Wno-unused-but-set-variable', 1102 '-Wno-maybe-uninitialized', 1103 '-Wno-type-limits']) 1104 1105 1106 # The address sanitizer is available for gcc >= 4.8 1107 if GetOption('with_asan'): 1108 if GetOption('with_ubsan') and \ 1109 compareVersions(env['GCC_VERSION'], '4.9') >= 0: 1110 new_env.Append(CCFLAGS=['-fsanitize=address,undefined', 1111 '-fno-omit-frame-pointer']) 1112 new_env.Append(LINKFLAGS='-fsanitize=address,undefined') 1113 else: 1114 new_env.Append(CCFLAGS=['-fsanitize=address', 1115 '-fno-omit-frame-pointer']) 1116 new_env.Append(LINKFLAGS='-fsanitize=address') 1117 # Only gcc >= 4.9 supports UBSan, so check both the version 1118 # and the command-line option before adding the compiler and 1119 # linker flags. 1120 elif GetOption('with_ubsan') and \ 1121 compareVersions(env['GCC_VERSION'], '4.9') >= 0: 1122 new_env.Append(CCFLAGS='-fsanitize=undefined') 1123 new_env.Append(LINKFLAGS='-fsanitize=undefined') 1124 1125 1126 if env['CLANG']: 1127 swig_env.Append(CCFLAGS=['-Wno-sometimes-uninitialized', 1128 '-Wno-deprecated-register', 1129 '-Wno-tautological-compare']) 1130 1131 # We require clang >= 3.1, so there is no need to check any 1132 # versions here. 1133 if GetOption('with_ubsan'): 1134 if GetOption('with_asan'): 1135 new_env.Append(CCFLAGS=['-fsanitize=address,undefined', 1136 '-fno-omit-frame-pointer']) 1137 new_env.Append(LINKFLAGS='-fsanitize=address,undefined') 1138 else: 1139 new_env.Append(CCFLAGS='-fsanitize=undefined') 1140 new_env.Append(LINKFLAGS='-fsanitize=undefined') 1141 1142 elif GetOption('with_asan'): 1143 new_env.Append(CCFLAGS=['-fsanitize=address', 1144 '-fno-omit-frame-pointer']) 1145 new_env.Append(LINKFLAGS='-fsanitize=address') 1146 1147 werror_env = new_env.Clone() 1148 # Treat warnings as errors but white list some warnings that we 1149 # want to allow (e.g., deprecation warnings). 1150 werror_env.Append(CCFLAGS=['-Werror', 1151 '-Wno-error=deprecated-declarations', 1152 '-Wno-error=deprecated', 1153 ]) 1154 1155 def make_obj(source, static, extra_deps = None): 1156 '''This function adds the specified source to the correct 1157 build environment, and returns the corresponding SCons Object 1158 nodes''' 1159 1160 if source.swig: 1161 env = swig_env 1162 elif source.Werror: 1163 env = werror_env 1164 else: 1165 env = new_env 1166 1167 if static: 1168 obj = env.StaticObject(source.tnode) 1169 else: 1170 obj = env.SharedObject(source.tnode) 1171 1172 if extra_deps: 1173 env.Depends(obj, extra_deps) 1174 1175 return obj 1176 1177 lib_guards = {'main': False, 'skip_lib': False} 1178 1179 # Without Python, leave out all SWIG and Python content from the 1180 # library builds. The option doesn't affect gem5 built as a program 1181 if GetOption('without_python'): 1182 lib_guards['skip_no_python'] = False 1183 1184 static_objs = [] 1185 shared_objs = [] 1186 for s in guarded_source_iterator(Source.source_groups[None], **lib_guards): 1187 static_objs.append(make_obj(s, True)) 1188 shared_objs.append(make_obj(s, False)) 1189 1190 partial_objs = [] 1191 for group, all_srcs in Source.source_groups.iteritems(): 1192 # If these are the ungrouped source files, skip them. 1193 if not group: 1194 continue 1195 1196 # Get a list of the source files compatible with the current guards. 1197 srcs = [ s for s in guarded_source_iterator(all_srcs, **lib_guards) ] 1198 # If there aren't any left, skip this group. 1199 if not srcs: 1200 continue 1201 1202 # Set up the static partially linked objects. 1203 source_objs = [ make_obj(s, True) for s in srcs ] 1204 file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial") 1205 target = File(joinpath(group, file_name)) 1206 partial = env.PartialStatic(target=target, source=source_objs) 1207 static_objs.append(partial) 1208 1209 # Set up the shared partially linked objects. 1210 source_objs = [ make_obj(s, False) for s in srcs ] 1211 file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial") 1212 target = File(joinpath(group, file_name)) 1213 partial = env.PartialShared(target=target, source=source_objs) 1214 shared_objs.append(partial) 1215 1216 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 1217 static_objs.append(static_date) 1218 1219 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 1220 shared_objs.append(shared_date) 1221 1222 # First make a library of everything but main() so other programs can 1223 # link against m5. 1224 static_lib = new_env.StaticLibrary(libname, static_objs) 1225 shared_lib = new_env.SharedLibrary(libname, shared_objs) 1226 1227 # Now link a stub with main() and the static library. 1228 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ] 1229 1230 for test in UnitTest.all: 1231 flags = { test.target : True } 1232 test_sources = Source.get(**flags) 1233 test_objs = [ make_obj(s, static=True) for s in test_sources ] 1234 if test.main: 1235 test_objs += main_objs 1236 path = variant('unittest/%s.%s' % (test.target, label)) 1237 new_env.Program(path, test_objs + static_objs) 1238 1239 progname = exename 1240 if strip: 1241 progname += '.unstripped' 1242 1243 # When linking the gem5 binary, the command line can be too big for the 1244 # shell to handle. Use "subprocess" to spawn processes without passing 1245 # through the shell to avoid this problem. That means we also can't use 1246 # shell syntax in any of the commands this will run, but that isn't 1247 # currently an issue. 1248 def spawn_with_subprocess(sh, escape, cmd, args, env): 1249 return subprocess.call(args, env=env) 1250 1251 # Since we're not running through a shell, no escaping is necessary either. 1252 targets = new_env.Program(progname, main_objs + static_objs, 1253 SPAWN=spawn_with_subprocess, 1254 ESCAPE=lambda x: x) 1255 1256 if strip: 1257 if sys.platform == 'sunos5': 1258 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 1259 else: 1260 cmd = 'strip $SOURCE -o $TARGET' 1261 targets = new_env.Command(exename, progname, 1262 MakeAction(cmd, Transform("STRIP"))) 1263 1264 new_env.Command(secondary_exename, exename, 1265 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK"))) 1266 1267 new_env.M5Binary = targets[0] 1268 return new_env 1269 1270# Start out with the compiler flags common to all compilers, 1271# i.e. they all use -g for opt and -g -pg for prof 1272ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'], 1273 'perf' : ['-g']} 1274 1275# Start out with the linker flags common to all linkers, i.e. -pg for 1276# prof, and -lprofiler for perf. The -lprofile flag is surrounded by 1277# no-as-needed and as-needed as the binutils linker is too clever and 1278# simply doesn't link to the library otherwise. 1279ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'], 1280 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']} 1281 1282# For Link Time Optimization, the optimisation flags used to compile 1283# individual files are decoupled from those used at link time 1284# (i.e. you can compile with -O3 and perform LTO with -O0), so we need 1285# to also update the linker flags based on the target. 1286if env['GCC']: 1287 if sys.platform == 'sunos5': 1288 ccflags['debug'] += ['-gstabs+'] 1289 else: 1290 ccflags['debug'] += ['-ggdb3'] 1291 ldflags['debug'] += ['-O0'] 1292 # opt, fast, prof and perf all share the same cc flags, also add 1293 # the optimization to the ldflags as LTO defers the optimization 1294 # to link time 1295 for target in ['opt', 'fast', 'prof', 'perf']: 1296 ccflags[target] += ['-O3'] 1297 ldflags[target] += ['-O3'] 1298 1299 ccflags['fast'] += env['LTO_CCFLAGS'] 1300 ldflags['fast'] += env['LTO_LDFLAGS'] 1301elif env['CLANG']: 1302 ccflags['debug'] += ['-g', '-O0'] 1303 # opt, fast, prof and perf all share the same cc flags 1304 for target in ['opt', 'fast', 'prof', 'perf']: 1305 ccflags[target] += ['-O3'] 1306else: 1307 print 'Unknown compiler, please fix compiler options' 1308 Exit(1) 1309 1310 1311# To speed things up, we only instantiate the build environments we 1312# need. We try to identify the needed environment for each target; if 1313# we can't, we fall back on instantiating all the environments just to 1314# be safe. 1315target_types = ['debug', 'opt', 'fast', 'prof', 'perf'] 1316obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof', 1317 'gpo' : 'perf'} 1318 1319def identifyTarget(t): 1320 ext = t.split('.')[-1] 1321 if ext in target_types: 1322 return ext 1323 if obj2target.has_key(ext): 1324 return obj2target[ext] 1325 match = re.search(r'/tests/([^/]+)/', t) 1326 if match and match.group(1) in target_types: 1327 return match.group(1) 1328 return 'all' 1329 1330needed_envs = [identifyTarget(target) for target in BUILD_TARGETS] 1331if 'all' in needed_envs: 1332 needed_envs += target_types 1333 1334def makeEnvirons(target, source, env): 1335 # cause any later Source() calls to be fatal, as a diagnostic. 1336 Source.done() 1337 1338 envList = [] 1339 1340 # Debug binary 1341 if 'debug' in needed_envs: 1342 envList.append( 1343 makeEnv(env, 'debug', '.do', 1344 CCFLAGS = Split(ccflags['debug']), 1345 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'], 1346 LINKFLAGS = Split(ldflags['debug']))) 1347 1348 # Optimized binary 1349 if 'opt' in needed_envs: 1350 envList.append( 1351 makeEnv(env, 'opt', '.o', 1352 CCFLAGS = Split(ccflags['opt']), 1353 CPPDEFINES = ['TRACING_ON=1'], 1354 LINKFLAGS = Split(ldflags['opt']))) 1355 1356 # "Fast" binary 1357 if 'fast' in needed_envs: 1358 envList.append( 1359 makeEnv(env, 'fast', '.fo', strip = True, 1360 CCFLAGS = Split(ccflags['fast']), 1361 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1362 LINKFLAGS = Split(ldflags['fast']))) 1363 1364 # Profiled binary using gprof 1365 if 'prof' in needed_envs: 1366 envList.append( 1367 makeEnv(env, 'prof', '.po', 1368 CCFLAGS = Split(ccflags['prof']), 1369 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1370 LINKFLAGS = Split(ldflags['prof']))) 1371 1372 # Profiled binary using google-pprof 1373 if 'perf' in needed_envs: 1374 envList.append( 1375 makeEnv(env, 'perf', '.gpo', 1376 CCFLAGS = Split(ccflags['perf']), 1377 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1378 LINKFLAGS = Split(ldflags['perf']))) 1379 1380 # Set up the regression tests for each build. 1381 for e in envList: 1382 SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'), 1383 variant_dir = variantd('tests', e.Label), 1384 exports = { 'env' : e }, duplicate = False) 1385 1386# The MakeEnvirons Builder defers the full dependency collection until 1387# after processing the ISA definition (due to dynamically generated 1388# source files). Add this dependency to all targets so they will wait 1389# until the environments are completely set up. Otherwise, a second 1390# process (e.g. -j2 or higher) will try to compile the requested target, 1391# not know how, and fail. 1392env.Append(BUILDERS = {'MakeEnvirons' : 1393 Builder(action=MakeAction(makeEnvirons, 1394 Transform("ENVIRONS", 1)))}) 1395 1396isa_target = env['PHONY_BASE'] + '-deps' 1397environs = env['PHONY_BASE'] + '-environs' 1398env.Depends('#all-deps', isa_target) 1399env.Depends('#all-environs', environs) 1400env.ScanISA(isa_target, File('arch/%s/generated/inc.d' % env['TARGET_ISA'])) 1401envSetup = env.MakeEnvirons(environs, isa_target) 1402 1403# make sure no -deps targets occur before all ISAs are complete 1404env.Depends(isa_target, '#all-isas') 1405# likewise for -environs targets and all the -deps targets 1406env.Depends(environs, '#all-deps') 1407