SConscript revision 8232
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 sys
38import zlib
39
40from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
41
42import SCons
43
44# This file defines how to build a particular configuration of M5
45# based on variable settings in the 'env' build environment.
46
47Import('*')
48
49# Children need to see the environment
50Export('env')
51
52build_env = [(opt, env[opt]) for opt in export_vars]
53
54from m5.util import code_formatter
55
56########################################################################
57# Code for adding source files of various types
58#
59class SourceMeta(type):
60    def __init__(cls, name, bases, dict):
61        super(SourceMeta, cls).__init__(name, bases, dict)
62        cls.all = []
63        
64    def get(cls, **kwargs):
65        for src in cls.all:
66            for attr,value in kwargs.iteritems():
67                if getattr(src, attr) != value:
68                    break
69            else:
70                yield src
71
72class SourceFile(object):
73    __metaclass__ = SourceMeta
74    def __init__(self, source):
75        tnode = source
76        if not isinstance(source, SCons.Node.FS.File):
77            tnode = File(source)
78
79        self.tnode = tnode
80        self.snode = tnode.srcnode()
81        self.filename = str(tnode)
82        self.dirname = dirname(self.filename)
83        self.basename = basename(self.filename)
84        index = self.basename.rfind('.')
85        if index <= 0:
86            # dot files aren't extensions
87            self.extname = self.basename, None
88        else:
89            self.extname = self.basename[:index], self.basename[index+1:]
90
91        for base in type(self).__mro__:
92            if issubclass(base, SourceFile):
93                base.all.append(self)
94
95    def __lt__(self, other): return self.filename < other.filename
96    def __le__(self, other): return self.filename <= other.filename
97    def __gt__(self, other): return self.filename > other.filename
98    def __ge__(self, other): return self.filename >= other.filename
99    def __eq__(self, other): return self.filename == other.filename
100    def __ne__(self, other): return self.filename != other.filename
101        
102class Source(SourceFile):
103    '''Add a c/c++ source file to the build'''
104    def __init__(self, source, Werror=True, swig=False, bin_only=False,
105                 skip_lib=False):
106        super(Source, self).__init__(source)
107
108        self.Werror = Werror
109        self.swig = swig
110        self.bin_only = bin_only
111        self.skip_lib = bin_only or skip_lib
112
113class PySource(SourceFile):
114    '''Add a python source file to the named package'''
115    invalid_sym_char = re.compile('[^A-z0-9_]')
116    modules = {}
117    tnodes = {}
118    symnames = {}
119    
120    def __init__(self, package, source):
121        super(PySource, self).__init__(source)
122
123        modname,ext = self.extname
124        assert ext == 'py'
125
126        if package:
127            path = package.split('.')
128        else:
129            path = []
130
131        modpath = path[:]
132        if modname != '__init__':
133            modpath += [ modname ]
134        modpath = '.'.join(modpath)
135
136        arcpath = path + [ self.basename ]
137        abspath = self.snode.abspath
138        if not exists(abspath):
139            abspath = self.tnode.abspath
140
141        self.package = package
142        self.modname = modname
143        self.modpath = modpath
144        self.arcname = joinpath(*arcpath)
145        self.abspath = abspath
146        self.compiled = File(self.filename + 'c')
147        self.cpp = File(self.filename + '.cc')
148        self.symname = PySource.invalid_sym_char.sub('_', modpath)
149
150        PySource.modules[modpath] = self
151        PySource.tnodes[self.tnode] = self
152        PySource.symnames[self.symname] = self
153
154class SimObject(PySource):
155    '''Add a SimObject python file as a python source object and add
156    it to a list of sim object modules'''
157
158    fixed = False
159    modnames = []
160
161    def __init__(self, source):
162        super(SimObject, self).__init__('m5.objects', source)
163        if self.fixed:
164            raise AttributeError, "Too late to call SimObject now."
165
166        bisect.insort_right(SimObject.modnames, self.modname)
167
168class SwigSource(SourceFile):
169    '''Add a swig file to build'''
170
171    def __init__(self, package, source):
172        super(SwigSource, self).__init__(source)
173
174        modname,ext = self.extname
175        assert ext == 'i'
176
177        self.module = modname
178        cc_file = joinpath(self.dirname, modname + '_wrap.cc')
179        py_file = joinpath(self.dirname, modname + '.py')
180
181        self.cc_source = Source(cc_file, swig=True)
182        self.py_source = PySource(package, py_file)
183
184unit_tests = []
185def UnitTest(target, sources):
186    if not isinstance(sources, (list, tuple)):
187        sources = [ sources ]
188
189    sources = [ Source(src, skip_lib=True) for src in sources ]
190    unit_tests.append((target, sources))
191
192# Children should have access
193Export('Source')
194Export('PySource')
195Export('SimObject')
196Export('SwigSource')
197Export('UnitTest')
198
199########################################################################
200#
201# Debug Flags
202#
203debug_flags = {}
204def DebugFlag(name, desc=None):
205    if name in debug_flags:
206        raise AttributeError, "Flag %s already specified" % name
207    debug_flags[name] = (name, (), desc)
208TraceFlag = DebugFlag
209
210def CompoundFlag(name, flags, desc=None):
211    if name in debug_flags:
212        raise AttributeError, "Flag %s already specified" % name
213
214    compound = tuple(flags)
215    debug_flags[name] = (name, compound, desc)
216
217Export('DebugFlag')
218Export('TraceFlag')
219Export('CompoundFlag')
220
221########################################################################
222#
223# Set some compiler variables
224#
225
226# Include file paths are rooted in this directory.  SCons will
227# automatically expand '.' to refer to both the source directory and
228# the corresponding build directory to pick up generated include
229# files.
230env.Append(CPPPATH=Dir('.'))
231
232for extra_dir in extras_dir_list:
233    env.Append(CPPPATH=Dir(extra_dir))
234
235# Workaround for bug in SCons version > 0.97d20071212
236# Scons bug id: 2006 M5 Bug id: 308 
237for root, dirs, files in os.walk(base_dir, topdown=True):
238    Dir(root[len(base_dir) + 1:])
239
240########################################################################
241#
242# Walk the tree and execute all SConscripts in subdirectories
243#
244
245here = Dir('.').srcnode().abspath
246for root, dirs, files in os.walk(base_dir, topdown=True):
247    if root == here:
248        # we don't want to recurse back into this SConscript
249        continue
250
251    if 'SConscript' in files:
252        build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
253        SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
254
255for extra_dir in extras_dir_list:
256    prefix_len = len(dirname(extra_dir)) + 1
257    for root, dirs, files in os.walk(extra_dir, topdown=True):
258        if 'SConscript' in files:
259            build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
260            SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
261
262for opt in export_vars:
263    env.ConfigFile(opt)
264
265def makeTheISA(source, target, env):
266    isas = [ src.get_contents() for src in source ]
267    target_isa = env['TARGET_ISA']
268    def define(isa):
269        return isa.upper() + '_ISA'
270    
271    def namespace(isa):
272        return isa[0].upper() + isa[1:].lower() + 'ISA' 
273
274
275    code = code_formatter()
276    code('''\
277#ifndef __CONFIG_THE_ISA_HH__
278#define __CONFIG_THE_ISA_HH__
279
280''')
281
282    for i,isa in enumerate(isas):
283        code('#define $0 $1', define(isa), i + 1)
284
285    code('''
286
287#define THE_ISA ${{define(target_isa)}}
288#define TheISA ${{namespace(target_isa)}}
289
290#endif // __CONFIG_THE_ISA_HH__''')
291
292    code.write(str(target[0]))
293
294env.Command('config/the_isa.hh', map(Value, all_isa_list),
295            MakeAction(makeTheISA, Transform("CFG ISA", 0)))
296
297########################################################################
298#
299# Prevent any SimObjects from being added after this point, they
300# should all have been added in the SConscripts above
301#
302SimObject.fixed = True
303
304class DictImporter(object):
305    '''This importer takes a dictionary of arbitrary module names that
306    map to arbitrary filenames.'''
307    def __init__(self, modules):
308        self.modules = modules
309        self.installed = set()
310
311    def __del__(self):
312        self.unload()
313
314    def unload(self):
315        import sys
316        for module in self.installed:
317            del sys.modules[module]
318        self.installed = set()
319
320    def find_module(self, fullname, path):
321        if fullname == 'm5.defines':
322            return self
323
324        if fullname == 'm5.objects':
325            return self
326
327        if fullname.startswith('m5.internal'):
328            return None
329
330        source = self.modules.get(fullname, None)
331        if source is not None and fullname.startswith('m5.objects'):
332            return self
333
334        return None
335
336    def load_module(self, fullname):
337        mod = imp.new_module(fullname)
338        sys.modules[fullname] = mod
339        self.installed.add(fullname)
340
341        mod.__loader__ = self
342        if fullname == 'm5.objects':
343            mod.__path__ = fullname.split('.')
344            return mod
345
346        if fullname == 'm5.defines':
347            mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
348            return mod
349
350        source = self.modules[fullname]
351        if source.modname == '__init__':
352            mod.__path__ = source.modpath
353        mod.__file__ = source.abspath
354
355        exec file(source.abspath, 'r') in mod.__dict__
356
357        return mod
358
359import m5.SimObject
360import m5.params
361from m5.util import code_formatter
362
363m5.SimObject.clear()
364m5.params.clear()
365
366# install the python importer so we can grab stuff from the source
367# tree itself.  We can't have SimObjects added after this point or
368# else we won't know about them for the rest of the stuff.
369importer = DictImporter(PySource.modules)
370sys.meta_path[0:0] = [ importer ]
371
372# import all sim objects so we can populate the all_objects list
373# make sure that we're working with a list, then let's sort it
374for modname in SimObject.modnames:
375    exec('from m5.objects import %s' % modname)
376
377# we need to unload all of the currently imported modules so that they
378# will be re-imported the next time the sconscript is run
379importer.unload()
380sys.meta_path.remove(importer)
381
382sim_objects = m5.SimObject.allClasses
383all_enums = m5.params.allEnums
384
385all_params = {}
386for name,obj in sorted(sim_objects.iteritems()):
387    for param in obj._params.local.values():
388        # load the ptype attribute now because it depends on the
389        # current version of SimObject.allClasses, but when scons
390        # actually uses the value, all versions of
391        # SimObject.allClasses will have been loaded
392        param.ptype
393
394        if not hasattr(param, 'swig_decl'):
395            continue
396        pname = param.ptype_str
397        if pname not in all_params:
398            all_params[pname] = param
399
400########################################################################
401#
402# calculate extra dependencies
403#
404module_depends = ["m5", "m5.SimObject", "m5.params"]
405depends = [ PySource.modules[dep].snode for dep in module_depends ]
406
407########################################################################
408#
409# Commands for the basic automatically generated python files
410#
411
412# Generate Python file containing a dict specifying the current
413# buildEnv flags.
414def makeDefinesPyFile(target, source, env):
415    build_env = source[0].get_contents()
416
417    code = code_formatter()
418    code("""
419import m5.internal
420import m5.util
421
422buildEnv = m5.util.SmartDict($build_env)
423
424compileDate = m5.internal.core.compileDate
425_globals = globals()
426for key,val in m5.internal.core.__dict__.iteritems():
427    if key.startswith('flag_'):
428        flag = key[5:]
429        _globals[flag] = val
430del _globals
431""")
432    code.write(target[0].abspath)
433
434defines_info = Value(build_env)
435# Generate a file with all of the compile options in it
436env.Command('python/m5/defines.py', defines_info,
437            MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
438PySource('m5', 'python/m5/defines.py')
439
440# Generate python file containing info about the M5 source code
441def makeInfoPyFile(target, source, env):
442    code = code_formatter()
443    for src in source:
444        data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
445        code('$src = ${{repr(data)}}')
446    code.write(str(target[0]))
447
448# Generate a file that wraps the basic top level files
449env.Command('python/m5/info.py',
450            [ '#/AUTHORS', '#/LICENSE', '#/README', ],
451            MakeAction(makeInfoPyFile, Transform("INFO")))
452PySource('m5', 'python/m5/info.py')
453
454########################################################################
455#
456# Create all of the SimObject param headers and enum headers
457#
458
459def createSimObjectParam(target, source, env):
460    assert len(target) == 1 and len(source) == 1
461
462    name = str(source[0].get_contents())
463    obj = sim_objects[name]
464
465    code = code_formatter()
466    obj.cxx_decl(code)
467    code.write(target[0].abspath)
468
469def createSwigParam(target, source, env):
470    assert len(target) == 1 and len(source) == 1
471
472    name = str(source[0].get_contents())
473    param = all_params[name]
474
475    code = code_formatter()
476    code('%module(package="m5.internal") $0_${name}', param.file_ext)
477    param.swig_decl(code)
478    code.write(target[0].abspath)
479
480def createEnumStrings(target, source, env):
481    assert len(target) == 1 and len(source) == 1
482
483    name = str(source[0].get_contents())
484    obj = all_enums[name]
485
486    code = code_formatter()
487    obj.cxx_def(code)
488    code.write(target[0].abspath)
489
490def createEnumParam(target, source, env):
491    assert len(target) == 1 and len(source) == 1
492
493    name = str(source[0].get_contents())
494    obj = all_enums[name]
495
496    code = code_formatter()
497    obj.cxx_decl(code)
498    code.write(target[0].abspath)
499
500def createEnumSwig(target, source, env):
501    assert len(target) == 1 and len(source) == 1
502
503    name = str(source[0].get_contents())
504    obj = all_enums[name]
505
506    code = code_formatter()
507    code('''\
508%module(package="m5.internal") enum_$name
509
510%{
511#include "enums/$name.hh"
512%}
513
514%include "enums/$name.hh"
515''')
516    code.write(target[0].abspath)
517
518# Generate all of the SimObject param struct header files
519params_hh_files = []
520for name,simobj in sorted(sim_objects.iteritems()):
521    py_source = PySource.modules[simobj.__module__]
522    extra_deps = [ py_source.tnode ]
523
524    hh_file = File('params/%s.hh' % name)
525    params_hh_files.append(hh_file)
526    env.Command(hh_file, Value(name),
527                MakeAction(createSimObjectParam, Transform("SO PARAM")))
528    env.Depends(hh_file, depends + extra_deps)
529
530# Generate any parameter header files needed
531params_i_files = []
532for name,param in all_params.iteritems():
533    i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name))
534    params_i_files.append(i_file)
535    env.Command(i_file, Value(name),
536                MakeAction(createSwigParam, Transform("SW PARAM")))
537    env.Depends(i_file, depends)
538    SwigSource('m5.internal', i_file)
539
540# Generate all enum header files
541for name,enum in sorted(all_enums.iteritems()):
542    py_source = PySource.modules[enum.__module__]
543    extra_deps = [ py_source.tnode ]
544
545    cc_file = File('enums/%s.cc' % name)
546    env.Command(cc_file, Value(name),
547                MakeAction(createEnumStrings, Transform("ENUM STR")))
548    env.Depends(cc_file, depends + extra_deps)
549    Source(cc_file)
550
551    hh_file = File('enums/%s.hh' % name)
552    env.Command(hh_file, Value(name),
553                MakeAction(createEnumParam, Transform("EN PARAM")))
554    env.Depends(hh_file, depends + extra_deps)
555
556    i_file = File('python/m5/internal/enum_%s.i' % name)
557    env.Command(i_file, Value(name),
558                MakeAction(createEnumSwig, Transform("ENUMSWIG")))
559    env.Depends(i_file, depends + extra_deps)
560    SwigSource('m5.internal', i_file)
561
562def buildParam(target, source, env):
563    name = source[0].get_contents()
564    obj = sim_objects[name]
565    class_path = obj.cxx_class.split('::')
566    classname = class_path[-1]
567    namespaces = class_path[:-1]
568    params = obj._params.local.values()
569
570    code = code_formatter()
571
572    code('%module(package="m5.internal") param_$name')
573    code()
574    code('%{')
575    code('#include "params/$obj.hh"')
576    for param in params:
577        param.cxx_predecls(code)
578    code('%}')
579    code()
580
581    for param in params:
582        param.swig_predecls(code)
583
584    code()
585    if obj._base:
586        code('%import "python/m5/internal/param_${{obj._base}}.i"')
587    code()
588    obj.swig_objdecls(code)
589    code()
590
591    code('%include "params/$obj.hh"')
592
593    code.write(target[0].abspath)
594
595for name in sim_objects.iterkeys():
596    params_file = File('python/m5/internal/param_%s.i' % name)
597    env.Command(params_file, Value(name),
598                MakeAction(buildParam, Transform("BLDPARAM")))
599    env.Depends(params_file, depends)
600    SwigSource('m5.internal', params_file)
601
602# Generate the main swig init file
603def makeEmbeddedSwigInit(target, source, env):
604    code = code_formatter()
605    module = source[0].get_contents()
606    code('''\
607#include "sim/init.hh"
608
609extern "C" {
610    void init_${module}();
611}
612
613EmbeddedSwig embed_swig_${module}(init_${module});
614''')
615    code.write(str(target[0]))
616    
617# Build all swig modules
618for swig in SwigSource.all:
619    env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
620                MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
621                '-o ${TARGETS[0]} $SOURCES', Transform("SWIG")))
622    init_file = 'python/swig/init_%s.cc' % swig.module
623    env.Command(init_file, Value(swig.module),
624                MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW")))
625    Source(init_file)
626
627#
628# Handle debug flags
629#
630def makeDebugFlagCC(target, source, env):
631    assert(len(target) == 1 and len(source) == 1)
632
633    val = eval(source[0].get_contents())
634    name, compound, desc = val
635    compound = list(sorted(compound))
636
637    code = code_formatter()
638
639    # file header
640    code('''
641/*
642 * DO NOT EDIT THIS FILE! Automatically generated
643 */
644
645#include "base/debug.hh"
646''')
647
648    for flag in compound:
649        code('#include "debug/$flag.hh"')
650    code()
651    code('namespace Debug {')
652    code()
653
654    if not compound:
655        code('SimpleFlag $name("$name", "$desc");')
656    else:
657        code('CompoundFlag $name("$name", "$desc",')
658        code.indent()
659        last = len(compound) - 1
660        for i,flag in enumerate(compound):
661            if i != last:
662                code('$flag,')
663            else:
664                code('$flag);')
665        code.dedent()
666
667    code()
668    code('} // namespace Debug')
669
670    code.write(str(target[0]))
671
672def makeDebugFlagHH(target, source, env):
673    assert(len(target) == 1 and len(source) == 1)
674
675    val = eval(source[0].get_contents())
676    name, compound, desc = val
677
678    code = code_formatter()
679
680    # file header boilerplate
681    code('''\
682/*
683 * DO NOT EDIT THIS FILE!
684 *
685 * Automatically generated by SCons
686 */
687
688#ifndef __DEBUG_${name}_HH__
689#define __DEBUG_${name}_HH__
690
691namespace Debug {
692''')
693
694    if compound:
695        code('class CompoundFlag;')
696    code('class SimpleFlag;')
697
698    if compound:
699        code('extern CompoundFlag $name;')
700        for flag in compound:
701            code('extern SimpleFlag $flag;')
702    else:
703        code('extern SimpleFlag $name;')
704
705    code('''
706}
707
708#endif // __DEBUG_${name}_HH__
709''')
710
711    code.write(str(target[0]))
712
713for name,flag in sorted(debug_flags.iteritems()):
714    n, compound, desc = flag
715    assert n == name
716
717    env.Command('debug/%s.hh' % name, Value(flag),
718                MakeAction(makeDebugFlagHH, Transform("TRACING", 0)))
719    env.Command('debug/%s.cc' % name, Value(flag),
720                MakeAction(makeDebugFlagCC, Transform("TRACING", 0)))
721    Source('debug/%s.cc' % name)
722
723# Embed python files.  All .py files that have been indicated by a
724# PySource() call in a SConscript need to be embedded into the M5
725# library.  To do that, we compile the file to byte code, marshal the
726# byte code, compress it, and then generate a c++ file that
727# inserts the result into an array.
728def embedPyFile(target, source, env):
729    def c_str(string):
730        if string is None:
731            return "0"
732        return '"%s"' % string
733
734    '''Action function to compile a .py into a code object, marshal
735    it, compress it, and stick it into an asm file so the code appears
736    as just bytes with a label in the data section'''
737
738    src = file(str(source[0]), 'r').read()
739
740    pysource = PySource.tnodes[source[0]]
741    compiled = compile(src, pysource.abspath, 'exec')
742    marshalled = marshal.dumps(compiled)
743    compressed = zlib.compress(marshalled)
744    data = compressed
745    sym = pysource.symname
746
747    code = code_formatter()
748    code('''\
749#include "sim/init.hh"
750
751namespace {
752
753const char data_${sym}[] = {
754''')
755    code.indent()
756    step = 16
757    for i in xrange(0, len(data), step):
758        x = array.array('B', data[i:i+step])
759        code(''.join('%d,' % d for d in x))
760    code.dedent()
761    
762    code('''};
763
764EmbeddedPython embedded_${sym}(
765    ${{c_str(pysource.arcname)}},
766    ${{c_str(pysource.abspath)}},
767    ${{c_str(pysource.modpath)}},
768    data_${sym},
769    ${{len(data)}},
770    ${{len(marshalled)}});
771
772} // anonymous namespace
773''')
774    code.write(str(target[0]))
775
776for source in PySource.all:
777    env.Command(source.cpp, source.tnode, 
778                MakeAction(embedPyFile, Transform("EMBED PY")))
779    Source(source.cpp)
780
781########################################################################
782#
783# Define binaries.  Each different build type (debug, opt, etc.) gets
784# a slightly different build environment.
785#
786
787# List of constructed environments to pass back to SConstruct
788envList = []
789
790date_source = Source('base/date.cc', skip_lib=True)
791
792# Function to create a new build environment as clone of current
793# environment 'env' with modified object suffix and optional stripped
794# binary.  Additional keyword arguments are appended to corresponding
795# build environment vars.
796def makeEnv(label, objsfx, strip = False, **kwargs):
797    # SCons doesn't know to append a library suffix when there is a '.' in the
798    # name.  Use '_' instead.
799    libname = 'm5_' + label
800    exename = 'm5.' + label
801
802    new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
803    new_env.Label = label
804    new_env.Append(**kwargs)
805
806    swig_env = new_env.Clone()
807    swig_env.Append(CCFLAGS='-Werror')
808    if env['GCC']:
809        swig_env.Append(CCFLAGS='-Wno-uninitialized')
810        swig_env.Append(CCFLAGS='-Wno-sign-compare')
811        swig_env.Append(CCFLAGS='-Wno-parentheses')
812
813    werror_env = new_env.Clone()
814    werror_env.Append(CCFLAGS='-Werror')
815
816    def make_obj(source, static, extra_deps = None):
817        '''This function adds the specified source to the correct
818        build environment, and returns the corresponding SCons Object
819        nodes'''
820
821        if source.swig:
822            env = swig_env
823        elif source.Werror:
824            env = werror_env
825        else:
826            env = new_env
827
828        if static:
829            obj = env.StaticObject(source.tnode)
830        else:
831            obj = env.SharedObject(source.tnode)
832
833        if extra_deps:
834            env.Depends(obj, extra_deps)
835
836        return obj
837
838    static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)]
839    shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)]
840
841    static_date = make_obj(date_source, static=True, extra_deps=static_objs)
842    static_objs.append(static_date)
843    
844    shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
845    shared_objs.append(shared_date)
846
847    # First make a library of everything but main() so other programs can
848    # link against m5.
849    static_lib = new_env.StaticLibrary(libname, static_objs)
850    shared_lib = new_env.SharedLibrary(libname, shared_objs)
851
852    for target, sources in unit_tests:
853        objs = [ make_obj(s, static=True) for s in sources ]
854        new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs)
855
856    # Now link a stub with main() and the static library.
857    bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ]
858    progname = exename
859    if strip:
860        progname += '.unstripped'
861
862    targets = new_env.Program(progname, bin_objs + static_objs)
863
864    if strip:
865        if sys.platform == 'sunos5':
866            cmd = 'cp $SOURCE $TARGET; strip $TARGET'
867        else:
868            cmd = 'strip $SOURCE -o $TARGET'
869        targets = new_env.Command(exename, progname,
870                    MakeAction(cmd, Transform("STRIP")))
871            
872    new_env.M5Binary = targets[0]
873    envList.append(new_env)
874
875# Debug binary
876ccflags = {}
877if env['GCC']:
878    if sys.platform == 'sunos5':
879        ccflags['debug'] = '-gstabs+'
880    else:
881        ccflags['debug'] = '-ggdb3'
882    ccflags['opt'] = '-g -O3'
883    ccflags['fast'] = '-O3'
884    ccflags['prof'] = '-O3 -g -pg'
885elif env['SUNCC']:
886    ccflags['debug'] = '-g0'
887    ccflags['opt'] = '-g -O'
888    ccflags['fast'] = '-fast'
889    ccflags['prof'] = '-fast -g -pg'
890elif env['ICC']:
891    ccflags['debug'] = '-g -O0'
892    ccflags['opt'] = '-g -O'
893    ccflags['fast'] = '-fast'
894    ccflags['prof'] = '-fast -g -pg'
895else:
896    print 'Unknown compiler, please fix compiler options'
897    Exit(1)
898
899makeEnv('debug', '.do',
900        CCFLAGS = Split(ccflags['debug']),
901        CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
902
903# Optimized binary
904makeEnv('opt', '.o',
905        CCFLAGS = Split(ccflags['opt']),
906        CPPDEFINES = ['TRACING_ON=1'])
907
908# "Fast" binary
909makeEnv('fast', '.fo', strip = True,
910        CCFLAGS = Split(ccflags['fast']),
911        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
912
913# Profiled binary
914makeEnv('prof', '.po',
915        CCFLAGS = Split(ccflags['prof']),
916        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
917        LINKFLAGS = '-pg')
918
919Return('envList')
920