SConscript revision 8942
19264Sdjordje.kovacevic@arm.com# -*- mode:python -*- 29264Sdjordje.kovacevic@arm.com 39264Sdjordje.kovacevic@arm.com# Copyright (c) 2004-2005 The Regents of The University of Michigan 49264Sdjordje.kovacevic@arm.com# All rights reserved. 59264Sdjordje.kovacevic@arm.com# 69264Sdjordje.kovacevic@arm.com# Redistribution and use in source and binary forms, with or without 79264Sdjordje.kovacevic@arm.com# modification, are permitted provided that the following conditions are 89264Sdjordje.kovacevic@arm.com# met: redistributions of source code must retain the above copyright 99264Sdjordje.kovacevic@arm.com# notice, this list of conditions and the following disclaimer; 109264Sdjordje.kovacevic@arm.com# redistributions in binary form must reproduce the above copyright 119264Sdjordje.kovacevic@arm.com# notice, this list of conditions and the following disclaimer in the 129264Sdjordje.kovacevic@arm.com# documentation and/or other materials provided with the distribution; 139264Sdjordje.kovacevic@arm.com# neither the name of the copyright holders nor the names of its 149264Sdjordje.kovacevic@arm.com# contributors may be used to endorse or promote products derived from 159264Sdjordje.kovacevic@arm.com# this software without specific prior written permission. 169264Sdjordje.kovacevic@arm.com# 179264Sdjordje.kovacevic@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 189264Sdjordje.kovacevic@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 199264Sdjordje.kovacevic@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 209264Sdjordje.kovacevic@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 219264Sdjordje.kovacevic@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 229264Sdjordje.kovacevic@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 239264Sdjordje.kovacevic@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 249264Sdjordje.kovacevic@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 259264Sdjordje.kovacevic@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 269264Sdjordje.kovacevic@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 279264Sdjordje.kovacevic@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 289264Sdjordje.kovacevic@arm.com# 299264Sdjordje.kovacevic@arm.com# Authors: Nathan Binkert 309264Sdjordje.kovacevic@arm.com 319264Sdjordje.kovacevic@arm.comimport array 329264Sdjordje.kovacevic@arm.comimport bisect 339264Sdjordje.kovacevic@arm.comimport imp 349264Sdjordje.kovacevic@arm.comimport marshal 359264Sdjordje.kovacevic@arm.comimport os 369264Sdjordje.kovacevic@arm.comimport re 379264Sdjordje.kovacevic@arm.comimport sys 389264Sdjordje.kovacevic@arm.comimport zlib 399264Sdjordje.kovacevic@arm.com 409264Sdjordje.kovacevic@arm.comfrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath 419264Sdjordje.kovacevic@arm.com 429264Sdjordje.kovacevic@arm.comimport SCons 439264Sdjordje.kovacevic@arm.com 449264Sdjordje.kovacevic@arm.com# This file defines how to build a particular configuration of gem5 459264Sdjordje.kovacevic@arm.com# based on variable settings in the 'env' build environment. 469264Sdjordje.kovacevic@arm.com 479264Sdjordje.kovacevic@arm.comImport('*') 489264Sdjordje.kovacevic@arm.com 499264Sdjordje.kovacevic@arm.com# Children need to see the environment 509264Sdjordje.kovacevic@arm.comExport('env') 519264Sdjordje.kovacevic@arm.com 529264Sdjordje.kovacevic@arm.combuild_env = [(opt, env[opt]) for opt in export_vars] 539264Sdjordje.kovacevic@arm.com 5413892Sgabeblack@google.comfrom m5.util import code_formatter, compareVersions 559264Sdjordje.kovacevic@arm.com 569264Sdjordje.kovacevic@arm.com######################################################################## 579264Sdjordje.kovacevic@arm.com# Code for adding source files of various types 5813892Sgabeblack@google.com# 599264Sdjordje.kovacevic@arm.com# When specifying a source file of some type, a set of guards can be 6013892Sgabeblack@google.com# specified for that file. When get() is used to find the files, if 619264Sdjordje.kovacevic@arm.com# get specifies a set of filters, only files that match those filters 629264Sdjordje.kovacevic@arm.com# will be accepted (unspecified filters on files are assumed to be 639264Sdjordje.kovacevic@arm.com# false). Current filters are: 649264Sdjordje.kovacevic@arm.com# main -- specifies the gem5 main() function 659264Sdjordje.kovacevic@arm.com# skip_lib -- do not put this file into the gem5 library 669264Sdjordje.kovacevic@arm.com# <unittest> -- unit tests use filters based on the unit test name 679264Sdjordje.kovacevic@arm.com# 689264Sdjordje.kovacevic@arm.com# A parent can now be specified for a source file and default filter 699264Sdjordje.kovacevic@arm.com# values will be retrieved recursively from parents (children override 709264Sdjordje.kovacevic@arm.com# parents). 719264Sdjordje.kovacevic@arm.com# 729264Sdjordje.kovacevic@arm.comclass SourceMeta(type): 739264Sdjordje.kovacevic@arm.com '''Meta class for source files that keeps track of all files of a 749264Sdjordje.kovacevic@arm.com particular type and has a get function for finding all functions 759264Sdjordje.kovacevic@arm.com of a certain type that match a set of guards''' 769264Sdjordje.kovacevic@arm.com def __init__(cls, name, bases, dict): 779264Sdjordje.kovacevic@arm.com super(SourceMeta, cls).__init__(name, bases, dict) 789264Sdjordje.kovacevic@arm.com cls.all = [] 799264Sdjordje.kovacevic@arm.com 8013892Sgabeblack@google.com def get(cls, **guards): 819264Sdjordje.kovacevic@arm.com '''Find all files that match the specified guards. If a source 829264Sdjordje.kovacevic@arm.com file does not specify a flag, the default is False''' 839264Sdjordje.kovacevic@arm.com for src in cls.all: 849264Sdjordje.kovacevic@arm.com for flag,value in guards.iteritems(): 859264Sdjordje.kovacevic@arm.com # if the flag is found and has a different value, skip 869264Sdjordje.kovacevic@arm.com # this file 879264Sdjordje.kovacevic@arm.com if src.all_guards.get(flag, False) != value: 889264Sdjordje.kovacevic@arm.com break 899264Sdjordje.kovacevic@arm.com else: 909264Sdjordje.kovacevic@arm.com yield src 919264Sdjordje.kovacevic@arm.com 9213892Sgabeblack@google.comclass SourceFile(object): 939264Sdjordje.kovacevic@arm.com '''Base object that encapsulates the notion of a source file. 949264Sdjordje.kovacevic@arm.com This includes, the source node, target node, various manipulations 959264Sdjordje.kovacevic@arm.com of those. A source file also specifies a set of guards which 969264Sdjordje.kovacevic@arm.com describing which builds the source file applies to. A parent can 979264Sdjordje.kovacevic@arm.com also be specified to get default guards from''' 989264Sdjordje.kovacevic@arm.com __metaclass__ = SourceMeta 999264Sdjordje.kovacevic@arm.com def __init__(self, source, parent=None, **guards): 1009264Sdjordje.kovacevic@arm.com self.guards = guards 1019264Sdjordje.kovacevic@arm.com self.parent = parent 1029264Sdjordje.kovacevic@arm.com 1039264Sdjordje.kovacevic@arm.com tnode = source 1049264Sdjordje.kovacevic@arm.com if not isinstance(source, SCons.Node.FS.File): 1059264Sdjordje.kovacevic@arm.com tnode = File(source) 1069264Sdjordje.kovacevic@arm.com 1079264Sdjordje.kovacevic@arm.com self.tnode = tnode 1089264Sdjordje.kovacevic@arm.com self.snode = tnode.srcnode() 1099264Sdjordje.kovacevic@arm.com 1109264Sdjordje.kovacevic@arm.com for base in type(self).__mro__: 1119264Sdjordje.kovacevic@arm.com if issubclass(base, SourceFile): 1129264Sdjordje.kovacevic@arm.com base.all.append(self) 1139264Sdjordje.kovacevic@arm.com 1149264Sdjordje.kovacevic@arm.com @property 1159264Sdjordje.kovacevic@arm.com def filename(self): 1169264Sdjordje.kovacevic@arm.com return str(self.tnode) 1179264Sdjordje.kovacevic@arm.com 1189264Sdjordje.kovacevic@arm.com @property 1199264Sdjordje.kovacevic@arm.com def dirname(self): 1209264Sdjordje.kovacevic@arm.com return dirname(self.filename) 1219264Sdjordje.kovacevic@arm.com 1229264Sdjordje.kovacevic@arm.com @property 1239264Sdjordje.kovacevic@arm.com def basename(self): 1249264Sdjordje.kovacevic@arm.com return basename(self.filename) 1259264Sdjordje.kovacevic@arm.com 1269264Sdjordje.kovacevic@arm.com @property 1279264Sdjordje.kovacevic@arm.com def extname(self): 1289264Sdjordje.kovacevic@arm.com index = self.basename.rfind('.') 1299264Sdjordje.kovacevic@arm.com if index <= 0: 1309264Sdjordje.kovacevic@arm.com # dot files aren't extensions 1319264Sdjordje.kovacevic@arm.com return self.basename, None 1329264Sdjordje.kovacevic@arm.com 1339264Sdjordje.kovacevic@arm.com return self.basename[:index], self.basename[index+1:] 1349264Sdjordje.kovacevic@arm.com 1359264Sdjordje.kovacevic@arm.com @property 1369264Sdjordje.kovacevic@arm.com def all_guards(self): 1379264Sdjordje.kovacevic@arm.com '''find all guards for this object getting default values 1389264Sdjordje.kovacevic@arm.com recursively from its parents''' 1399264Sdjordje.kovacevic@arm.com guards = {} 1409264Sdjordje.kovacevic@arm.com if self.parent: 1419264Sdjordje.kovacevic@arm.com guards.update(self.parent.guards) 1429264Sdjordje.kovacevic@arm.com guards.update(self.guards) 1439264Sdjordje.kovacevic@arm.com return guards 1449264Sdjordje.kovacevic@arm.com 1459264Sdjordje.kovacevic@arm.com def __lt__(self, other): return self.filename < other.filename 1469264Sdjordje.kovacevic@arm.com def __le__(self, other): return self.filename <= other.filename 1479264Sdjordje.kovacevic@arm.com def __gt__(self, other): return self.filename > other.filename 1489264Sdjordje.kovacevic@arm.com def __ge__(self, other): return self.filename >= other.filename 1499264Sdjordje.kovacevic@arm.com def __eq__(self, other): return self.filename == other.filename 1509264Sdjordje.kovacevic@arm.com def __ne__(self, other): return self.filename != other.filename 1519264Sdjordje.kovacevic@arm.com 1529264Sdjordje.kovacevic@arm.comclass Source(SourceFile): 1539264Sdjordje.kovacevic@arm.com '''Add a c/c++ source file to the build''' 1549264Sdjordje.kovacevic@arm.com def __init__(self, source, swig = False, **guards): 1559264Sdjordje.kovacevic@arm.com '''specify the source file, and any guards''' 1569264Sdjordje.kovacevic@arm.com super(Source, self).__init__(source, **guards) 1579264Sdjordje.kovacevic@arm.com 1589264Sdjordje.kovacevic@arm.com self.swig = swig 1599264Sdjordje.kovacevic@arm.com 1609264Sdjordje.kovacevic@arm.comclass PySource(SourceFile): 1619264Sdjordje.kovacevic@arm.com '''Add a python source file to the named package''' 1629264Sdjordje.kovacevic@arm.com invalid_sym_char = re.compile('[^A-z0-9_]') 1639264Sdjordje.kovacevic@arm.com modules = {} 1649264Sdjordje.kovacevic@arm.com tnodes = {} 1659264Sdjordje.kovacevic@arm.com symnames = {} 1669264Sdjordje.kovacevic@arm.com 1679264Sdjordje.kovacevic@arm.com def __init__(self, package, source, **guards): 1689264Sdjordje.kovacevic@arm.com '''specify the python package, the source file, and any guards''' 1699264Sdjordje.kovacevic@arm.com super(PySource, self).__init__(source, **guards) 1709264Sdjordje.kovacevic@arm.com 1719264Sdjordje.kovacevic@arm.com modname,ext = self.extname 1729264Sdjordje.kovacevic@arm.com assert ext == 'py' 1739264Sdjordje.kovacevic@arm.com 1749264Sdjordje.kovacevic@arm.com if package: 1759264Sdjordje.kovacevic@arm.com path = package.split('.') 1769264Sdjordje.kovacevic@arm.com else: 1779264Sdjordje.kovacevic@arm.com path = [] 1789264Sdjordje.kovacevic@arm.com 1799264Sdjordje.kovacevic@arm.com modpath = path[:] 1809264Sdjordje.kovacevic@arm.com if modname != '__init__': 1819264Sdjordje.kovacevic@arm.com modpath += [ modname ] 1829264Sdjordje.kovacevic@arm.com modpath = '.'.join(modpath) 1839264Sdjordje.kovacevic@arm.com 1849264Sdjordje.kovacevic@arm.com arcpath = path + [ self.basename ] 1859264Sdjordje.kovacevic@arm.com abspath = self.snode.abspath 1869264Sdjordje.kovacevic@arm.com if not exists(abspath): 1879264Sdjordje.kovacevic@arm.com abspath = self.tnode.abspath 1889264Sdjordje.kovacevic@arm.com 1899264Sdjordje.kovacevic@arm.com self.package = package 1909264Sdjordje.kovacevic@arm.com self.modname = modname 1919264Sdjordje.kovacevic@arm.com self.modpath = modpath 1929264Sdjordje.kovacevic@arm.com self.arcname = joinpath(*arcpath) 1939264Sdjordje.kovacevic@arm.com self.abspath = abspath 1949264Sdjordje.kovacevic@arm.com self.compiled = File(self.filename + 'c') 1959264Sdjordje.kovacevic@arm.com self.cpp = File(self.filename + '.cc') 1969264Sdjordje.kovacevic@arm.com self.symname = PySource.invalid_sym_char.sub('_', modpath) 1979264Sdjordje.kovacevic@arm.com 1989264Sdjordje.kovacevic@arm.com PySource.modules[modpath] = self 1999264Sdjordje.kovacevic@arm.com PySource.tnodes[self.tnode] = self 2009264Sdjordje.kovacevic@arm.com PySource.symnames[self.symname] = self 2019264Sdjordje.kovacevic@arm.com 2029264Sdjordje.kovacevic@arm.comclass SimObject(PySource): 2039264Sdjordje.kovacevic@arm.com '''Add a SimObject python file as a python source object and add 2049264Sdjordje.kovacevic@arm.com it to a list of sim object modules''' 2059264Sdjordje.kovacevic@arm.com 2069264Sdjordje.kovacevic@arm.com fixed = False 2079264Sdjordje.kovacevic@arm.com modnames = [] 2089264Sdjordje.kovacevic@arm.com 2099264Sdjordje.kovacevic@arm.com def __init__(self, source, **guards): 2109264Sdjordje.kovacevic@arm.com '''Specify the source file and any guards (automatically in 2119264Sdjordje.kovacevic@arm.com the m5.objects package)''' 2129264Sdjordje.kovacevic@arm.com super(SimObject, self).__init__('m5.objects', source, **guards) 2139264Sdjordje.kovacevic@arm.com if self.fixed: 2149264Sdjordje.kovacevic@arm.com raise AttributeError, "Too late to call SimObject now." 2159264Sdjordje.kovacevic@arm.com 2169264Sdjordje.kovacevic@arm.com bisect.insort_right(SimObject.modnames, self.modname) 2179264Sdjordje.kovacevic@arm.com 2189264Sdjordje.kovacevic@arm.comclass SwigSource(SourceFile): 2199264Sdjordje.kovacevic@arm.com '''Add a swig file to build''' 2209264Sdjordje.kovacevic@arm.com 2219264Sdjordje.kovacevic@arm.com def __init__(self, package, source, **guards): 2229264Sdjordje.kovacevic@arm.com '''Specify the python package, the source file, and any guards''' 2239264Sdjordje.kovacevic@arm.com super(SwigSource, self).__init__(source, **guards) 2249264Sdjordje.kovacevic@arm.com 2259264Sdjordje.kovacevic@arm.com modname,ext = self.extname 2269264Sdjordje.kovacevic@arm.com assert ext == 'i' 2279264Sdjordje.kovacevic@arm.com 2289264Sdjordje.kovacevic@arm.com self.module = modname 2299264Sdjordje.kovacevic@arm.com cc_file = joinpath(self.dirname, modname + '_wrap.cc') 2309264Sdjordje.kovacevic@arm.com py_file = joinpath(self.dirname, modname + '.py') 2319264Sdjordje.kovacevic@arm.com 2329264Sdjordje.kovacevic@arm.com self.cc_source = Source(cc_file, swig=True, parent=self) 2339264Sdjordje.kovacevic@arm.com self.py_source = PySource(package, py_file, parent=self) 2349264Sdjordje.kovacevic@arm.com 2359264Sdjordje.kovacevic@arm.comclass UnitTest(object): 2369264Sdjordje.kovacevic@arm.com '''Create a UnitTest''' 2379264Sdjordje.kovacevic@arm.com 2389264Sdjordje.kovacevic@arm.com all = [] 2399264Sdjordje.kovacevic@arm.com def __init__(self, target, *sources): 2409264Sdjordje.kovacevic@arm.com '''Specify the target name and any sources. Sources that are 2419264Sdjordje.kovacevic@arm.com not SourceFiles are evalued with Source(). All files are 2429264Sdjordje.kovacevic@arm.com guarded with a guard of the same name as the UnitTest 2439264Sdjordje.kovacevic@arm.com target.''' 2449264Sdjordje.kovacevic@arm.com 2459264Sdjordje.kovacevic@arm.com srcs = [] 2469264Sdjordje.kovacevic@arm.com for src in sources: 2479264Sdjordje.kovacevic@arm.com if not isinstance(src, SourceFile): 2489264Sdjordje.kovacevic@arm.com src = Source(src, skip_lib=True) 2499264Sdjordje.kovacevic@arm.com src.guards[target] = True 2509264Sdjordje.kovacevic@arm.com srcs.append(src) 2519264Sdjordje.kovacevic@arm.com 2529264Sdjordje.kovacevic@arm.com self.sources = srcs 2539264Sdjordje.kovacevic@arm.com self.target = target 2549264Sdjordje.kovacevic@arm.com UnitTest.all.append(self) 2559264Sdjordje.kovacevic@arm.com 2569264Sdjordje.kovacevic@arm.com# Children should have access 2579264Sdjordje.kovacevic@arm.comExport('Source') 2589264Sdjordje.kovacevic@arm.comExport('PySource') 2599264Sdjordje.kovacevic@arm.comExport('SimObject') 2609264Sdjordje.kovacevic@arm.comExport('SwigSource') 2619264Sdjordje.kovacevic@arm.comExport('UnitTest') 2629264Sdjordje.kovacevic@arm.com 2639264Sdjordje.kovacevic@arm.com######################################################################## 2649264Sdjordje.kovacevic@arm.com# 2659264Sdjordje.kovacevic@arm.com# Debug Flags 2669264Sdjordje.kovacevic@arm.com# 2679264Sdjordje.kovacevic@arm.comdebug_flags = {} 2689264Sdjordje.kovacevic@arm.comdef DebugFlag(name, desc=None): 2699264Sdjordje.kovacevic@arm.com if name in debug_flags: 2709264Sdjordje.kovacevic@arm.com raise AttributeError, "Flag %s already specified" % name 2719264Sdjordje.kovacevic@arm.com debug_flags[name] = (name, (), desc) 2729264Sdjordje.kovacevic@arm.com 2739264Sdjordje.kovacevic@arm.comdef CompoundFlag(name, flags, desc=None): 2749264Sdjordje.kovacevic@arm.com if name in debug_flags: 2759264Sdjordje.kovacevic@arm.com raise AttributeError, "Flag %s already specified" % name 2769264Sdjordje.kovacevic@arm.com 2779264Sdjordje.kovacevic@arm.com compound = tuple(flags) 2789264Sdjordje.kovacevic@arm.com debug_flags[name] = (name, compound, desc) 279 280Export('DebugFlag') 281Export('CompoundFlag') 282 283######################################################################## 284# 285# Set some compiler variables 286# 287 288# Include file paths are rooted in this directory. SCons will 289# automatically expand '.' to refer to both the source directory and 290# the corresponding build directory to pick up generated include 291# files. 292env.Append(CPPPATH=Dir('.')) 293 294for extra_dir in extras_dir_list: 295 env.Append(CPPPATH=Dir(extra_dir)) 296 297# Workaround for bug in SCons version > 0.97d20071212 298# Scons bug id: 2006 gem5 Bug id: 308 299for root, dirs, files in os.walk(base_dir, topdown=True): 300 Dir(root[len(base_dir) + 1:]) 301 302######################################################################## 303# 304# Walk the tree and execute all SConscripts in subdirectories 305# 306 307here = Dir('.').srcnode().abspath 308for root, dirs, files in os.walk(base_dir, topdown=True): 309 if root == here: 310 # we don't want to recurse back into this SConscript 311 continue 312 313 if 'SConscript' in files: 314 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 315 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 316 317for extra_dir in extras_dir_list: 318 prefix_len = len(dirname(extra_dir)) + 1 319 for root, dirs, files in os.walk(extra_dir, topdown=True): 320 # if build lives in the extras directory, don't walk down it 321 if 'build' in dirs: 322 dirs.remove('build') 323 324 if 'SConscript' in files: 325 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 326 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 327 328for opt in export_vars: 329 env.ConfigFile(opt) 330 331def makeTheISA(source, target, env): 332 isas = [ src.get_contents() for src in source ] 333 target_isa = env['TARGET_ISA'] 334 def define(isa): 335 return isa.upper() + '_ISA' 336 337 def namespace(isa): 338 return isa[0].upper() + isa[1:].lower() + 'ISA' 339 340 341 code = code_formatter() 342 code('''\ 343#ifndef __CONFIG_THE_ISA_HH__ 344#define __CONFIG_THE_ISA_HH__ 345 346''') 347 348 for i,isa in enumerate(isas): 349 code('#define $0 $1', define(isa), i + 1) 350 351 code(''' 352 353#define THE_ISA ${{define(target_isa)}} 354#define TheISA ${{namespace(target_isa)}} 355 356#endif // __CONFIG_THE_ISA_HH__''') 357 358 code.write(str(target[0])) 359 360env.Command('config/the_isa.hh', map(Value, all_isa_list), 361 MakeAction(makeTheISA, Transform("CFG ISA", 0))) 362 363######################################################################## 364# 365# Prevent any SimObjects from being added after this point, they 366# should all have been added in the SConscripts above 367# 368SimObject.fixed = True 369 370class DictImporter(object): 371 '''This importer takes a dictionary of arbitrary module names that 372 map to arbitrary filenames.''' 373 def __init__(self, modules): 374 self.modules = modules 375 self.installed = set() 376 377 def __del__(self): 378 self.unload() 379 380 def unload(self): 381 import sys 382 for module in self.installed: 383 del sys.modules[module] 384 self.installed = set() 385 386 def find_module(self, fullname, path): 387 if fullname == 'm5.defines': 388 return self 389 390 if fullname == 'm5.objects': 391 return self 392 393 if fullname.startswith('m5.internal'): 394 return None 395 396 source = self.modules.get(fullname, None) 397 if source is not None and fullname.startswith('m5.objects'): 398 return self 399 400 return None 401 402 def load_module(self, fullname): 403 mod = imp.new_module(fullname) 404 sys.modules[fullname] = mod 405 self.installed.add(fullname) 406 407 mod.__loader__ = self 408 if fullname == 'm5.objects': 409 mod.__path__ = fullname.split('.') 410 return mod 411 412 if fullname == 'm5.defines': 413 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 414 return mod 415 416 source = self.modules[fullname] 417 if source.modname == '__init__': 418 mod.__path__ = source.modpath 419 mod.__file__ = source.abspath 420 421 exec file(source.abspath, 'r') in mod.__dict__ 422 423 return mod 424 425import m5.SimObject 426import m5.params 427from m5.util import code_formatter 428 429m5.SimObject.clear() 430m5.params.clear() 431 432# install the python importer so we can grab stuff from the source 433# tree itself. We can't have SimObjects added after this point or 434# else we won't know about them for the rest of the stuff. 435importer = DictImporter(PySource.modules) 436sys.meta_path[0:0] = [ importer ] 437 438# import all sim objects so we can populate the all_objects list 439# make sure that we're working with a list, then let's sort it 440for modname in SimObject.modnames: 441 exec('from m5.objects import %s' % modname) 442 443# we need to unload all of the currently imported modules so that they 444# will be re-imported the next time the sconscript is run 445importer.unload() 446sys.meta_path.remove(importer) 447 448sim_objects = m5.SimObject.allClasses 449all_enums = m5.params.allEnums 450 451# Find param types that need to be explicitly wrapped with swig. 452# These will be recognized because the ParamDesc will have a 453# swig_decl() method. Most param types are based on types that don't 454# need this, either because they're based on native types (like Int) 455# or because they're SimObjects (which get swigged independently). 456# For now the only things handled here are VectorParam types. 457params_to_swig = {} 458for name,obj in sorted(sim_objects.iteritems()): 459 for param in obj._params.local.values(): 460 # load the ptype attribute now because it depends on the 461 # current version of SimObject.allClasses, but when scons 462 # actually uses the value, all versions of 463 # SimObject.allClasses will have been loaded 464 param.ptype 465 466 if not hasattr(param, 'swig_decl'): 467 continue 468 pname = param.ptype_str 469 if pname not in params_to_swig: 470 params_to_swig[pname] = param 471 472######################################################################## 473# 474# calculate extra dependencies 475# 476module_depends = ["m5", "m5.SimObject", "m5.params"] 477depends = [ PySource.modules[dep].snode for dep in module_depends ] 478 479######################################################################## 480# 481# Commands for the basic automatically generated python files 482# 483 484# Generate Python file containing a dict specifying the current 485# buildEnv flags. 486def makeDefinesPyFile(target, source, env): 487 build_env = source[0].get_contents() 488 489 code = code_formatter() 490 code(""" 491import m5.internal 492import m5.util 493 494buildEnv = m5.util.SmartDict($build_env) 495 496compileDate = m5.internal.core.compileDate 497_globals = globals() 498for key,val in m5.internal.core.__dict__.iteritems(): 499 if key.startswith('flag_'): 500 flag = key[5:] 501 _globals[flag] = val 502del _globals 503""") 504 code.write(target[0].abspath) 505 506defines_info = Value(build_env) 507# Generate a file with all of the compile options in it 508env.Command('python/m5/defines.py', defines_info, 509 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 510PySource('m5', 'python/m5/defines.py') 511 512# Generate python file containing info about the M5 source code 513def makeInfoPyFile(target, source, env): 514 code = code_formatter() 515 for src in source: 516 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 517 code('$src = ${{repr(data)}}') 518 code.write(str(target[0])) 519 520# Generate a file that wraps the basic top level files 521env.Command('python/m5/info.py', 522 [ '#/COPYING', '#/LICENSE', '#/README', ], 523 MakeAction(makeInfoPyFile, Transform("INFO"))) 524PySource('m5', 'python/m5/info.py') 525 526######################################################################## 527# 528# Create all of the SimObject param headers and enum headers 529# 530 531def createSimObjectParamStruct(target, source, env): 532 assert len(target) == 1 and len(source) == 1 533 534 name = str(source[0].get_contents()) 535 obj = sim_objects[name] 536 537 code = code_formatter() 538 obj.cxx_param_decl(code) 539 code.write(target[0].abspath) 540 541def createParamSwigWrapper(target, source, env): 542 assert len(target) == 1 and len(source) == 1 543 544 name = str(source[0].get_contents()) 545 param = params_to_swig[name] 546 547 code = code_formatter() 548 param.swig_decl(code) 549 code.write(target[0].abspath) 550 551def createEnumStrings(target, source, env): 552 assert len(target) == 1 and len(source) == 1 553 554 name = str(source[0].get_contents()) 555 obj = all_enums[name] 556 557 code = code_formatter() 558 obj.cxx_def(code) 559 code.write(target[0].abspath) 560 561def createEnumDecls(target, source, env): 562 assert len(target) == 1 and len(source) == 1 563 564 name = str(source[0].get_contents()) 565 obj = all_enums[name] 566 567 code = code_formatter() 568 obj.cxx_decl(code) 569 code.write(target[0].abspath) 570 571def createEnumSwigWrapper(target, source, env): 572 assert len(target) == 1 and len(source) == 1 573 574 name = str(source[0].get_contents()) 575 obj = all_enums[name] 576 577 code = code_formatter() 578 obj.swig_decl(code) 579 code.write(target[0].abspath) 580 581def createSimObjectSwigWrapper(target, source, env): 582 name = source[0].get_contents() 583 obj = sim_objects[name] 584 585 code = code_formatter() 586 obj.swig_decl(code) 587 code.write(target[0].abspath) 588 589# Generate all of the SimObject param C++ struct header files 590params_hh_files = [] 591for name,simobj in sorted(sim_objects.iteritems()): 592 py_source = PySource.modules[simobj.__module__] 593 extra_deps = [ py_source.tnode ] 594 595 hh_file = File('params/%s.hh' % name) 596 params_hh_files.append(hh_file) 597 env.Command(hh_file, Value(name), 598 MakeAction(createSimObjectParamStruct, Transform("SO PARAM"))) 599 env.Depends(hh_file, depends + extra_deps) 600 601# Generate any needed param SWIG wrapper files 602params_i_files = [] 603for name,param in params_to_swig.iteritems(): 604 i_file = File('python/m5/internal/%s.i' % (param.swig_module_name())) 605 params_i_files.append(i_file) 606 env.Command(i_file, Value(name), 607 MakeAction(createParamSwigWrapper, Transform("SW PARAM"))) 608 env.Depends(i_file, depends) 609 SwigSource('m5.internal', i_file) 610 611# Generate all enum header files 612for name,enum in sorted(all_enums.iteritems()): 613 py_source = PySource.modules[enum.__module__] 614 extra_deps = [ py_source.tnode ] 615 616 cc_file = File('enums/%s.cc' % name) 617 env.Command(cc_file, Value(name), 618 MakeAction(createEnumStrings, Transform("ENUM STR"))) 619 env.Depends(cc_file, depends + extra_deps) 620 Source(cc_file) 621 622 hh_file = File('enums/%s.hh' % name) 623 env.Command(hh_file, Value(name), 624 MakeAction(createEnumDecls, Transform("ENUMDECL"))) 625 env.Depends(hh_file, depends + extra_deps) 626 627 i_file = File('python/m5/internal/enum_%s.i' % name) 628 env.Command(i_file, Value(name), 629 MakeAction(createEnumSwigWrapper, Transform("ENUMSWIG"))) 630 env.Depends(i_file, depends + extra_deps) 631 SwigSource('m5.internal', i_file) 632 633# Generate SimObject SWIG wrapper files 634for name in sim_objects.iterkeys(): 635 i_file = File('python/m5/internal/param_%s.i' % name) 636 env.Command(i_file, Value(name), 637 MakeAction(createSimObjectSwigWrapper, Transform("SO SWIG"))) 638 env.Depends(i_file, depends) 639 SwigSource('m5.internal', i_file) 640 641# Generate the main swig init file 642def makeEmbeddedSwigInit(target, source, env): 643 code = code_formatter() 644 module = source[0].get_contents() 645 code('''\ 646#include "sim/init.hh" 647 648extern "C" { 649 void init_${module}(); 650} 651 652EmbeddedSwig embed_swig_${module}(init_${module}); 653''') 654 code.write(str(target[0])) 655 656# Build all swig modules 657for swig in SwigSource.all: 658 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 659 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 660 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG"))) 661 cc_file = str(swig.tnode) 662 init_file = '%s/%s_init.cc' % (dirname(cc_file), basename(cc_file)) 663 env.Command(init_file, Value(swig.module), 664 MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW"))) 665 Source(init_file, **swig.guards) 666 667# 668# Handle debug flags 669# 670def makeDebugFlagCC(target, source, env): 671 assert(len(target) == 1 and len(source) == 1) 672 673 val = eval(source[0].get_contents()) 674 name, compound, desc = val 675 compound = list(sorted(compound)) 676 677 code = code_formatter() 678 679 # file header 680 code(''' 681/* 682 * DO NOT EDIT THIS FILE! Automatically generated 683 */ 684 685#include "base/debug.hh" 686''') 687 688 for flag in compound: 689 code('#include "debug/$flag.hh"') 690 code() 691 code('namespace Debug {') 692 code() 693 694 if not compound: 695 code('SimpleFlag $name("$name", "$desc");') 696 else: 697 code('CompoundFlag $name("$name", "$desc",') 698 code.indent() 699 last = len(compound) - 1 700 for i,flag in enumerate(compound): 701 if i != last: 702 code('$flag,') 703 else: 704 code('$flag);') 705 code.dedent() 706 707 code() 708 code('} // namespace Debug') 709 710 code.write(str(target[0])) 711 712def makeDebugFlagHH(target, source, env): 713 assert(len(target) == 1 and len(source) == 1) 714 715 val = eval(source[0].get_contents()) 716 name, compound, desc = val 717 718 code = code_formatter() 719 720 # file header boilerplate 721 code('''\ 722/* 723 * DO NOT EDIT THIS FILE! 724 * 725 * Automatically generated by SCons 726 */ 727 728#ifndef __DEBUG_${name}_HH__ 729#define __DEBUG_${name}_HH__ 730 731namespace Debug { 732''') 733 734 if compound: 735 code('class CompoundFlag;') 736 code('class SimpleFlag;') 737 738 if compound: 739 code('extern CompoundFlag $name;') 740 for flag in compound: 741 code('extern SimpleFlag $flag;') 742 else: 743 code('extern SimpleFlag $name;') 744 745 code(''' 746} 747 748#endif // __DEBUG_${name}_HH__ 749''') 750 751 code.write(str(target[0])) 752 753for name,flag in sorted(debug_flags.iteritems()): 754 n, compound, desc = flag 755 assert n == name 756 757 env.Command('debug/%s.hh' % name, Value(flag), 758 MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) 759 env.Command('debug/%s.cc' % name, Value(flag), 760 MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) 761 Source('debug/%s.cc' % name) 762 763# Embed python files. All .py files that have been indicated by a 764# PySource() call in a SConscript need to be embedded into the M5 765# library. To do that, we compile the file to byte code, marshal the 766# byte code, compress it, and then generate a c++ file that 767# inserts the result into an array. 768def embedPyFile(target, source, env): 769 def c_str(string): 770 if string is None: 771 return "0" 772 return '"%s"' % string 773 774 '''Action function to compile a .py into a code object, marshal 775 it, compress it, and stick it into an asm file so the code appears 776 as just bytes with a label in the data section''' 777 778 src = file(str(source[0]), 'r').read() 779 780 pysource = PySource.tnodes[source[0]] 781 compiled = compile(src, pysource.abspath, 'exec') 782 marshalled = marshal.dumps(compiled) 783 compressed = zlib.compress(marshalled) 784 data = compressed 785 sym = pysource.symname 786 787 code = code_formatter() 788 code('''\ 789#include "sim/init.hh" 790 791namespace { 792 793const char data_${sym}[] = { 794''') 795 code.indent() 796 step = 16 797 for i in xrange(0, len(data), step): 798 x = array.array('B', data[i:i+step]) 799 code(''.join('%d,' % d for d in x)) 800 code.dedent() 801 802 code('''}; 803 804EmbeddedPython embedded_${sym}( 805 ${{c_str(pysource.arcname)}}, 806 ${{c_str(pysource.abspath)}}, 807 ${{c_str(pysource.modpath)}}, 808 data_${sym}, 809 ${{len(data)}}, 810 ${{len(marshalled)}}); 811 812} // anonymous namespace 813''') 814 code.write(str(target[0])) 815 816for source in PySource.all: 817 env.Command(source.cpp, source.tnode, 818 MakeAction(embedPyFile, Transform("EMBED PY"))) 819 Source(source.cpp) 820 821######################################################################## 822# 823# Define binaries. Each different build type (debug, opt, etc.) gets 824# a slightly different build environment. 825# 826 827# List of constructed environments to pass back to SConstruct 828envList = [] 829 830date_source = Source('base/date.cc', skip_lib=True) 831 832# Function to create a new build environment as clone of current 833# environment 'env' with modified object suffix and optional stripped 834# binary. Additional keyword arguments are appended to corresponding 835# build environment vars. 836def makeEnv(label, objsfx, strip = False, **kwargs): 837 # SCons doesn't know to append a library suffix when there is a '.' in the 838 # name. Use '_' instead. 839 libname = 'gem5_' + label 840 exename = 'gem5.' + label 841 secondary_exename = 'm5.' + label 842 843 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 844 new_env.Label = label 845 new_env.Append(**kwargs) 846 # Always consider warnings errors 847 new_env.Append(CCFLAGS='-Werror') 848 849 swig_env = new_env.Clone() 850 if env['GCC']: 851 swig_env.Append(CCFLAGS='-Wno-uninitialized') 852 swig_env.Append(CCFLAGS='-Wno-sign-compare') 853 swig_env.Append(CCFLAGS='-Wno-parentheses') 854 swig_env.Append(CCFLAGS='-Wno-unused-label') 855 if compareVersions(env['GCC_VERSION'], '4.6.0') != -1: 856 swig_env.Append(CCFLAGS='-Wno-unused-but-set-variable') 857 if env['CLANG']: 858 swig_env.Append(CCFLAGS=['-Wno-unused-label']) 859 860 def make_obj(source, static, extra_deps = None): 861 '''This function adds the specified source to the correct 862 build environment, and returns the corresponding SCons Object 863 nodes''' 864 865 if source.swig: 866 env = swig_env 867 else: 868 env = new_env 869 870 if static: 871 obj = env.StaticObject(source.tnode) 872 else: 873 obj = env.SharedObject(source.tnode) 874 875 if extra_deps: 876 env.Depends(obj, extra_deps) 877 878 return obj 879 880 static_objs = \ 881 [ make_obj(s, True) for s in Source.get(main=False, skip_lib=False) ] 882 shared_objs = \ 883 [ make_obj(s, False) for s in Source.get(main=False, skip_lib=False) ] 884 885 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 886 static_objs.append(static_date) 887 888 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 889 shared_objs.append(shared_date) 890 891 # First make a library of everything but main() so other programs can 892 # link against m5. 893 static_lib = new_env.StaticLibrary(libname, static_objs) 894 shared_lib = new_env.SharedLibrary(libname, shared_objs) 895 896 # Now link a stub with main() and the static library. 897 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ] 898 899 for test in UnitTest.all: 900 flags = { test.target : True } 901 test_sources = Source.get(**flags) 902 test_objs = [ make_obj(s, static=True) for s in test_sources ] 903 testname = "unittest/%s.%s" % (test.target, label) 904 new_env.Program(testname, test_objs + static_objs) 905 906 progname = exename 907 if strip: 908 progname += '.unstripped' 909 910 targets = new_env.Program(progname, main_objs + static_objs) 911 912 if strip: 913 if sys.platform == 'sunos5': 914 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 915 else: 916 cmd = 'strip $SOURCE -o $TARGET' 917 targets = new_env.Command(exename, progname, 918 MakeAction(cmd, Transform("STRIP"))) 919 920 new_env.Command(secondary_exename, exename, 921 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK"))) 922 923 new_env.M5Binary = targets[0] 924 envList.append(new_env) 925 926# Debug binary 927ccflags = {} 928if env['GCC'] or env['CLANG']: 929 if sys.platform == 'sunos5': 930 ccflags['debug'] = '-gstabs+' 931 else: 932 ccflags['debug'] = '-ggdb3' 933 ccflags['opt'] = '-g -O3' 934 ccflags['fast'] = '-O3' 935 ccflags['prof'] = '-O3 -g -pg' 936elif env['SUNCC']: 937 ccflags['debug'] = '-g0' 938 ccflags['opt'] = '-g -O' 939 ccflags['fast'] = '-fast' 940 ccflags['prof'] = '-fast -g -pg' 941elif env['ICC']: 942 ccflags['debug'] = '-g -O0' 943 ccflags['opt'] = '-g -O' 944 ccflags['fast'] = '-fast' 945 ccflags['prof'] = '-fast -g -pg' 946else: 947 print 'Unknown compiler, please fix compiler options' 948 Exit(1) 949 950 951# To speed things up, we only instantiate the build environments we 952# need. We try to identify the needed environment for each target; if 953# we can't, we fall back on instantiating all the environments just to 954# be safe. 955target_types = ['debug', 'opt', 'fast', 'prof'] 956obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof'} 957 958def identifyTarget(t): 959 ext = t.split('.')[-1] 960 if ext in target_types: 961 return ext 962 if obj2target.has_key(ext): 963 return obj2target[ext] 964 match = re.search(r'/tests/([^/]+)/', t) 965 if match and match.group(1) in target_types: 966 return match.group(1) 967 return 'all' 968 969needed_envs = [identifyTarget(target) for target in BUILD_TARGETS] 970if 'all' in needed_envs: 971 needed_envs += target_types 972 973# Debug binary 974if 'debug' in needed_envs: 975 makeEnv('debug', '.do', 976 CCFLAGS = Split(ccflags['debug']), 977 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 978 979# Optimized binary 980if 'opt' in needed_envs: 981 makeEnv('opt', '.o', 982 CCFLAGS = Split(ccflags['opt']), 983 CPPDEFINES = ['TRACING_ON=1']) 984 985# "Fast" binary 986if 'fast' in needed_envs: 987 makeEnv('fast', '.fo', strip = True, 988 CCFLAGS = Split(ccflags['fast']), 989 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 990 991# Profiled binary 992if 'prof' in needed_envs: 993 makeEnv('prof', '.po', 994 CCFLAGS = Split(ccflags['prof']), 995 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 996 LINKFLAGS = '-pg') 997 998Return('envList') 999