Deleted Added
sdiff udiff text old ( 11985:03e3d059c4b9 ) new ( 11988:665cd5f8b52b )
full compact
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 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 targets = new_env.Program(progname, main_objs + static_objs)
1245
1246 if strip:
1247 if sys.platform == 'sunos5':
1248 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1249 else:
1250 cmd = 'strip $SOURCE -o $TARGET'
1251 targets = new_env.Command(exename, progname,
1252 MakeAction(cmd, Transform("STRIP")))
1253
1254 new_env.Command(secondary_exename, exename,
1255 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK")))
1256
1257 new_env.M5Binary = targets[0]
1258 return new_env
1259
1260# Start out with the compiler flags common to all compilers,
1261# i.e. they all use -g for opt and -g -pg for prof
1262ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'],
1263 'perf' : ['-g']}
1264
1265# Start out with the linker flags common to all linkers, i.e. -pg for
1266# prof, and -lprofiler for perf. The -lprofile flag is surrounded by
1267# no-as-needed and as-needed as the binutils linker is too clever and
1268# simply doesn't link to the library otherwise.
1269ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'],
1270 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']}
1271
1272# For Link Time Optimization, the optimisation flags used to compile
1273# individual files are decoupled from those used at link time
1274# (i.e. you can compile with -O3 and perform LTO with -O0), so we need
1275# to also update the linker flags based on the target.
1276if env['GCC']:
1277 if sys.platform == 'sunos5':
1278 ccflags['debug'] += ['-gstabs+']
1279 else:
1280 ccflags['debug'] += ['-ggdb3']
1281 ldflags['debug'] += ['-O0']
1282 # opt, fast, prof and perf all share the same cc flags, also add
1283 # the optimization to the ldflags as LTO defers the optimization
1284 # to link time
1285 for target in ['opt', 'fast', 'prof', 'perf']:
1286 ccflags[target] += ['-O3']
1287 ldflags[target] += ['-O3']
1288
1289 ccflags['fast'] += env['LTO_CCFLAGS']
1290 ldflags['fast'] += env['LTO_LDFLAGS']
1291elif env['CLANG']:
1292 ccflags['debug'] += ['-g', '-O0']
1293 # opt, fast, prof and perf all share the same cc flags
1294 for target in ['opt', 'fast', 'prof', 'perf']:
1295 ccflags[target] += ['-O3']
1296else:
1297 print 'Unknown compiler, please fix compiler options'
1298 Exit(1)
1299
1300
1301# To speed things up, we only instantiate the build environments we
1302# need. We try to identify the needed environment for each target; if
1303# we can't, we fall back on instantiating all the environments just to
1304# be safe.
1305target_types = ['debug', 'opt', 'fast', 'prof', 'perf']
1306obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof',
1307 'gpo' : 'perf'}
1308
1309def identifyTarget(t):
1310 ext = t.split('.')[-1]
1311 if ext in target_types:
1312 return ext
1313 if obj2target.has_key(ext):
1314 return obj2target[ext]
1315 match = re.search(r'/tests/([^/]+)/', t)
1316 if match and match.group(1) in target_types:
1317 return match.group(1)
1318 return 'all'
1319
1320needed_envs = [identifyTarget(target) for target in BUILD_TARGETS]
1321if 'all' in needed_envs:
1322 needed_envs += target_types
1323
1324def makeEnvirons(target, source, env):
1325 # cause any later Source() calls to be fatal, as a diagnostic.
1326 Source.done()
1327
1328 envList = []
1329
1330 # Debug binary
1331 if 'debug' in needed_envs:
1332 envList.append(
1333 makeEnv(env, 'debug', '.do',
1334 CCFLAGS = Split(ccflags['debug']),
1335 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'],
1336 LINKFLAGS = Split(ldflags['debug'])))
1337
1338 # Optimized binary
1339 if 'opt' in needed_envs:
1340 envList.append(
1341 makeEnv(env, 'opt', '.o',
1342 CCFLAGS = Split(ccflags['opt']),
1343 CPPDEFINES = ['TRACING_ON=1'],
1344 LINKFLAGS = Split(ldflags['opt'])))
1345
1346 # "Fast" binary
1347 if 'fast' in needed_envs:
1348 envList.append(
1349 makeEnv(env, 'fast', '.fo', strip = True,
1350 CCFLAGS = Split(ccflags['fast']),
1351 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1352 LINKFLAGS = Split(ldflags['fast'])))
1353
1354 # Profiled binary using gprof
1355 if 'prof' in needed_envs:
1356 envList.append(
1357 makeEnv(env, 'prof', '.po',
1358 CCFLAGS = Split(ccflags['prof']),
1359 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1360 LINKFLAGS = Split(ldflags['prof'])))
1361
1362 # Profiled binary using google-pprof
1363 if 'perf' in needed_envs:
1364 envList.append(
1365 makeEnv(env, 'perf', '.gpo',
1366 CCFLAGS = Split(ccflags['perf']),
1367 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1368 LINKFLAGS = Split(ldflags['perf'])))
1369
1370 # Set up the regression tests for each build.
1371 for e in envList:
1372 SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'),
1373 variant_dir = variantd('tests', e.Label),
1374 exports = { 'env' : e }, duplicate = False)
1375
1376# The MakeEnvirons Builder defers the full dependency collection until
1377# after processing the ISA definition (due to dynamically generated
1378# source files). Add this dependency to all targets so they will wait
1379# until the environments are completely set up. Otherwise, a second
1380# process (e.g. -j2 or higher) will try to compile the requested target,
1381# not know how, and fail.
1382env.Append(BUILDERS = {'MakeEnvirons' :
1383 Builder(action=MakeAction(makeEnvirons,
1384 Transform("ENVIRONS", 1)))})
1385
1386isa_target = env['PHONY_BASE'] + '-deps'
1387environs = env['PHONY_BASE'] + '-environs'
1388env.Depends('#all-deps', isa_target)
1389env.Depends('#all-environs', environs)
1390env.ScanISA(isa_target, File('arch/%s/generated/inc.d' % env['TARGET_ISA']))
1391envSetup = env.MakeEnvirons(environs, isa_target)
1392
1393# make sure no -deps targets occur before all ISAs are complete
1394env.Depends(isa_target, '#all-isas')
1395# likewise for -environs targets and all the -deps targets
1396env.Depends(environs, '#all-deps')