SConscript revision 5456
19983Sstever@gmail.com# -*- mode:python -*-
29983Sstever@gmail.com
39983Sstever@gmail.com# Copyright (c) 2004-2005 The Regents of The University of Michigan
49983Sstever@gmail.com# All rights reserved.
59983Sstever@gmail.com#
69983Sstever@gmail.com# Redistribution and use in source and binary forms, with or without
79983Sstever@gmail.com# modification, are permitted provided that the following conditions are
89983Sstever@gmail.com# met: redistributions of source code must retain the above copyright
99983Sstever@gmail.com# notice, this list of conditions and the following disclaimer;
109983Sstever@gmail.com# redistributions in binary form must reproduce the above copyright
119983Sstever@gmail.com# notice, this list of conditions and the following disclaimer in the
129983Sstever@gmail.com# documentation and/or other materials provided with the distribution;
139983Sstever@gmail.com# neither the name of the copyright holders nor the names of its
149983Sstever@gmail.com# contributors may be used to endorse or promote products derived from
159983Sstever@gmail.com# this software without specific prior written permission.
169983Sstever@gmail.com#
179983Sstever@gmail.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
189983Sstever@gmail.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
199983Sstever@gmail.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
209983Sstever@gmail.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
219983Sstever@gmail.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
229983Sstever@gmail.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
239983Sstever@gmail.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
249983Sstever@gmail.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
259983Sstever@gmail.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
269983Sstever@gmail.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
279983Sstever@gmail.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289983Sstever@gmail.com#
299983Sstever@gmail.com# Authors: Nathan Binkert
309983Sstever@gmail.com
319983Sstever@gmail.comimport imp
329983Sstever@gmail.comimport os
339983Sstever@gmail.comimport sys
349983Sstever@gmail.com
359983Sstever@gmail.comfrom os.path import basename, exists, isdir, isfile, join as joinpath
369983Sstever@gmail.com
379983Sstever@gmail.comimport SCons
389983Sstever@gmail.com
399983Sstever@gmail.com# This file defines how to build a particular configuration of M5
409983Sstever@gmail.com# based on variable settings in the 'env' build environment.
419983Sstever@gmail.com
429983Sstever@gmail.comImport('*')
439983Sstever@gmail.com
449983Sstever@gmail.com# Children need to see the environment
459983Sstever@gmail.comExport('env')
469983Sstever@gmail.com
479983Sstever@gmail.comdef sort_list(_list):
489983Sstever@gmail.com    """return a sorted copy of '_list'"""
499983Sstever@gmail.com    if isinstance(_list, list):
509983Sstever@gmail.com        _list = _list[:]
519983Sstever@gmail.com    else:
529983Sstever@gmail.com        _list = list(_list)
539983Sstever@gmail.com    _list.sort()
549983Sstever@gmail.com    return _list
559983Sstever@gmail.com
569983Sstever@gmail.comclass PySourceFile(object):
579983Sstever@gmail.com    def __init__(self, package, source):
589983Sstever@gmail.com        filename = str(source)
599983Sstever@gmail.com        pyname = basename(filename)
609983Sstever@gmail.com        assert pyname.endswith('.py')
619983Sstever@gmail.com        name = pyname[:-3]
629983Sstever@gmail.com        path = package.split('.')
639983Sstever@gmail.com        modpath = path
649983Sstever@gmail.com        if name != '__init__':
659983Sstever@gmail.com            modpath += [name]
669983Sstever@gmail.com        modpath = '.'.join(modpath)
679983Sstever@gmail.com
689983Sstever@gmail.com        arcpath = package.split('.') + [ pyname + 'c' ]
699983Sstever@gmail.com        arcname = joinpath(*arcpath)
709983Sstever@gmail.com
719983Sstever@gmail.com        self.source = source
729983Sstever@gmail.com        self.pyname = pyname
739983Sstever@gmail.com        self.srcpath = source.srcnode().abspath
749983Sstever@gmail.com        self.package = package
759983Sstever@gmail.com        self.modpath = modpath
769983Sstever@gmail.com        self.arcname = arcname
779983Sstever@gmail.com        self.filename = filename
789983Sstever@gmail.com        self.compiled = File(filename + 'c')
799983Sstever@gmail.com
809983Sstever@gmail.com########################################################################
819983Sstever@gmail.com# Code for adding source files of various types
829983Sstever@gmail.com#
839983Sstever@gmail.comcc_sources = []
849983Sstever@gmail.comdef Source(source):
859983Sstever@gmail.com    '''Add a C/C++ source file to the build'''
869983Sstever@gmail.com    if not isinstance(source, SCons.Node.FS.File):
879983Sstever@gmail.com        source = File(source)
889983Sstever@gmail.com
899983Sstever@gmail.com    cc_sources.append(source)
909983Sstever@gmail.com
919983Sstever@gmail.compy_sources = []
929983Sstever@gmail.comdef PySource(package, source):
939983Sstever@gmail.com    '''Add a python source file to the named package'''
9410153Sandreas@sandberg.pp.se    if not isinstance(source, SCons.Node.FS.File):
9510153Sandreas@sandberg.pp.se        source = File(source)
9610153Sandreas@sandberg.pp.se
9710153Sandreas@sandberg.pp.se    source = PySourceFile(package, source)
9810153Sandreas@sandberg.pp.se    py_sources.append(source)
9910153Sandreas@sandberg.pp.se
10010153Sandreas@sandberg.pp.sesim_objects_fixed = False
10110153Sandreas@sandberg.pp.sesim_object_modfiles = set()
10210153Sandreas@sandberg.pp.sedef SimObject(source):
10310361SAndreas.Sandberg@ARM.com    '''Add a SimObject python file as a python source object and add
1049983Sstever@gmail.com    it to a list of sim object modules'''
1059983Sstever@gmail.com
1069983Sstever@gmail.com    if sim_objects_fixed:
1079983Sstever@gmail.com        raise AttributeError, "Too late to call SimObject now."
1089983Sstever@gmail.com
1099983Sstever@gmail.com    if not isinstance(source, SCons.Node.FS.File):
1109983Sstever@gmail.com        source = File(source)
1119983Sstever@gmail.com
11210361SAndreas.Sandberg@ARM.com    PySource('m5.objects', source)
1139983Sstever@gmail.com    modfile = basename(str(source))
1149983Sstever@gmail.com    assert modfile.endswith('.py')
1159983Sstever@gmail.com    modname = modfile[:-3]
1169983Sstever@gmail.com    sim_object_modfiles.add(modname)
1179983Sstever@gmail.com
1189983Sstever@gmail.comswig_sources = []
1199983Sstever@gmail.comdef SwigSource(package, source):
1209983Sstever@gmail.com    '''Add a swig file to build'''
1219983Sstever@gmail.com    if not isinstance(source, SCons.Node.FS.File):
1229983Sstever@gmail.com        source = File(source)
1239983Sstever@gmail.com    val = source,package
1249983Sstever@gmail.com    swig_sources.append(val)
1259983Sstever@gmail.com
1269983Sstever@gmail.com# Children should have access
1279983Sstever@gmail.comExport('Source')
1289983Sstever@gmail.comExport('PySource')
1299983Sstever@gmail.comExport('SimObject')
1309983Sstever@gmail.comExport('SwigSource')
1319983Sstever@gmail.com
1329983Sstever@gmail.com########################################################################
1339983Sstever@gmail.com#
1349983Sstever@gmail.com# Trace Flags
1359983Sstever@gmail.com#
1369983Sstever@gmail.comall_flags = {}
1379983Sstever@gmail.comtrace_flags = []
1389983Sstever@gmail.comdef TraceFlag(name, desc=''):
1399983Sstever@gmail.com    if name in all_flags:
1409983Sstever@gmail.com        raise AttributeError, "Flag %s already specified" % name
1419983Sstever@gmail.com    flag = (name, (), desc)
1429983Sstever@gmail.com    trace_flags.append(flag)
1439983Sstever@gmail.com    all_flags[name] = ()
1449983Sstever@gmail.com
1459983Sstever@gmail.comdef CompoundFlag(name, flags, desc=''):
1469983Sstever@gmail.com    if name in all_flags:
1479983Sstever@gmail.com        raise AttributeError, "Flag %s already specified" % name
1489983Sstever@gmail.com
1499983Sstever@gmail.com    compound = tuple(flags)
1509983Sstever@gmail.com    for flag in compound:
1519983Sstever@gmail.com        if flag not in all_flags:
1529983Sstever@gmail.com            raise AttributeError, "Trace flag %s not found" % flag
1539983Sstever@gmail.com        if all_flags[flag]:
1549983Sstever@gmail.com            raise AttributeError, \
1559983Sstever@gmail.com                "Compound flag can't point to another compound flag"
1569983Sstever@gmail.com
1579983Sstever@gmail.com    flag = (name, compound, desc)
1589983Sstever@gmail.com    trace_flags.append(flag)
1599983Sstever@gmail.com    all_flags[name] = compound
1609983Sstever@gmail.com
1619983Sstever@gmail.comExport('TraceFlag')
1629983Sstever@gmail.comExport('CompoundFlag')
1639983Sstever@gmail.com
1649983Sstever@gmail.com########################################################################
1659983Sstever@gmail.com#
1669983Sstever@gmail.com# Set some compiler variables
1679983Sstever@gmail.com#
1689983Sstever@gmail.com
1699983Sstever@gmail.com# Include file paths are rooted in this directory.  SCons will
1709983Sstever@gmail.com# automatically expand '.' to refer to both the source directory and
1719983Sstever@gmail.com# the corresponding build directory to pick up generated include
1729983Sstever@gmail.com# files.
1739983Sstever@gmail.comenv.Append(CPPPATH=Dir('.'))
1749983Sstever@gmail.com
1759983Sstever@gmail.com# Add a flag defining what THE_ISA should be for all compilation
1769983Sstever@gmail.comenv.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
1779983Sstever@gmail.com
1789983Sstever@gmail.com########################################################################
1799983Sstever@gmail.com#
1809983Sstever@gmail.com# Walk the tree and execute all SConscripts in subdirectories
1819983Sstever@gmail.com#
1829983Sstever@gmail.com
1839983Sstever@gmail.comfor base_dir in base_dir_list:
1849983Sstever@gmail.com    here = Dir('.').srcnode().abspath
1859983Sstever@gmail.com    for root, dirs, files in os.walk(base_dir, topdown=True):
1869983Sstever@gmail.com        if root == here:
1879983Sstever@gmail.com            # we don't want to recurse back into this SConscript
1889983Sstever@gmail.com            continue
1899983Sstever@gmail.com
1909983Sstever@gmail.com        if 'SConscript' in files:
1919983Sstever@gmail.com            build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
1929983Sstever@gmail.com            SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
1939983Sstever@gmail.com
1949983Sstever@gmail.comfor opt in env.ExportOptions:
1959983Sstever@gmail.com    env.ConfigFile(opt)
1969983Sstever@gmail.com
1979983Sstever@gmail.com########################################################################
1989983Sstever@gmail.com#
1999983Sstever@gmail.com# Prevent any SimObjects from being added after this point, they
2009983Sstever@gmail.com# should all have been added in the SConscripts above
2019983Sstever@gmail.com#
2029983Sstever@gmail.comsim_objects_fixed = True
2039983Sstever@gmail.com
2049983Sstever@gmail.com########################################################################
2059983Sstever@gmail.com#
2069983Sstever@gmail.com# Manually turn python/generate.py into a python module and import it
2079983Sstever@gmail.com#
2089983Sstever@gmail.comgenerate_file = File('python/generate.py')
2099983Sstever@gmail.comgenerate_module = imp.new_module('generate')
2109983Sstever@gmail.comsys.modules['generate'] = generate_module
2119983Sstever@gmail.comexec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__
2129983Sstever@gmail.com
2139983Sstever@gmail.com########################################################################
2149983Sstever@gmail.com#
2159983Sstever@gmail.com# build a generate
2169983Sstever@gmail.com#
2179983Sstever@gmail.comfrom generate import Generate
2189983Sstever@gmail.comoptionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
2199983Sstever@gmail.comgenerate = Generate(py_sources, sim_object_modfiles, optionDict)
2209983Sstever@gmail.comm5 = generate.m5
2219983Sstever@gmail.com
22211290Sgabor.dozsa@arm.com########################################################################
2239983Sstever@gmail.com#
2249983Sstever@gmail.com# calculate extra dependencies
2259983Sstever@gmail.com#
2269983Sstever@gmail.commodule_depends = ["m5", "m5.SimObject", "m5.params"]
2279983Sstever@gmail.commodule_depends = [ File(generate.py_modules[dep]) for dep in module_depends ]
2289983Sstever@gmail.comfile_depends = [ generate_file ]
2299983Sstever@gmail.comdepends = module_depends + file_depends
2309983Sstever@gmail.com
2319983Sstever@gmail.com########################################################################
2329983Sstever@gmail.com#
2339983Sstever@gmail.com# Commands for the basic automatically generated python files
2349983Sstever@gmail.com#
2359983Sstever@gmail.com
2369983Sstever@gmail.com# Generate a file with all of the compile options in it
2379983Sstever@gmail.comenv.Command('python/m5/defines.py', Value(optionDict),
2389983Sstever@gmail.com            generate.makeDefinesPyFile)
2399983Sstever@gmail.comPySource('m5', 'python/m5/defines.py')
240
241# Generate a file that wraps the basic top level files
242env.Command('python/m5/info.py',
243            [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
244            generate.makeInfoPyFile)
245PySource('m5', 'python/m5/info.py')
246
247# Generate an __init__.py file for the objects package
248env.Command('python/m5/objects/__init__.py',
249            [ Value(o) for o in sort_list(sim_object_modfiles) ],
250            generate.makeObjectsInitFile)
251PySource('m5.objects', 'python/m5/objects/__init__.py')
252
253########################################################################
254#
255# Create all of the SimObject param headers and enum headers
256#
257
258# Generate all of the SimObject param struct header files
259params_hh_files = []
260for name,simobj in generate.sim_objects.iteritems():
261    extra_deps = [ File(generate.py_modules[simobj.__module__]) ]
262
263    hh_file = File('params/%s.hh' % name)
264    params_hh_files.append(hh_file)
265    env.Command(hh_file, Value(name), generate.createSimObjectParam)
266    env.Depends(hh_file, depends + extra_deps)
267
268# Generate any parameter header files needed
269for name,param in generate.params.iteritems():
270    if isinstance(param, m5.params.VectorParamDesc):
271        ext = 'vptype'
272    else:
273        ext = 'ptype'
274
275    i_file = File('params/%s_%s.i' % (name, ext))
276    env.Command(i_file, Value(name), generate.createSwigParam)
277    env.Depends(i_file, depends)
278
279# Generate all enum header files
280for name,enum in generate.enums.iteritems():
281    extra_deps = [ File(generate.py_modules[enum.__module__]) ]
282
283    cc_file = File('enums/%s.cc' % name)
284    env.Command(cc_file, Value(name), generate.createEnumStrings)
285    env.Depends(cc_file, depends + extra_deps)
286    Source(cc_file)
287
288    hh_file = File('enums/%s.hh' % name)
289    env.Command(hh_file, Value(name), generate.createEnumParam)
290    env.Depends(hh_file, depends + extra_deps)
291
292# Build the big monolithic swigged params module (wraps all SimObject
293# param structs and enum structs)
294params_file = File('params/params.i')
295names = sort_list(generate.sim_objects.keys())
296env.Command(params_file, [ Value(v) for v in names ],
297            generate.buildParams)
298env.Depends(params_file, params_hh_files + depends)
299SwigSource('m5.objects', params_file)
300
301# Build all swig modules
302swig_modules = []
303for source,package in swig_sources:
304    filename = str(source)
305    assert filename.endswith('.i')
306
307    base = '.'.join(filename.split('.')[:-1])
308    module = basename(base)
309    cc_file = base + '_wrap.cc'
310    py_file = base + '.py'
311
312    env.Command([cc_file, py_file], source,
313                '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
314                '-o ${TARGETS[0]} $SOURCES')
315    env.Depends(py_file, source)
316    env.Depends(cc_file, source)
317
318    swig_modules.append(Value(module))
319    Source(cc_file)
320    PySource(package, py_file)
321
322# Generate the main swig init file
323env.Command('swig/init.cc', swig_modules, generate.makeSwigInit)
324Source('swig/init.cc')
325
326# Generate traceflags.py
327flags = [ Value(f) for f in trace_flags ]
328env.Command('base/traceflags.py', flags, generate.traceFlagsPy)
329PySource('m5', 'base/traceflags.py')
330
331env.Command('base/traceflags.hh', flags, generate.traceFlagsHH)
332env.Command('base/traceflags.cc', flags, generate.traceFlagsCC)
333Source('base/traceflags.cc')
334
335# Generate program_info.cc
336env.Command('base/program_info.cc',
337            Value(str(SCons.Node.FS.default_fs.SConstruct_dir)), generate.programInfo)
338
339# Build the zip file
340py_compiled = []
341py_zip_depends = []
342for source in py_sources:
343    env.Command(source.compiled, source.source, generate.compilePyFile)
344    py_compiled.append(source.compiled)
345
346    # make the zipfile depend on the archive name so that the archive
347    # is rebuilt if the name changes
348    py_zip_depends.append(Value(source.arcname))
349
350# Add the zip file target to the environment.
351m5zip = File('m5py.zip')
352env.Command(m5zip, py_compiled, generate.buildPyZip)
353env.Depends(m5zip, py_zip_depends)
354
355########################################################################
356#
357# Define binaries.  Each different build type (debug, opt, etc.) gets
358# a slightly different build environment.
359#
360
361# List of constructed environments to pass back to SConstruct
362envList = []
363
364# This function adds the specified sources to the given build
365# environment, and returns a list of all the corresponding SCons
366# Object nodes (including an extra one for date.cc).  We explicitly
367# add the Object nodes so we can set up special dependencies for
368# date.cc.
369def make_objs(sources, env):
370    objs = [env.Object(s) for s in sources]
371  
372    # make date.cc depend on all other objects so it always gets
373    # recompiled whenever anything else does
374    date_obj = env.Object('base/date.cc')
375
376    # Make the generation of program_info.cc dependend on all 
377    # the other cc files and the compiling of program_info.cc 
378    # dependent on all the objects but program_info.o 
379    pinfo_obj = env.Object('base/program_info.cc')
380    env.Depends('base/program_info.cc', sources)
381    env.Depends(date_obj, objs)
382    env.Depends(pinfo_obj, objs)
383    objs.extend([date_obj,pinfo_obj])
384    return objs
385
386# Function to create a new build environment as clone of current
387# environment 'env' with modified object suffix and optional stripped
388# binary.  Additional keyword arguments are appended to corresponding
389# build environment vars.
390def makeEnv(label, objsfx, strip = False, **kwargs):
391    newEnv = env.Copy(OBJSUFFIX=objsfx)
392    newEnv.Label = label
393    newEnv.Append(**kwargs)
394    exe = 'm5.' + label  # final executable
395    bin = exe + '.bin'   # executable w/o appended Python zip archive
396    newEnv.Program(bin, make_objs(cc_sources, newEnv))
397    if strip:
398        stripped_bin = bin + '.stripped'
399        if sys.platform == 'sunos5':
400            cmd = 'cp $SOURCE $TARGET; strip $TARGET'
401        else:
402            cmd = 'strip $SOURCE -o $TARGET'
403        newEnv.Command(stripped_bin, bin, cmd)
404        bin = stripped_bin
405    targets = newEnv.Concat(exe, [bin, 'm5py.zip'])
406    newEnv.M5Binary = targets[0]
407    envList.append(newEnv)
408
409# Debug binary
410ccflags = {}
411if env['GCC']:
412    if sys.platform == 'sunos5':
413        ccflags['debug'] = '-gstabs+'
414    else:
415        ccflags['debug'] = '-ggdb3'
416    ccflags['opt'] = '-g -O3'
417    ccflags['fast'] = '-O3'
418    ccflags['prof'] = '-O3 -g -pg'
419elif env['SUNCC']:
420    ccflags['debug'] = '-g0'
421    ccflags['opt'] = '-g -O'
422    ccflags['fast'] = '-fast'
423    ccflags['prof'] = '-fast -g -pg'
424elif env['ICC']:
425    ccflags['debug'] = '-g -O0'
426    ccflags['opt'] = '-g -O'
427    ccflags['fast'] = '-fast'
428    ccflags['prof'] = '-fast -g -pg'
429else:
430    print 'Unknown compiler, please fix compiler options'
431    Exit(1)
432
433makeEnv('debug', '.do',
434        CCFLAGS = Split(ccflags['debug']),
435        CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
436
437# Optimized binary
438makeEnv('opt', '.o',
439        CCFLAGS = Split(ccflags['opt']),
440        CPPDEFINES = ['TRACING_ON=1'])
441
442# "Fast" binary
443makeEnv('fast', '.fo', strip = True,
444        CCFLAGS = Split(ccflags['fast']),
445        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
446
447# Profiled binary
448makeEnv('prof', '.po',
449        CCFLAGS = Split(ccflags['prof']),
450        CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
451        LINKFLAGS = '-pg')
452
453Return('envList')
454