SConscript revision 11983
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