SConscript revision 12366
110244Satgutier@umich.edu# -*- mode:python -*- 210244Satgutier@umich.edu 310244Satgutier@umich.edu# Copyright (c) 2004-2005 The Regents of The University of Michigan 410244Satgutier@umich.edu# All rights reserved. 510244Satgutier@umich.edu# 610244Satgutier@umich.edu# Redistribution and use in source and binary forms, with or without 710244Satgutier@umich.edu# modification, are permitted provided that the following conditions are 810244Satgutier@umich.edu# met: redistributions of source code must retain the above copyright 910244Satgutier@umich.edu# notice, this list of conditions and the following disclaimer; 1010244Satgutier@umich.edu# redistributions in binary form must reproduce the above copyright 1110244Satgutier@umich.edu# notice, this list of conditions and the following disclaimer in the 1210244Satgutier@umich.edu# documentation and/or other materials provided with the distribution; 1310244Satgutier@umich.edu# neither the name of the copyright holders nor the names of its 1410244Satgutier@umich.edu# contributors may be used to endorse or promote products derived from 1510244Satgutier@umich.edu# this software without specific prior written permission. 1610244Satgutier@umich.edu# 1710244Satgutier@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1810244Satgutier@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1910244Satgutier@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2010244Satgutier@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2110244Satgutier@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2210244Satgutier@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2310244Satgutier@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2410244Satgutier@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2510244Satgutier@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2610244Satgutier@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2710244Satgutier@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2810244Satgutier@umich.edu# 2910244Satgutier@umich.edu# Authors: Nathan Binkert 3010244Satgutier@umich.edu 3110244Satgutier@umich.eduimport array 3210244Satgutier@umich.eduimport bisect 3310244Satgutier@umich.eduimport imp 3410244Satgutier@umich.eduimport marshal 3511793Sbrandon.potter@amd.comimport os 3611793Sbrandon.potter@amd.comimport re 3710244Satgutier@umich.eduimport subprocess 3810244Satgutier@umich.eduimport sys 3910244Satgutier@umich.eduimport zlib 4010785Sgope@wisc.edu 4110785Sgope@wisc.edufrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath 4211434Smitch.hayenga@arm.com 4310244Satgutier@umich.eduimport SCons 4410244Satgutier@umich.edu 4510244Satgutier@umich.edufrom gem5_scons import Transform 4610244Satgutier@umich.edu 4713959Sodanrc@yahoo.com.br# This file defines how to build a particular configuration of gem5 4813959Sodanrc@yahoo.com.br# based on variable settings in the 'env' build environment. 4913959Sodanrc@yahoo.com.br 5013959Sodanrc@yahoo.com.brImport('*') 5110244Satgutier@umich.edu 5210244Satgutier@umich.edu# Children need to see the environment 5310244Satgutier@umich.eduExport('env') 5410244Satgutier@umich.edu 5510244Satgutier@umich.edubuild_env = [(opt, env[opt]) for opt in export_vars] 5610244Satgutier@umich.edu 5710244Satgutier@umich.edufrom m5.util import code_formatter, compareVersions 5810244Satgutier@umich.edu 5910244Satgutier@umich.edu######################################################################## 6010244Satgutier@umich.edu# Code for adding source files of various types 6110244Satgutier@umich.edu# 6212180Srico.amslinger@informatik.uni-augsburg.de# When specifying a source file of some type, a set of tags can be 6312180Srico.amslinger@informatik.uni-augsburg.de# specified for that file. 6410244Satgutier@umich.edu 6510244Satgutier@umich.educlass SourceList(list): 6610244Satgutier@umich.edu def with_tags_that(self, predicate): 6710244Satgutier@umich.edu '''Return a list of sources with tags that satisfy a predicate.''' 6810244Satgutier@umich.edu def match(source): 6910244Satgutier@umich.edu return predicate(source.tags) 7010244Satgutier@umich.edu return SourceList(filter(match, self)) 7110244Satgutier@umich.edu 7211434Smitch.hayenga@arm.com def with_any_tags(self, *tags): 7310244Satgutier@umich.edu '''Return a list of sources with any of the supplied tags.''' 7410244Satgutier@umich.edu return self.with_tags_that(lambda stags: len(set(tags) & stags) > 0) 7511434Smitch.hayenga@arm.com 7610244Satgutier@umich.edu def with_all_tags(self, *tags): 7710244Satgutier@umich.edu '''Return a list of sources with all of the supplied tags.''' 7810244Satgutier@umich.edu return self.with_tags_that(lambda stags: set(tags) <= stags) 7910244Satgutier@umich.edu 8010244Satgutier@umich.edu def with_tag(self, tag): 8111434Smitch.hayenga@arm.com '''Return a list of sources with the supplied tag.''' 8210244Satgutier@umich.edu return self.with_tags_that(lambda stags: tag in stags) 8310244Satgutier@umich.edu 8410244Satgutier@umich.edu def without_tags(self, *tags): 8511434Smitch.hayenga@arm.com '''Return a list of sources without any of the supplied tags.''' 8610244Satgutier@umich.edu return self.with_tags_that(lambda stags: len(set(tags) & stags) == 0) 8710244Satgutier@umich.edu 8811434Smitch.hayenga@arm.com def without_tag(self, tag): 8910244Satgutier@umich.edu '''Return a list of sources with the supplied tag.''' 9010244Satgutier@umich.edu return self.with_tags_that(lambda stags: tag not in stags) 9110244Satgutier@umich.edu 9210244Satgutier@umich.educlass SourceMeta(type): 9310244Satgutier@umich.edu '''Meta class for source files that keeps track of all files of a 9410244Satgutier@umich.edu particular type.''' 9510244Satgutier@umich.edu def __init__(cls, name, bases, dict): 9610244Satgutier@umich.edu super(SourceMeta, cls).__init__(name, bases, dict) 9710244Satgutier@umich.edu cls.all = SourceList() 9810244Satgutier@umich.edu 9910244Satgutier@umich.educlass SourceFile(object): 10010244Satgutier@umich.edu '''Base object that encapsulates the notion of a source file. 10110244Satgutier@umich.edu This includes, the source node, target node, various manipulations 10210244Satgutier@umich.edu of those. A source file also specifies a set of tags which 10311434Smitch.hayenga@arm.com describing arbitrary properties of the source file.''' 10410244Satgutier@umich.edu __metaclass__ = SourceMeta 10510244Satgutier@umich.edu 10610244Satgutier@umich.edu static_objs = {} 10710244Satgutier@umich.edu shared_objs = {} 10811434Smitch.hayenga@arm.com 10910244Satgutier@umich.edu def __init__(self, source, tags=None, add_tags=None): 11010244Satgutier@umich.edu if tags is None: 11110244Satgutier@umich.edu tags='gem5 lib' 11210244Satgutier@umich.edu if isinstance(tags, basestring): 11310244Satgutier@umich.edu tags = set([tags]) 11413959Sodanrc@yahoo.com.br if not isinstance(tags, set): 11510244Satgutier@umich.edu tags = set(tags) 11613959Sodanrc@yahoo.com.br self.tags = tags 11710244Satgutier@umich.edu 11813959Sodanrc@yahoo.com.br if add_tags: 11910244Satgutier@umich.edu if isinstance(add_tags, basestring): 12010244Satgutier@umich.edu add_tags = set([add_tags]) 12110244Satgutier@umich.edu if not isinstance(add_tags, set): 12210244Satgutier@umich.edu add_tags = set(add_tags) 12311434Smitch.hayenga@arm.com self.tags |= add_tags 12410244Satgutier@umich.edu 12510244Satgutier@umich.edu tnode = source 12610244Satgutier@umich.edu if not isinstance(source, SCons.Node.FS.File): 12710244Satgutier@umich.edu tnode = File(source) 12810244Satgutier@umich.edu 12910244Satgutier@umich.edu self.tnode = tnode 13010244Satgutier@umich.edu self.snode = tnode.srcnode() 13110244Satgutier@umich.edu 13210244Satgutier@umich.edu for base in type(self).__mro__: 13310244Satgutier@umich.edu if issubclass(base, SourceFile): 13410244Satgutier@umich.edu base.all.append(self) 13510244Satgutier@umich.edu 13611434Smitch.hayenga@arm.com def static(self, env): 13710244Satgutier@umich.edu key = (self.tnode, env['OBJSUFFIX']) 13810244Satgutier@umich.edu if not key in self.static_objs: 13910244Satgutier@umich.edu self.static_objs[key] = env.StaticObject(self.tnode) 14010244Satgutier@umich.edu return self.static_objs[key] 14110244Satgutier@umich.edu 14211434Smitch.hayenga@arm.com def shared(self, env): 14310244Satgutier@umich.edu key = (self.tnode, env['OBJSUFFIX']) 14411434Smitch.hayenga@arm.com if not key in self.shared_objs: 14510244Satgutier@umich.edu self.shared_objs[key] = env.SharedObject(self.tnode) 14610244Satgutier@umich.edu return self.shared_objs[key] 14710244Satgutier@umich.edu 14810244Satgutier@umich.edu @property 14910244Satgutier@umich.edu def filename(self): 15010244Satgutier@umich.edu return str(self.tnode) 15110244Satgutier@umich.edu 15210244Satgutier@umich.edu @property 15310244Satgutier@umich.edu def dirname(self): 15411434Smitch.hayenga@arm.com return dirname(self.filename) 15513626Sjairo.balart@metempsy.com 15610244Satgutier@umich.edu @property 15711783Sarthur.perais@inria.fr def basename(self): 15810244Satgutier@umich.edu return basename(self.filename) 15911783Sarthur.perais@inria.fr 16010244Satgutier@umich.edu @property 16111783Sarthur.perais@inria.fr def extname(self): 16211783Sarthur.perais@inria.fr index = self.basename.rfind('.') 16311783Sarthur.perais@inria.fr if index <= 0: 16411783Sarthur.perais@inria.fr # dot files aren't extensions 16511783Sarthur.perais@inria.fr return self.basename, None 16611783Sarthur.perais@inria.fr 16710244Satgutier@umich.edu return self.basename[:index], self.basename[index+1:] 16811783Sarthur.perais@inria.fr 16911783Sarthur.perais@inria.fr def __lt__(self, other): return self.filename < other.filename 17011783Sarthur.perais@inria.fr def __le__(self, other): return self.filename <= other.filename 17111783Sarthur.perais@inria.fr def __gt__(self, other): return self.filename > other.filename 17211783Sarthur.perais@inria.fr def __ge__(self, other): return self.filename >= other.filename 17311783Sarthur.perais@inria.fr def __eq__(self, other): return self.filename == other.filename 17411783Sarthur.perais@inria.fr def __ne__(self, other): return self.filename != other.filename 17511783Sarthur.perais@inria.fr 17611783Sarthur.perais@inria.frclass Source(SourceFile): 17711783Sarthur.perais@inria.fr ungrouped_tag = 'No link group' 17811783Sarthur.perais@inria.fr source_groups = set() 17911783Sarthur.perais@inria.fr 18013959Sodanrc@yahoo.com.br _current_group_tag = ungrouped_tag 18110244Satgutier@umich.edu 18213959Sodanrc@yahoo.com.br @staticmethod 18310244Satgutier@umich.edu def link_group_tag(group): 18411783Sarthur.perais@inria.fr return 'link group: %s' % group 18511783Sarthur.perais@inria.fr 18611783Sarthur.perais@inria.fr @classmethod 18713959Sodanrc@yahoo.com.br def set_group(cls, group): 18811783Sarthur.perais@inria.fr new_tag = Source.link_group_tag(group) 18913959Sodanrc@yahoo.com.br Source._current_group_tag = new_tag 19011783Sarthur.perais@inria.fr Source.source_groups.add(group) 19111783Sarthur.perais@inria.fr 19210244Satgutier@umich.edu def _add_link_group_tag(self): 19311783Sarthur.perais@inria.fr self.tags.add(Source._current_group_tag) 19411783Sarthur.perais@inria.fr 19511783Sarthur.perais@inria.fr '''Add a c/c++ source file to the build''' 19611783Sarthur.perais@inria.fr def __init__(self, source, tags=None, add_tags=None): 19711783Sarthur.perais@inria.fr '''specify the source file, and any tags''' 19811783Sarthur.perais@inria.fr super(Source, self).__init__(source, tags, add_tags) 19911783Sarthur.perais@inria.fr self._add_link_group_tag() 20011783Sarthur.perais@inria.fr 20111783Sarthur.perais@inria.frclass PySource(SourceFile): 20211783Sarthur.perais@inria.fr '''Add a python source file to the named package''' 20311783Sarthur.perais@inria.fr invalid_sym_char = re.compile('[^A-z0-9_]') 20411783Sarthur.perais@inria.fr modules = {} 20510244Satgutier@umich.edu tnodes = {} 20613959Sodanrc@yahoo.com.br symnames = {} 20710244Satgutier@umich.edu 20813959Sodanrc@yahoo.com.br def __init__(self, package, source, tags=None, add_tags=None): 20910244Satgutier@umich.edu '''specify the python package, the source file, and any tags''' 21010244Satgutier@umich.edu super(PySource, self).__init__(source, tags, add_tags) 21111783Sarthur.perais@inria.fr 21211783Sarthur.perais@inria.fr modname,ext = self.extname 21311783Sarthur.perais@inria.fr assert ext == 'py' 21413959Sodanrc@yahoo.com.br 21510244Satgutier@umich.edu if package: 21613959Sodanrc@yahoo.com.br path = package.split('.') 21710244Satgutier@umich.edu else: 21810244Satgutier@umich.edu path = [] 21910244Satgutier@umich.edu 22010244Satgutier@umich.edu modpath = path[:] 22110244Satgutier@umich.edu if modname != '__init__': 22210244Satgutier@umich.edu modpath += [ modname ] 22311429Sandreas.sandberg@arm.com modpath = '.'.join(modpath) 22411434Smitch.hayenga@arm.com 22511426Smitch.hayenga@arm.com arcpath = path + [ self.basename ] 22611434Smitch.hayenga@arm.com abspath = self.snode.abspath 22711434Smitch.hayenga@arm.com if not exists(abspath): 22811434Smitch.hayenga@arm.com abspath = self.tnode.abspath 22910244Satgutier@umich.edu 23010785Sgope@wisc.edu self.package = package 23110785Sgope@wisc.edu self.modname = modname 23210785Sgope@wisc.edu self.modpath = modpath 23310785Sgope@wisc.edu self.arcname = joinpath(*arcpath) 23410785Sgope@wisc.edu self.abspath = abspath 23510785Sgope@wisc.edu self.compiled = File(self.filename + 'c') 236 self.cpp = File(self.filename + '.cc') 237 self.symname = PySource.invalid_sym_char.sub('_', modpath) 238 239 PySource.modules[modpath] = self 240 PySource.tnodes[self.tnode] = self 241 PySource.symnames[self.symname] = self 242 243class SimObject(PySource): 244 '''Add a SimObject python file as a python source object and add 245 it to a list of sim object modules''' 246 247 fixed = False 248 modnames = [] 249 250 def __init__(self, source, tags=None, add_tags=None): 251 '''Specify the source file and any tags (automatically in 252 the m5.objects package)''' 253 super(SimObject, self).__init__('m5.objects', source, tags, add_tags) 254 if self.fixed: 255 raise AttributeError, "Too late to call SimObject now." 256 257 bisect.insort_right(SimObject.modnames, self.modname) 258 259class ProtoBuf(SourceFile): 260 '''Add a Protocol Buffer to build''' 261 262 def __init__(self, source, tags=None, add_tags=None): 263 '''Specify the source file, and any tags''' 264 super(ProtoBuf, self).__init__(source, tags, add_tags) 265 266 # Get the file name and the extension 267 modname,ext = self.extname 268 assert ext == 'proto' 269 270 # Currently, we stick to generating the C++ headers, so we 271 # only need to track the source and header. 272 self.cc_file = File(modname + '.pb.cc') 273 self.hh_file = File(modname + '.pb.h') 274 275class UnitTest(object): 276 '''Create a UnitTest''' 277 278 all = [] 279 def __init__(self, target, *sources, **kwargs): 280 '''Specify the target name and any sources. Sources that are 281 not SourceFiles are evalued with Source(). All files are 282 tagged with the name of the UnitTest target.''' 283 284 srcs = SourceList() 285 for src in sources: 286 if not isinstance(src, SourceFile): 287 src = Source(src, tags=str(target)) 288 srcs.append(src) 289 290 self.sources = srcs 291 self.target = target 292 self.main = kwargs.get('main', False) 293 self.all.append(self) 294 295class GTest(UnitTest): 296 '''Create a unit test based on the google test framework.''' 297 298 all = [] 299 def __init__(self, *args, **kwargs): 300 super(GTest, self).__init__(*args, **kwargs) 301 self.dir = Dir('.') 302 303# Children should have access 304Export('Source') 305Export('PySource') 306Export('SimObject') 307Export('ProtoBuf') 308Export('UnitTest') 309Export('GTest') 310 311######################################################################## 312# 313# Debug Flags 314# 315debug_flags = {} 316def DebugFlag(name, desc=None): 317 if name in debug_flags: 318 raise AttributeError, "Flag %s already specified" % name 319 debug_flags[name] = (name, (), desc) 320 321def CompoundFlag(name, flags, desc=None): 322 if name in debug_flags: 323 raise AttributeError, "Flag %s already specified" % name 324 325 compound = tuple(flags) 326 debug_flags[name] = (name, compound, desc) 327 328Export('DebugFlag') 329Export('CompoundFlag') 330 331######################################################################## 332# 333# Set some compiler variables 334# 335 336# Include file paths are rooted in this directory. SCons will 337# automatically expand '.' to refer to both the source directory and 338# the corresponding build directory to pick up generated include 339# files. 340env.Append(CPPPATH=Dir('.')) 341 342for extra_dir in extras_dir_list: 343 env.Append(CPPPATH=Dir(extra_dir)) 344 345# Workaround for bug in SCons version > 0.97d20071212 346# Scons bug id: 2006 gem5 Bug id: 308 347for root, dirs, files in os.walk(base_dir, topdown=True): 348 Dir(root[len(base_dir) + 1:]) 349 350######################################################################## 351# 352# Walk the tree and execute all SConscripts in subdirectories 353# 354 355here = Dir('.').srcnode().abspath 356for root, dirs, files in os.walk(base_dir, topdown=True): 357 if root == here: 358 # we don't want to recurse back into this SConscript 359 continue 360 361 if 'SConscript' in files: 362 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 363 Source.set_group(build_dir) 364 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 365 366for extra_dir in extras_dir_list: 367 prefix_len = len(dirname(extra_dir)) + 1 368 369 # Also add the corresponding build directory to pick up generated 370 # include files. 371 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:]))) 372 373 for root, dirs, files in os.walk(extra_dir, topdown=True): 374 # if build lives in the extras directory, don't walk down it 375 if 'build' in dirs: 376 dirs.remove('build') 377 378 if 'SConscript' in files: 379 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 380 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 381 382for opt in export_vars: 383 env.ConfigFile(opt) 384 385def makeTheISA(source, target, env): 386 isas = [ src.get_contents() for src in source ] 387 target_isa = env['TARGET_ISA'] 388 def define(isa): 389 return isa.upper() + '_ISA' 390 391 def namespace(isa): 392 return isa[0].upper() + isa[1:].lower() + 'ISA' 393 394 395 code = code_formatter() 396 code('''\ 397#ifndef __CONFIG_THE_ISA_HH__ 398#define __CONFIG_THE_ISA_HH__ 399 400''') 401 402 # create defines for the preprocessing and compile-time determination 403 for i,isa in enumerate(isas): 404 code('#define $0 $1', define(isa), i + 1) 405 code() 406 407 # create an enum for any run-time determination of the ISA, we 408 # reuse the same name as the namespaces 409 code('enum class Arch {') 410 for i,isa in enumerate(isas): 411 if i + 1 == len(isas): 412 code(' $0 = $1', namespace(isa), define(isa)) 413 else: 414 code(' $0 = $1,', namespace(isa), define(isa)) 415 code('};') 416 417 code(''' 418 419#define THE_ISA ${{define(target_isa)}} 420#define TheISA ${{namespace(target_isa)}} 421#define THE_ISA_STR "${{target_isa}}" 422 423#endif // __CONFIG_THE_ISA_HH__''') 424 425 code.write(str(target[0])) 426 427env.Command('config/the_isa.hh', map(Value, all_isa_list), 428 MakeAction(makeTheISA, Transform("CFG ISA", 0))) 429 430def makeTheGPUISA(source, target, env): 431 isas = [ src.get_contents() for src in source ] 432 target_gpu_isa = env['TARGET_GPU_ISA'] 433 def define(isa): 434 return isa.upper() + '_ISA' 435 436 def namespace(isa): 437 return isa[0].upper() + isa[1:].lower() + 'ISA' 438 439 440 code = code_formatter() 441 code('''\ 442#ifndef __CONFIG_THE_GPU_ISA_HH__ 443#define __CONFIG_THE_GPU_ISA_HH__ 444 445''') 446 447 # create defines for the preprocessing and compile-time determination 448 for i,isa in enumerate(isas): 449 code('#define $0 $1', define(isa), i + 1) 450 code() 451 452 # create an enum for any run-time determination of the ISA, we 453 # reuse the same name as the namespaces 454 code('enum class GPUArch {') 455 for i,isa in enumerate(isas): 456 if i + 1 == len(isas): 457 code(' $0 = $1', namespace(isa), define(isa)) 458 else: 459 code(' $0 = $1,', namespace(isa), define(isa)) 460 code('};') 461 462 code(''' 463 464#define THE_GPU_ISA ${{define(target_gpu_isa)}} 465#define TheGpuISA ${{namespace(target_gpu_isa)}} 466#define THE_GPU_ISA_STR "${{target_gpu_isa}}" 467 468#endif // __CONFIG_THE_GPU_ISA_HH__''') 469 470 code.write(str(target[0])) 471 472env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list), 473 MakeAction(makeTheGPUISA, Transform("CFG ISA", 0))) 474 475######################################################################## 476# 477# Prevent any SimObjects from being added after this point, they 478# should all have been added in the SConscripts above 479# 480SimObject.fixed = True 481 482class DictImporter(object): 483 '''This importer takes a dictionary of arbitrary module names that 484 map to arbitrary filenames.''' 485 def __init__(self, modules): 486 self.modules = modules 487 self.installed = set() 488 489 def __del__(self): 490 self.unload() 491 492 def unload(self): 493 import sys 494 for module in self.installed: 495 del sys.modules[module] 496 self.installed = set() 497 498 def find_module(self, fullname, path): 499 if fullname == 'm5.defines': 500 return self 501 502 if fullname == 'm5.objects': 503 return self 504 505 if fullname.startswith('_m5'): 506 return None 507 508 source = self.modules.get(fullname, None) 509 if source is not None and fullname.startswith('m5.objects'): 510 return self 511 512 return None 513 514 def load_module(self, fullname): 515 mod = imp.new_module(fullname) 516 sys.modules[fullname] = mod 517 self.installed.add(fullname) 518 519 mod.__loader__ = self 520 if fullname == 'm5.objects': 521 mod.__path__ = fullname.split('.') 522 return mod 523 524 if fullname == 'm5.defines': 525 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 526 return mod 527 528 source = self.modules[fullname] 529 if source.modname == '__init__': 530 mod.__path__ = source.modpath 531 mod.__file__ = source.abspath 532 533 exec file(source.abspath, 'r') in mod.__dict__ 534 535 return mod 536 537import m5.SimObject 538import m5.params 539from m5.util import code_formatter 540 541m5.SimObject.clear() 542m5.params.clear() 543 544# install the python importer so we can grab stuff from the source 545# tree itself. We can't have SimObjects added after this point or 546# else we won't know about them for the rest of the stuff. 547importer = DictImporter(PySource.modules) 548sys.meta_path[0:0] = [ importer ] 549 550# import all sim objects so we can populate the all_objects list 551# make sure that we're working with a list, then let's sort it 552for modname in SimObject.modnames: 553 exec('from m5.objects import %s' % modname) 554 555# we need to unload all of the currently imported modules so that they 556# will be re-imported the next time the sconscript is run 557importer.unload() 558sys.meta_path.remove(importer) 559 560sim_objects = m5.SimObject.allClasses 561all_enums = m5.params.allEnums 562 563for name,obj in sorted(sim_objects.iteritems()): 564 for param in obj._params.local.values(): 565 # load the ptype attribute now because it depends on the 566 # current version of SimObject.allClasses, but when scons 567 # actually uses the value, all versions of 568 # SimObject.allClasses will have been loaded 569 param.ptype 570 571######################################################################## 572# 573# calculate extra dependencies 574# 575module_depends = ["m5", "m5.SimObject", "m5.params"] 576depends = [ PySource.modules[dep].snode for dep in module_depends ] 577depends.sort(key = lambda x: x.name) 578 579######################################################################## 580# 581# Commands for the basic automatically generated python files 582# 583 584# Generate Python file containing a dict specifying the current 585# buildEnv flags. 586def makeDefinesPyFile(target, source, env): 587 build_env = source[0].get_contents() 588 589 code = code_formatter() 590 code(""" 591import _m5.core 592import m5.util 593 594buildEnv = m5.util.SmartDict($build_env) 595 596compileDate = _m5.core.compileDate 597_globals = globals() 598for key,val in _m5.core.__dict__.iteritems(): 599 if key.startswith('flag_'): 600 flag = key[5:] 601 _globals[flag] = val 602del _globals 603""") 604 code.write(target[0].abspath) 605 606defines_info = Value(build_env) 607# Generate a file with all of the compile options in it 608env.Command('python/m5/defines.py', defines_info, 609 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 610PySource('m5', 'python/m5/defines.py') 611 612# Generate python file containing info about the M5 source code 613def makeInfoPyFile(target, source, env): 614 code = code_formatter() 615 for src in source: 616 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 617 code('$src = ${{repr(data)}}') 618 code.write(str(target[0])) 619 620# Generate a file that wraps the basic top level files 621env.Command('python/m5/info.py', 622 [ '#/COPYING', '#/LICENSE', '#/README', ], 623 MakeAction(makeInfoPyFile, Transform("INFO"))) 624PySource('m5', 'python/m5/info.py') 625 626######################################################################## 627# 628# Create all of the SimObject param headers and enum headers 629# 630 631def createSimObjectParamStruct(target, source, env): 632 assert len(target) == 1 and len(source) == 1 633 634 name = source[0].get_text_contents() 635 obj = sim_objects[name] 636 637 code = code_formatter() 638 obj.cxx_param_decl(code) 639 code.write(target[0].abspath) 640 641def createSimObjectCxxConfig(is_header): 642 def body(target, source, env): 643 assert len(target) == 1 and len(source) == 1 644 645 name = str(source[0].get_contents()) 646 obj = sim_objects[name] 647 648 code = code_formatter() 649 obj.cxx_config_param_file(code, is_header) 650 code.write(target[0].abspath) 651 return body 652 653def createEnumStrings(target, source, env): 654 assert len(target) == 1 and len(source) == 2 655 656 name = source[0].get_text_contents() 657 use_python = source[1].read() 658 obj = all_enums[name] 659 660 code = code_formatter() 661 obj.cxx_def(code) 662 if use_python: 663 obj.pybind_def(code) 664 code.write(target[0].abspath) 665 666def createEnumDecls(target, source, env): 667 assert len(target) == 1 and len(source) == 1 668 669 name = source[0].get_text_contents() 670 obj = all_enums[name] 671 672 code = code_formatter() 673 obj.cxx_decl(code) 674 code.write(target[0].abspath) 675 676def createSimObjectPyBindWrapper(target, source, env): 677 name = source[0].get_text_contents() 678 obj = sim_objects[name] 679 680 code = code_formatter() 681 obj.pybind_decl(code) 682 code.write(target[0].abspath) 683 684# Generate all of the SimObject param C++ struct header files 685params_hh_files = [] 686for name,simobj in sorted(sim_objects.iteritems()): 687 py_source = PySource.modules[simobj.__module__] 688 extra_deps = [ py_source.tnode ] 689 690 hh_file = File('params/%s.hh' % name) 691 params_hh_files.append(hh_file) 692 env.Command(hh_file, Value(name), 693 MakeAction(createSimObjectParamStruct, Transform("SO PARAM"))) 694 env.Depends(hh_file, depends + extra_deps) 695 696# C++ parameter description files 697if GetOption('with_cxx_config'): 698 for name,simobj in sorted(sim_objects.iteritems()): 699 py_source = PySource.modules[simobj.__module__] 700 extra_deps = [ py_source.tnode ] 701 702 cxx_config_hh_file = File('cxx_config/%s.hh' % name) 703 cxx_config_cc_file = File('cxx_config/%s.cc' % name) 704 env.Command(cxx_config_hh_file, Value(name), 705 MakeAction(createSimObjectCxxConfig(True), 706 Transform("CXXCPRHH"))) 707 env.Command(cxx_config_cc_file, Value(name), 708 MakeAction(createSimObjectCxxConfig(False), 709 Transform("CXXCPRCC"))) 710 env.Depends(cxx_config_hh_file, depends + extra_deps + 711 [File('params/%s.hh' % name), File('sim/cxx_config.hh')]) 712 env.Depends(cxx_config_cc_file, depends + extra_deps + 713 [cxx_config_hh_file]) 714 Source(cxx_config_cc_file) 715 716 cxx_config_init_cc_file = File('cxx_config/init.cc') 717 718 def createCxxConfigInitCC(target, source, env): 719 assert len(target) == 1 and len(source) == 1 720 721 code = code_formatter() 722 723 for name,simobj in sorted(sim_objects.iteritems()): 724 if not hasattr(simobj, 'abstract') or not simobj.abstract: 725 code('#include "cxx_config/${name}.hh"') 726 code() 727 code('void cxxConfigInit()') 728 code('{') 729 code.indent() 730 for name,simobj in sorted(sim_objects.iteritems()): 731 not_abstract = not hasattr(simobj, 'abstract') or \ 732 not simobj.abstract 733 if not_abstract and 'type' in simobj.__dict__: 734 code('cxx_config_directory["${name}"] = ' 735 '${name}CxxConfigParams::makeDirectoryEntry();') 736 code.dedent() 737 code('}') 738 code.write(target[0].abspath) 739 740 py_source = PySource.modules[simobj.__module__] 741 extra_deps = [ py_source.tnode ] 742 env.Command(cxx_config_init_cc_file, Value(name), 743 MakeAction(createCxxConfigInitCC, Transform("CXXCINIT"))) 744 cxx_param_hh_files = ["cxx_config/%s.hh" % simobj 745 for name,simobj in sorted(sim_objects.iteritems()) 746 if not hasattr(simobj, 'abstract') or not simobj.abstract] 747 Depends(cxx_config_init_cc_file, cxx_param_hh_files + 748 [File('sim/cxx_config.hh')]) 749 Source(cxx_config_init_cc_file) 750 751# Generate all enum header files 752for name,enum in sorted(all_enums.iteritems()): 753 py_source = PySource.modules[enum.__module__] 754 extra_deps = [ py_source.tnode ] 755 756 cc_file = File('enums/%s.cc' % name) 757 env.Command(cc_file, [Value(name), Value(env['USE_PYTHON'])], 758 MakeAction(createEnumStrings, Transform("ENUM STR"))) 759 env.Depends(cc_file, depends + extra_deps) 760 Source(cc_file) 761 762 hh_file = File('enums/%s.hh' % name) 763 env.Command(hh_file, Value(name), 764 MakeAction(createEnumDecls, Transform("ENUMDECL"))) 765 env.Depends(hh_file, depends + extra_deps) 766 767# Generate SimObject Python bindings wrapper files 768if env['USE_PYTHON']: 769 for name,simobj in sorted(sim_objects.iteritems()): 770 py_source = PySource.modules[simobj.__module__] 771 extra_deps = [ py_source.tnode ] 772 cc_file = File('python/_m5/param_%s.cc' % name) 773 env.Command(cc_file, Value(name), 774 MakeAction(createSimObjectPyBindWrapper, 775 Transform("SO PyBind"))) 776 env.Depends(cc_file, depends + extra_deps) 777 Source(cc_file) 778 779# Build all protocol buffers if we have got protoc and protobuf available 780if env['HAVE_PROTOBUF']: 781 for proto in ProtoBuf.all: 782 # Use both the source and header as the target, and the .proto 783 # file as the source. When executing the protoc compiler, also 784 # specify the proto_path to avoid having the generated files 785 # include the path. 786 env.Command([proto.cc_file, proto.hh_file], proto.tnode, 787 MakeAction('$PROTOC --cpp_out ${TARGET.dir} ' 788 '--proto_path ${SOURCE.dir} $SOURCE', 789 Transform("PROTOC"))) 790 791 # Add the C++ source file 792 Source(proto.cc_file, tags=proto.tags) 793elif ProtoBuf.all: 794 print 'Got protobuf to build, but lacks support!' 795 Exit(1) 796 797# 798# Handle debug flags 799# 800def makeDebugFlagCC(target, source, env): 801 assert(len(target) == 1 and len(source) == 1) 802 803 code = code_formatter() 804 805 # delay definition of CompoundFlags until after all the definition 806 # of all constituent SimpleFlags 807 comp_code = code_formatter() 808 809 # file header 810 code(''' 811/* 812 * DO NOT EDIT THIS FILE! Automatically generated by SCons. 813 */ 814 815#include "base/debug.hh" 816 817namespace Debug { 818 819''') 820 821 for name, flag in sorted(source[0].read().iteritems()): 822 n, compound, desc = flag 823 assert n == name 824 825 if not compound: 826 code('SimpleFlag $name("$name", "$desc");') 827 else: 828 comp_code('CompoundFlag $name("$name", "$desc",') 829 comp_code.indent() 830 last = len(compound) - 1 831 for i,flag in enumerate(compound): 832 if i != last: 833 comp_code('&$flag,') 834 else: 835 comp_code('&$flag);') 836 comp_code.dedent() 837 838 code.append(comp_code) 839 code() 840 code('} // namespace Debug') 841 842 code.write(str(target[0])) 843 844def makeDebugFlagHH(target, source, env): 845 assert(len(target) == 1 and len(source) == 1) 846 847 val = eval(source[0].get_contents()) 848 name, compound, desc = val 849 850 code = code_formatter() 851 852 # file header boilerplate 853 code('''\ 854/* 855 * DO NOT EDIT THIS FILE! Automatically generated by SCons. 856 */ 857 858#ifndef __DEBUG_${name}_HH__ 859#define __DEBUG_${name}_HH__ 860 861namespace Debug { 862''') 863 864 if compound: 865 code('class CompoundFlag;') 866 code('class SimpleFlag;') 867 868 if compound: 869 code('extern CompoundFlag $name;') 870 for flag in compound: 871 code('extern SimpleFlag $flag;') 872 else: 873 code('extern SimpleFlag $name;') 874 875 code(''' 876} 877 878#endif // __DEBUG_${name}_HH__ 879''') 880 881 code.write(str(target[0])) 882 883for name,flag in sorted(debug_flags.iteritems()): 884 n, compound, desc = flag 885 assert n == name 886 887 hh_file = 'debug/%s.hh' % name 888 env.Command(hh_file, Value(flag), 889 MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) 890 891env.Command('debug/flags.cc', Value(debug_flags), 892 MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) 893Source('debug/flags.cc') 894 895# version tags 896tags = \ 897env.Command('sim/tags.cc', None, 898 MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET', 899 Transform("VER TAGS"))) 900env.AlwaysBuild(tags) 901 902# Embed python files. All .py files that have been indicated by a 903# PySource() call in a SConscript need to be embedded into the M5 904# library. To do that, we compile the file to byte code, marshal the 905# byte code, compress it, and then generate a c++ file that 906# inserts the result into an array. 907def embedPyFile(target, source, env): 908 def c_str(string): 909 if string is None: 910 return "0" 911 return '"%s"' % string 912 913 '''Action function to compile a .py into a code object, marshal 914 it, compress it, and stick it into an asm file so the code appears 915 as just bytes with a label in the data section''' 916 917 src = file(str(source[0]), 'r').read() 918 919 pysource = PySource.tnodes[source[0]] 920 compiled = compile(src, pysource.abspath, 'exec') 921 marshalled = marshal.dumps(compiled) 922 compressed = zlib.compress(marshalled) 923 data = compressed 924 sym = pysource.symname 925 926 code = code_formatter() 927 code('''\ 928#include "sim/init.hh" 929 930namespace { 931 932const uint8_t data_${sym}[] = { 933''') 934 code.indent() 935 step = 16 936 for i in xrange(0, len(data), step): 937 x = array.array('B', data[i:i+step]) 938 code(''.join('%d,' % d for d in x)) 939 code.dedent() 940 941 code('''}; 942 943EmbeddedPython embedded_${sym}( 944 ${{c_str(pysource.arcname)}}, 945 ${{c_str(pysource.abspath)}}, 946 ${{c_str(pysource.modpath)}}, 947 data_${sym}, 948 ${{len(data)}}, 949 ${{len(marshalled)}}); 950 951} // anonymous namespace 952''') 953 code.write(str(target[0])) 954 955for source in PySource.all: 956 env.Command(source.cpp, source.tnode, 957 MakeAction(embedPyFile, Transform("EMBED PY"))) 958 Source(source.cpp, tags=source.tags, add_tags='python') 959 960######################################################################## 961# 962# Define binaries. Each different build type (debug, opt, etc.) gets 963# a slightly different build environment. 964# 965 966# List of constructed environments to pass back to SConstruct 967date_source = Source('base/date.cc', tags=[]) 968 969# Function to create a new build environment as clone of current 970# environment 'env' with modified object suffix and optional stripped 971# binary. Additional keyword arguments are appended to corresponding 972# build environment vars. 973def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs): 974 # SCons doesn't know to append a library suffix when there is a '.' in the 975 # name. Use '_' instead. 976 libname = 'gem5_' + label 977 exename = 'gem5.' + label 978 secondary_exename = 'm5.' + label 979 980 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 981 new_env.Label = label 982 new_env.Append(**kwargs) 983 984 lib_sources = Source.all.with_tag('gem5 lib') 985 986 # Without Python, leave out all Python content from the library 987 # builds. The option doesn't affect gem5 built as a program 988 if GetOption('without_python'): 989 lib_sources = lib_sources.without_tag('python') 990 991 static_objs = [] 992 shared_objs = [] 993 994 for s in lib_sources.with_tag(Source.ungrouped_tag): 995 static_objs.append(s.static(new_env)) 996 shared_objs.append(s.shared(new_env)) 997 998 for group in Source.source_groups: 999 srcs = lib_sources.with_tag(Source.link_group_tag(group)) 1000 if not srcs: 1001 continue 1002 1003 group_static = [ s.static(new_env) for s in srcs ] 1004 group_shared = [ s.shared(new_env) for s in srcs ] 1005 1006 # If partial linking is disabled, add these sources to the build 1007 # directly, and short circuit this loop. 1008 if disable_partial: 1009 static_objs.extend(group_static) 1010 shared_objs.extend(group_shared) 1011 continue 1012 1013 # Set up the static partially linked objects. 1014 file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial") 1015 target = File(joinpath(group, file_name)) 1016 partial = env.PartialStatic(target=target, source=group_static) 1017 static_objs.extend(partial) 1018 1019 # Set up the shared partially linked objects. 1020 file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial") 1021 target = File(joinpath(group, file_name)) 1022 partial = env.PartialShared(target=target, source=group_shared) 1023 shared_objs.extend(partial) 1024 1025 static_date = date_source.static(new_env) 1026 new_env.Depends(static_date, static_objs) 1027 static_objs.extend(static_date) 1028 1029 shared_date = date_source.shared(new_env) 1030 new_env.Depends(shared_date, shared_objs) 1031 shared_objs.extend(shared_date) 1032 1033 # First make a library of everything but main() so other programs can 1034 # link against m5. 1035 static_lib = new_env.StaticLibrary(libname, static_objs) 1036 shared_lib = new_env.SharedLibrary(libname, shared_objs) 1037 1038 # Now link a stub with main() and the static library. 1039 main_objs = [ s.static(new_env) for s in Source.all.with_tag('main') ] 1040 1041 for test in UnitTest.all: 1042 test_sources = Source.all.with_tag(str(test.target)) 1043 test_objs = [ s.static(new_env) for s in test_sources ] 1044 if test.main: 1045 test_objs += main_objs 1046 path = 'unittest/%s.%s' % (test.target, label) 1047 new_env.Program(path, test_objs + static_objs) 1048 1049 gtest_env = new_env.Clone() 1050 gtest_env.Append(LIBS=gtest_env['GTEST_LIBS']) 1051 gtest_env.Append(CPPFLAGS=gtest_env['GTEST_CPPFLAGS']) 1052 for test in GTest.all: 1053 test_sources = Source.all.with_tag(str(test.target)) 1054 test_objs = [ s.static(gtest_env) for s in test_sources ] 1055 gtest_env.Program(test.dir.File('%s.%s' % (test.target, label)), 1056 test_objs) 1057 1058 progname = exename 1059 if strip: 1060 progname += '.unstripped' 1061 1062 targets = new_env.Program(progname, main_objs + static_objs) 1063 1064 if strip: 1065 if sys.platform == 'sunos5': 1066 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 1067 else: 1068 cmd = 'strip $SOURCE -o $TARGET' 1069 targets = new_env.Command(exename, progname, 1070 MakeAction(cmd, Transform("STRIP"))) 1071 1072 new_env.Command(secondary_exename, exename, 1073 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK"))) 1074 1075 new_env.M5Binary = targets[0] 1076 1077 # Set up regression tests. 1078 SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'), 1079 variant_dir=Dir('tests').Dir(new_env.Label), 1080 exports={ 'env' : new_env }, duplicate=False) 1081 1082# Start out with the compiler flags common to all compilers, 1083# i.e. they all use -g for opt and -g -pg for prof 1084ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'], 1085 'perf' : ['-g']} 1086 1087# Start out with the linker flags common to all linkers, i.e. -pg for 1088# prof, and -lprofiler for perf. The -lprofile flag is surrounded by 1089# no-as-needed and as-needed as the binutils linker is too clever and 1090# simply doesn't link to the library otherwise. 1091ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'], 1092 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']} 1093 1094# For Link Time Optimization, the optimisation flags used to compile 1095# individual files are decoupled from those used at link time 1096# (i.e. you can compile with -O3 and perform LTO with -O0), so we need 1097# to also update the linker flags based on the target. 1098if env['GCC']: 1099 if sys.platform == 'sunos5': 1100 ccflags['debug'] += ['-gstabs+'] 1101 else: 1102 ccflags['debug'] += ['-ggdb3'] 1103 ldflags['debug'] += ['-O0'] 1104 # opt, fast, prof and perf all share the same cc flags, also add 1105 # the optimization to the ldflags as LTO defers the optimization 1106 # to link time 1107 for target in ['opt', 'fast', 'prof', 'perf']: 1108 ccflags[target] += ['-O3'] 1109 ldflags[target] += ['-O3'] 1110 1111 ccflags['fast'] += env['LTO_CCFLAGS'] 1112 ldflags['fast'] += env['LTO_LDFLAGS'] 1113elif env['CLANG']: 1114 ccflags['debug'] += ['-g', '-O0'] 1115 # opt, fast, prof and perf all share the same cc flags 1116 for target in ['opt', 'fast', 'prof', 'perf']: 1117 ccflags[target] += ['-O3'] 1118else: 1119 print 'Unknown compiler, please fix compiler options' 1120 Exit(1) 1121 1122 1123# To speed things up, we only instantiate the build environments we 1124# need. We try to identify the needed environment for each target; if 1125# we can't, we fall back on instantiating all the environments just to 1126# be safe. 1127target_types = ['debug', 'opt', 'fast', 'prof', 'perf'] 1128obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof', 1129 'gpo' : 'perf'} 1130 1131def identifyTarget(t): 1132 ext = t.split('.')[-1] 1133 if ext in target_types: 1134 return ext 1135 if obj2target.has_key(ext): 1136 return obj2target[ext] 1137 match = re.search(r'/tests/([^/]+)/', t) 1138 if match and match.group(1) in target_types: 1139 return match.group(1) 1140 return 'all' 1141 1142needed_envs = [identifyTarget(target) for target in BUILD_TARGETS] 1143if 'all' in needed_envs: 1144 needed_envs += target_types 1145 1146# Debug binary 1147if 'debug' in needed_envs: 1148 makeEnv(env, 'debug', '.do', 1149 CCFLAGS = Split(ccflags['debug']), 1150 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'], 1151 LINKFLAGS = Split(ldflags['debug'])) 1152 1153# Optimized binary 1154if 'opt' in needed_envs: 1155 makeEnv(env, 'opt', '.o', 1156 CCFLAGS = Split(ccflags['opt']), 1157 CPPDEFINES = ['TRACING_ON=1'], 1158 LINKFLAGS = Split(ldflags['opt'])) 1159 1160# "Fast" binary 1161if 'fast' in needed_envs: 1162 disable_partial = \ 1163 env.get('BROKEN_INCREMENTAL_LTO', False) and \ 1164 GetOption('force_lto') 1165 makeEnv(env, 'fast', '.fo', strip = True, 1166 CCFLAGS = Split(ccflags['fast']), 1167 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1168 LINKFLAGS = Split(ldflags['fast']), 1169 disable_partial=disable_partial) 1170 1171# Profiled binary using gprof 1172if 'prof' in needed_envs: 1173 makeEnv(env, 'prof', '.po', 1174 CCFLAGS = Split(ccflags['prof']), 1175 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1176 LINKFLAGS = Split(ldflags['prof'])) 1177 1178# Profiled binary using google-pprof 1179if 'perf' in needed_envs: 1180 makeEnv(env, 'perf', '.gpo', 1181 CCFLAGS = Split(ccflags['perf']), 1182 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1183 LINKFLAGS = Split(ldflags['perf'])) 1184