SConscript revision 13577:70ab75eec40b
16019Shines@cs.fsu.edu# -*- mode:python -*- 26019Shines@cs.fsu.edu 37100Sgblack@eecs.umich.edu# Copyright (c) 2018 ARM Limited 47100Sgblack@eecs.umich.edu# 57100Sgblack@eecs.umich.edu# The license below extends only to copyright in the software and shall 67100Sgblack@eecs.umich.edu# not be construed as granting a license to any other intellectual 77100Sgblack@eecs.umich.edu# property including but not limited to intellectual property relating 87100Sgblack@eecs.umich.edu# to a hardware implementation of the functionality of the software 97100Sgblack@eecs.umich.edu# licensed hereunder. You may use the software subject to the license 107100Sgblack@eecs.umich.edu# terms below provided that you ensure that this notice is replicated 117100Sgblack@eecs.umich.edu# unmodified and in its entirety in all distributions of the software, 127100Sgblack@eecs.umich.edu# modified or unmodified, in source code or in binary form. 137100Sgblack@eecs.umich.edu# 147100Sgblack@eecs.umich.edu# Copyright (c) 2004-2005 The Regents of The University of Michigan 156019Shines@cs.fsu.edu# All rights reserved. 166019Shines@cs.fsu.edu# 176019Shines@cs.fsu.edu# Redistribution and use in source and binary forms, with or without 186019Shines@cs.fsu.edu# modification, are permitted provided that the following conditions are 196019Shines@cs.fsu.edu# met: redistributions of source code must retain the above copyright 206019Shines@cs.fsu.edu# notice, this list of conditions and the following disclaimer; 216019Shines@cs.fsu.edu# redistributions in binary form must reproduce the above copyright 226019Shines@cs.fsu.edu# notice, this list of conditions and the following disclaimer in the 236019Shines@cs.fsu.edu# documentation and/or other materials provided with the distribution; 246019Shines@cs.fsu.edu# neither the name of the copyright holders nor the names of its 256019Shines@cs.fsu.edu# contributors may be used to endorse or promote products derived from 266019Shines@cs.fsu.edu# this software without specific prior written permission. 276019Shines@cs.fsu.edu# 286019Shines@cs.fsu.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 296019Shines@cs.fsu.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 306019Shines@cs.fsu.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 316019Shines@cs.fsu.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 326019Shines@cs.fsu.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 336019Shines@cs.fsu.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 346019Shines@cs.fsu.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 356019Shines@cs.fsu.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 366019Shines@cs.fsu.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 376019Shines@cs.fsu.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 386019Shines@cs.fsu.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 396019Shines@cs.fsu.edu# 406019Shines@cs.fsu.edu# Authors: Nathan Binkert 416019Shines@cs.fsu.edu 426757SAli.Saidi@ARM.comfrom __future__ import print_function 436019Shines@cs.fsu.edu 446019Shines@cs.fsu.eduimport array 456019Shines@cs.fsu.eduimport bisect 466019Shines@cs.fsu.eduimport functools 476019Shines@cs.fsu.eduimport imp 486019Shines@cs.fsu.eduimport marshal 496019Shines@cs.fsu.eduimport os 506019Shines@cs.fsu.eduimport re 517170Sgblack@eecs.umich.eduimport subprocess 526253Sgblack@eecs.umich.eduimport sys 537202Sgblack@eecs.umich.eduimport zlib 546253Sgblack@eecs.umich.edu 556253Sgblack@eecs.umich.edufrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath 567396Sgblack@eecs.umich.edu 578745Sgblack@eecs.umich.eduimport SCons 587405SAli.Saidi@ARM.com 597259Sgblack@eecs.umich.edufrom gem5_scons import Transform 607423Sgblack@eecs.umich.edu 616397Sgblack@eecs.umich.edu# This file defines how to build a particular configuration of gem5 626019Shines@cs.fsu.edu# based on variable settings in the 'env' build environment. 636757SAli.Saidi@ARM.com 647752SWilliam.Wang@arm.comImport('*') 656019Shines@cs.fsu.edu 668745Sgblack@eecs.umich.edu# Children need to see the environment 676397Sgblack@eecs.umich.eduExport('env') 686019Shines@cs.fsu.edu 696397Sgblack@eecs.umich.edubuild_env = [(opt, env[opt]) for opt in export_vars] 708335Snate@binkert.org 718335Snate@binkert.orgfrom m5.util import code_formatter, compareVersions 728335Snate@binkert.org 738335Snate@binkert.org######################################################################## 746019Shines@cs.fsu.edu# Code for adding source files of various types 756757SAli.Saidi@ARM.com# 766757SAli.Saidi@ARM.com# When specifying a source file of some type, a set of tags can be 777694SAli.Saidi@ARM.com# specified for that file. 787585SAli.Saidi@arm.com 797404SAli.Saidi@ARM.comclass SourceFilter(object): 806757SAli.Saidi@ARM.com def __init__(self, predicate): 816757SAli.Saidi@ARM.com self.predicate = predicate 826019Shines@cs.fsu.edu 836019Shines@cs.fsu.edu def __or__(self, other): 846019Shines@cs.fsu.edu return SourceFilter(lambda tags: self.predicate(tags) or 856019Shines@cs.fsu.edu other.predicate(tags)) 866019Shines@cs.fsu.edu 876019Shines@cs.fsu.edu def __and__(self, other): 886019Shines@cs.fsu.edu return SourceFilter(lambda tags: self.predicate(tags) and 896019Shines@cs.fsu.edu other.predicate(tags)) 906019Shines@cs.fsu.edu 916019Shines@cs.fsu.edudef with_tags_that(predicate): 926019Shines@cs.fsu.edu '''Return a list of sources with tags that satisfy a predicate.''' 936019Shines@cs.fsu.edu return SourceFilter(predicate) 94 95def with_any_tags(*tags): 96 '''Return a list of sources with any of the supplied tags.''' 97 return SourceFilter(lambda stags: len(set(tags) & stags) > 0) 98 99def with_all_tags(*tags): 100 '''Return a list of sources with all of the supplied tags.''' 101 return SourceFilter(lambda stags: set(tags) <= stags) 102 103def with_tag(tag): 104 '''Return a list of sources with the supplied tag.''' 105 return SourceFilter(lambda stags: tag in stags) 106 107def without_tags(*tags): 108 '''Return a list of sources without any of the supplied tags.''' 109 return SourceFilter(lambda stags: len(set(tags) & stags) == 0) 110 111def without_tag(tag): 112 '''Return a list of sources with the supplied tag.''' 113 return SourceFilter(lambda stags: tag not in stags) 114 115source_filter_factories = { 116 'with_tags_that': with_tags_that, 117 'with_any_tags': with_any_tags, 118 'with_all_tags': with_all_tags, 119 'with_tag': with_tag, 120 'without_tags': without_tags, 121 'without_tag': without_tag, 122} 123 124Export(source_filter_factories) 125 126class SourceList(list): 127 def apply_filter(self, f): 128 def match(source): 129 return f.predicate(source.tags) 130 return SourceList(filter(match, self)) 131 132 def __getattr__(self, name): 133 func = source_filter_factories.get(name, None) 134 if not func: 135 raise AttributeError 136 137 @functools.wraps(func) 138 def wrapper(*args, **kwargs): 139 return self.apply_filter(func(*args, **kwargs)) 140 return wrapper 141 142class SourceMeta(type): 143 '''Meta class for source files that keeps track of all files of a 144 particular type.''' 145 def __init__(cls, name, bases, dict): 146 super(SourceMeta, cls).__init__(name, bases, dict) 147 cls.all = SourceList() 148 149class SourceFile(object): 150 '''Base object that encapsulates the notion of a source file. 151 This includes, the source node, target node, various manipulations 152 of those. A source file also specifies a set of tags which 153 describing arbitrary properties of the source file.''' 154 __metaclass__ = SourceMeta 155 156 static_objs = {} 157 shared_objs = {} 158 159 def __init__(self, source, tags=None, add_tags=None): 160 if tags is None: 161 tags='gem5 lib' 162 if isinstance(tags, basestring): 163 tags = set([tags]) 164 if not isinstance(tags, set): 165 tags = set(tags) 166 self.tags = tags 167 168 if add_tags: 169 if isinstance(add_tags, basestring): 170 add_tags = set([add_tags]) 171 if not isinstance(add_tags, set): 172 add_tags = set(add_tags) 173 self.tags |= add_tags 174 175 tnode = source 176 if not isinstance(source, SCons.Node.FS.File): 177 tnode = File(source) 178 179 self.tnode = tnode 180 self.snode = tnode.srcnode() 181 182 for base in type(self).__mro__: 183 if issubclass(base, SourceFile): 184 base.all.append(self) 185 186 def static(self, env): 187 key = (self.tnode, env['OBJSUFFIX']) 188 if not key in self.static_objs: 189 self.static_objs[key] = env.StaticObject(self.tnode) 190 return self.static_objs[key] 191 192 def shared(self, env): 193 key = (self.tnode, env['OBJSUFFIX']) 194 if not key in self.shared_objs: 195 self.shared_objs[key] = env.SharedObject(self.tnode) 196 return self.shared_objs[key] 197 198 @property 199 def filename(self): 200 return str(self.tnode) 201 202 @property 203 def dirname(self): 204 return dirname(self.filename) 205 206 @property 207 def basename(self): 208 return basename(self.filename) 209 210 @property 211 def extname(self): 212 index = self.basename.rfind('.') 213 if index <= 0: 214 # dot files aren't extensions 215 return self.basename, None 216 217 return self.basename[:index], self.basename[index+1:] 218 219 def __lt__(self, other): return self.filename < other.filename 220 def __le__(self, other): return self.filename <= other.filename 221 def __gt__(self, other): return self.filename > other.filename 222 def __ge__(self, other): return self.filename >= other.filename 223 def __eq__(self, other): return self.filename == other.filename 224 def __ne__(self, other): return self.filename != other.filename 225 226def blobToCpp(data, symbol, cpp_code, hpp_code=None, namespace=None): 227 ''' 228 Convert bytes data into C++ .cpp and .hh uint8_t byte array 229 code containing that binary data. 230 231 :param data: binary data to be converted to C++ 232 :param symbol: name of the symbol 233 :param cpp_code: append the generated cpp_code to this object 234 :param hpp_code: append the generated hpp_code to this object 235 If None, ignore it. Otherwise, also include it 236 in the .cpp file. 237 :param namespace: namespace to put the symbol into. If None, 238 don't put the symbols into any namespace. 239 ''' 240 symbol_len_declaration = 'const std::size_t {}_len'.format(symbol) 241 symbol_declaration = 'const std::uint8_t {}[]'.format(symbol) 242 if hpp_code is not None: 243 cpp_code('''\ 244#include "blobs/{}.hh" 245'''.format(symbol)) 246 hpp_code('''\ 247#include <cstddef> 248#include <cstdint> 249''') 250 if namespace is not None: 251 hpp_code('namespace {} {{'.format(namespace)) 252 hpp_code('extern ' + symbol_len_declaration + ';') 253 hpp_code('extern ' + symbol_declaration + ';') 254 if namespace is not None: 255 hpp_code('}') 256 if namespace is not None: 257 cpp_code('namespace {} {{'.format(namespace)) 258 cpp_code(symbol_len_declaration + ' = {};'.format(len(data))) 259 cpp_code(symbol_declaration + ' = {') 260 cpp_code.indent() 261 step = 16 262 for i in xrange(0, len(data), step): 263 x = array.array('B', data[i:i+step]) 264 cpp_code(''.join('%d,' % d for d in x)) 265 cpp_code.dedent() 266 cpp_code('};') 267 if namespace is not None: 268 cpp_code('}') 269 270def Blob(blob_path, symbol): 271 ''' 272 Embed an arbitrary blob into the gem5 executable, 273 and make it accessible to C++ as a byte array. 274 ''' 275 blob_path = os.path.abspath(blob_path) 276 blob_out_dir = os.path.join(env['BUILDDIR'], 'blobs') 277 path_noext = joinpath(blob_out_dir, symbol) 278 cpp_path = path_noext + '.cc' 279 hpp_path = path_noext + '.hh' 280 def embedBlob(target, source, env): 281 data = file(str(source[0]), 'r').read() 282 cpp_code = code_formatter() 283 hpp_code = code_formatter() 284 blobToCpp(data, symbol, cpp_code, hpp_code, namespace='Blobs') 285 cpp_path = str(target[0]) 286 hpp_path = str(target[1]) 287 cpp_dir = os.path.split(cpp_path)[0] 288 if not os.path.exists(cpp_dir): 289 os.makedirs(cpp_dir) 290 cpp_code.write(cpp_path) 291 hpp_code.write(hpp_path) 292 env.Command([cpp_path, hpp_path], blob_path, 293 MakeAction(embedBlob, Transform("EMBED BLOB"))) 294 Source(cpp_path) 295 296def GdbXml(xml_id, symbol): 297 Blob(joinpath(gdb_xml_dir, xml_id), symbol) 298 299class Source(SourceFile): 300 ungrouped_tag = 'No link group' 301 source_groups = set() 302 303 _current_group_tag = ungrouped_tag 304 305 @staticmethod 306 def link_group_tag(group): 307 return 'link group: %s' % group 308 309 @classmethod 310 def set_group(cls, group): 311 new_tag = Source.link_group_tag(group) 312 Source._current_group_tag = new_tag 313 Source.source_groups.add(group) 314 315 def _add_link_group_tag(self): 316 self.tags.add(Source._current_group_tag) 317 318 '''Add a c/c++ source file to the build''' 319 def __init__(self, source, tags=None, add_tags=None): 320 '''specify the source file, and any tags''' 321 super(Source, self).__init__(source, tags, add_tags) 322 self._add_link_group_tag() 323 324class PySource(SourceFile): 325 '''Add a python source file to the named package''' 326 invalid_sym_char = re.compile('[^A-z0-9_]') 327 modules = {} 328 tnodes = {} 329 symnames = {} 330 331 def __init__(self, package, source, tags=None, add_tags=None): 332 '''specify the python package, the source file, and any tags''' 333 super(PySource, self).__init__(source, tags, add_tags) 334 335 modname,ext = self.extname 336 assert ext == 'py' 337 338 if package: 339 path = package.split('.') 340 else: 341 path = [] 342 343 modpath = path[:] 344 if modname != '__init__': 345 modpath += [ modname ] 346 modpath = '.'.join(modpath) 347 348 arcpath = path + [ self.basename ] 349 abspath = self.snode.abspath 350 if not exists(abspath): 351 abspath = self.tnode.abspath 352 353 self.package = package 354 self.modname = modname 355 self.modpath = modpath 356 self.arcname = joinpath(*arcpath) 357 self.abspath = abspath 358 self.compiled = File(self.filename + 'c') 359 self.cpp = File(self.filename + '.cc') 360 self.symname = PySource.invalid_sym_char.sub('_', modpath) 361 362 PySource.modules[modpath] = self 363 PySource.tnodes[self.tnode] = self 364 PySource.symnames[self.symname] = self 365 366class SimObject(PySource): 367 '''Add a SimObject python file as a python source object and add 368 it to a list of sim object modules''' 369 370 fixed = False 371 modnames = [] 372 373 def __init__(self, source, tags=None, add_tags=None): 374 '''Specify the source file and any tags (automatically in 375 the m5.objects package)''' 376 super(SimObject, self).__init__('m5.objects', source, tags, add_tags) 377 if self.fixed: 378 raise AttributeError, "Too late to call SimObject now." 379 380 bisect.insort_right(SimObject.modnames, self.modname) 381 382class ProtoBuf(SourceFile): 383 '''Add a Protocol Buffer to build''' 384 385 def __init__(self, source, tags=None, add_tags=None): 386 '''Specify the source file, and any tags''' 387 super(ProtoBuf, self).__init__(source, tags, add_tags) 388 389 # Get the file name and the extension 390 modname,ext = self.extname 391 assert ext == 'proto' 392 393 # Currently, we stick to generating the C++ headers, so we 394 # only need to track the source and header. 395 self.cc_file = File(modname + '.pb.cc') 396 self.hh_file = File(modname + '.pb.h') 397 398 399exectuable_classes = [] 400class ExecutableMeta(type): 401 '''Meta class for Executables.''' 402 all = [] 403 404 def __init__(cls, name, bases, d): 405 if not d.pop('abstract', False): 406 ExecutableMeta.all.append(cls) 407 super(ExecutableMeta, cls).__init__(name, bases, d) 408 409 cls.all = [] 410 411class Executable(object): 412 '''Base class for creating an executable from sources.''' 413 __metaclass__ = ExecutableMeta 414 415 abstract = True 416 417 def __init__(self, target, *srcs_and_filts): 418 '''Specify the target name and any sources. Sources that are 419 not SourceFiles are evalued with Source().''' 420 super(Executable, self).__init__() 421 self.all.append(self) 422 self.target = target 423 424 isFilter = lambda arg: isinstance(arg, SourceFilter) 425 self.filters = filter(isFilter, srcs_and_filts) 426 sources = filter(lambda a: not isFilter(a), srcs_and_filts) 427 428 srcs = SourceList() 429 for src in sources: 430 if not isinstance(src, SourceFile): 431 src = Source(src, tags=[]) 432 srcs.append(src) 433 434 self.sources = srcs 435 self.dir = Dir('.') 436 437 def path(self, env): 438 return self.dir.File(self.target + '.' + env['EXE_SUFFIX']) 439 440 def srcs_to_objs(self, env, sources): 441 return list([ s.static(env) for s in sources ]) 442 443 @classmethod 444 def declare_all(cls, env): 445 return list([ instance.declare(env) for instance in cls.all ]) 446 447 def declare(self, env, objs=None): 448 if objs is None: 449 objs = self.srcs_to_objs(env, self.sources) 450 451 if env['STRIP_EXES']: 452 stripped = self.path(env) 453 unstripped = env.File(str(stripped) + '.unstripped') 454 if sys.platform == 'sunos5': 455 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 456 else: 457 cmd = 'strip $SOURCE -o $TARGET' 458 env.Program(unstripped, objs) 459 return env.Command(stripped, unstripped, 460 MakeAction(cmd, Transform("STRIP"))) 461 else: 462 return env.Program(self.path(env), objs) 463 464class UnitTest(Executable): 465 '''Create a UnitTest''' 466 def __init__(self, target, *srcs_and_filts, **kwargs): 467 super(UnitTest, self).__init__(target, *srcs_and_filts) 468 469 self.main = kwargs.get('main', False) 470 471 def declare(self, env): 472 sources = list(self.sources) 473 for f in self.filters: 474 sources = Source.all.apply_filter(f) 475 objs = self.srcs_to_objs(env, sources) + env['STATIC_OBJS'] 476 if self.main: 477 objs += env['MAIN_OBJS'] 478 return super(UnitTest, self).declare(env, objs) 479 480class GTest(Executable): 481 '''Create a unit test based on the google test framework.''' 482 all = [] 483 def __init__(self, *srcs_and_filts, **kwargs): 484 super(GTest, self).__init__(*srcs_and_filts) 485 486 self.skip_lib = kwargs.pop('skip_lib', False) 487 488 @classmethod 489 def declare_all(cls, env): 490 env = env.Clone() 491 env.Append(LIBS=env['GTEST_LIBS']) 492 env.Append(CPPFLAGS=env['GTEST_CPPFLAGS']) 493 env['GTEST_LIB_SOURCES'] = Source.all.with_tag('gtest lib') 494 env['GTEST_OUT_DIR'] = \ 495 Dir(env['BUILDDIR']).Dir('unittests.' + env['EXE_SUFFIX']) 496 return super(GTest, cls).declare_all(env) 497 498 def declare(self, env): 499 sources = list(self.sources) 500 if not self.skip_lib: 501 sources += env['GTEST_LIB_SOURCES'] 502 for f in self.filters: 503 sources += Source.all.apply_filter(f) 504 objs = self.srcs_to_objs(env, sources) 505 506 binary = super(GTest, self).declare(env, objs) 507 508 out_dir = env['GTEST_OUT_DIR'] 509 xml_file = out_dir.Dir(str(self.dir)).File(self.target + '.xml') 510 AlwaysBuild(env.Command(xml_file, binary, 511 "${SOURCES[0]} --gtest_output=xml:${TARGETS[0]}")) 512 513 return binary 514 515class Gem5(Executable): 516 '''Create a gem5 executable.''' 517 518 def __init__(self, target): 519 super(Gem5, self).__init__(target) 520 521 def declare(self, env): 522 objs = env['MAIN_OBJS'] + env['STATIC_OBJS'] 523 return super(Gem5, self).declare(env, objs) 524 525 526# Children should have access 527Export('Blob') 528Export('GdbXml') 529Export('Source') 530Export('PySource') 531Export('SimObject') 532Export('ProtoBuf') 533Export('Executable') 534Export('UnitTest') 535Export('GTest') 536 537######################################################################## 538# 539# Debug Flags 540# 541debug_flags = {} 542def DebugFlag(name, desc=None): 543 if name in debug_flags: 544 raise AttributeError, "Flag %s already specified" % name 545 debug_flags[name] = (name, (), desc) 546 547def CompoundFlag(name, flags, desc=None): 548 if name in debug_flags: 549 raise AttributeError, "Flag %s already specified" % name 550 551 compound = tuple(flags) 552 debug_flags[name] = (name, compound, desc) 553 554Export('DebugFlag') 555Export('CompoundFlag') 556 557######################################################################## 558# 559# Set some compiler variables 560# 561 562# Include file paths are rooted in this directory. SCons will 563# automatically expand '.' to refer to both the source directory and 564# the corresponding build directory to pick up generated include 565# files. 566env.Append(CPPPATH=Dir('.')) 567 568for extra_dir in extras_dir_list: 569 env.Append(CPPPATH=Dir(extra_dir)) 570 571# Workaround for bug in SCons version > 0.97d20071212 572# Scons bug id: 2006 gem5 Bug id: 308 573for root, dirs, files in os.walk(base_dir, topdown=True): 574 Dir(root[len(base_dir) + 1:]) 575 576######################################################################## 577# 578# Walk the tree and execute all SConscripts in subdirectories 579# 580 581here = Dir('.').srcnode().abspath 582for root, dirs, files in os.walk(base_dir, topdown=True): 583 if root == here: 584 # we don't want to recurse back into this SConscript 585 continue 586 587 if 'SConscript' in files: 588 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 589 Source.set_group(build_dir) 590 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 591 592for extra_dir in extras_dir_list: 593 prefix_len = len(dirname(extra_dir)) + 1 594 595 # Also add the corresponding build directory to pick up generated 596 # include files. 597 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:]))) 598 599 for root, dirs, files in os.walk(extra_dir, topdown=True): 600 # if build lives in the extras directory, don't walk down it 601 if 'build' in dirs: 602 dirs.remove('build') 603 604 if 'SConscript' in files: 605 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 606 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 607 608for opt in export_vars: 609 env.ConfigFile(opt) 610 611def makeTheISA(source, target, env): 612 isas = [ src.get_contents() for src in source ] 613 target_isa = env['TARGET_ISA'] 614 def define(isa): 615 return isa.upper() + '_ISA' 616 617 def namespace(isa): 618 return isa[0].upper() + isa[1:].lower() + 'ISA' 619 620 621 code = code_formatter() 622 code('''\ 623#ifndef __CONFIG_THE_ISA_HH__ 624#define __CONFIG_THE_ISA_HH__ 625 626''') 627 628 # create defines for the preprocessing and compile-time determination 629 for i,isa in enumerate(isas): 630 code('#define $0 $1', define(isa), i + 1) 631 code() 632 633 # create an enum for any run-time determination of the ISA, we 634 # reuse the same name as the namespaces 635 code('enum class Arch {') 636 for i,isa in enumerate(isas): 637 if i + 1 == len(isas): 638 code(' $0 = $1', namespace(isa), define(isa)) 639 else: 640 code(' $0 = $1,', namespace(isa), define(isa)) 641 code('};') 642 643 code(''' 644 645#define THE_ISA ${{define(target_isa)}} 646#define TheISA ${{namespace(target_isa)}} 647#define THE_ISA_STR "${{target_isa}}" 648 649#endif // __CONFIG_THE_ISA_HH__''') 650 651 code.write(str(target[0])) 652 653env.Command('config/the_isa.hh', map(Value, all_isa_list), 654 MakeAction(makeTheISA, Transform("CFG ISA", 0))) 655 656def makeTheGPUISA(source, target, env): 657 isas = [ src.get_contents() for src in source ] 658 target_gpu_isa = env['TARGET_GPU_ISA'] 659 def define(isa): 660 return isa.upper() + '_ISA' 661 662 def namespace(isa): 663 return isa[0].upper() + isa[1:].lower() + 'ISA' 664 665 666 code = code_formatter() 667 code('''\ 668#ifndef __CONFIG_THE_GPU_ISA_HH__ 669#define __CONFIG_THE_GPU_ISA_HH__ 670 671''') 672 673 # create defines for the preprocessing and compile-time determination 674 for i,isa in enumerate(isas): 675 code('#define $0 $1', define(isa), i + 1) 676 code() 677 678 # create an enum for any run-time determination of the ISA, we 679 # reuse the same name as the namespaces 680 code('enum class GPUArch {') 681 for i,isa in enumerate(isas): 682 if i + 1 == len(isas): 683 code(' $0 = $1', namespace(isa), define(isa)) 684 else: 685 code(' $0 = $1,', namespace(isa), define(isa)) 686 code('};') 687 688 code(''' 689 690#define THE_GPU_ISA ${{define(target_gpu_isa)}} 691#define TheGpuISA ${{namespace(target_gpu_isa)}} 692#define THE_GPU_ISA_STR "${{target_gpu_isa}}" 693 694#endif // __CONFIG_THE_GPU_ISA_HH__''') 695 696 code.write(str(target[0])) 697 698env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list), 699 MakeAction(makeTheGPUISA, Transform("CFG ISA", 0))) 700 701######################################################################## 702# 703# Prevent any SimObjects from being added after this point, they 704# should all have been added in the SConscripts above 705# 706SimObject.fixed = True 707 708class DictImporter(object): 709 '''This importer takes a dictionary of arbitrary module names that 710 map to arbitrary filenames.''' 711 def __init__(self, modules): 712 self.modules = modules 713 self.installed = set() 714 715 def __del__(self): 716 self.unload() 717 718 def unload(self): 719 import sys 720 for module in self.installed: 721 del sys.modules[module] 722 self.installed = set() 723 724 def find_module(self, fullname, path): 725 if fullname == 'm5.defines': 726 return self 727 728 if fullname == 'm5.objects': 729 return self 730 731 if fullname.startswith('_m5'): 732 return None 733 734 source = self.modules.get(fullname, None) 735 if source is not None and fullname.startswith('m5.objects'): 736 return self 737 738 return None 739 740 def load_module(self, fullname): 741 mod = imp.new_module(fullname) 742 sys.modules[fullname] = mod 743 self.installed.add(fullname) 744 745 mod.__loader__ = self 746 if fullname == 'm5.objects': 747 mod.__path__ = fullname.split('.') 748 return mod 749 750 if fullname == 'm5.defines': 751 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 752 return mod 753 754 source = self.modules[fullname] 755 if source.modname == '__init__': 756 mod.__path__ = source.modpath 757 mod.__file__ = source.abspath 758 759 exec file(source.abspath, 'r') in mod.__dict__ 760 761 return mod 762 763import m5.SimObject 764import m5.params 765from m5.util import code_formatter 766 767m5.SimObject.clear() 768m5.params.clear() 769 770# install the python importer so we can grab stuff from the source 771# tree itself. We can't have SimObjects added after this point or 772# else we won't know about them for the rest of the stuff. 773importer = DictImporter(PySource.modules) 774sys.meta_path[0:0] = [ importer ] 775 776# import all sim objects so we can populate the all_objects list 777# make sure that we're working with a list, then let's sort it 778for modname in SimObject.modnames: 779 exec('from m5.objects import %s' % modname) 780 781# we need to unload all of the currently imported modules so that they 782# will be re-imported the next time the sconscript is run 783importer.unload() 784sys.meta_path.remove(importer) 785 786sim_objects = m5.SimObject.allClasses 787all_enums = m5.params.allEnums 788 789for name,obj in sorted(sim_objects.iteritems()): 790 for param in obj._params.local.values(): 791 # load the ptype attribute now because it depends on the 792 # current version of SimObject.allClasses, but when scons 793 # actually uses the value, all versions of 794 # SimObject.allClasses will have been loaded 795 param.ptype 796 797######################################################################## 798# 799# calculate extra dependencies 800# 801module_depends = ["m5", "m5.SimObject", "m5.params"] 802depends = [ PySource.modules[dep].snode for dep in module_depends ] 803depends.sort(key = lambda x: x.name) 804 805######################################################################## 806# 807# Commands for the basic automatically generated python files 808# 809 810# Generate Python file containing a dict specifying the current 811# buildEnv flags. 812def makeDefinesPyFile(target, source, env): 813 build_env = source[0].get_contents() 814 815 code = code_formatter() 816 code(""" 817import _m5.core 818import m5.util 819 820buildEnv = m5.util.SmartDict($build_env) 821 822compileDate = _m5.core.compileDate 823_globals = globals() 824for key,val in _m5.core.__dict__.iteritems(): 825 if key.startswith('flag_'): 826 flag = key[5:] 827 _globals[flag] = val 828del _globals 829""") 830 code.write(target[0].abspath) 831 832defines_info = Value(build_env) 833# Generate a file with all of the compile options in it 834env.Command('python/m5/defines.py', defines_info, 835 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 836PySource('m5', 'python/m5/defines.py') 837 838# Generate python file containing info about the M5 source code 839def makeInfoPyFile(target, source, env): 840 code = code_formatter() 841 for src in source: 842 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 843 code('$src = ${{repr(data)}}') 844 code.write(str(target[0])) 845 846# Generate a file that wraps the basic top level files 847env.Command('python/m5/info.py', 848 [ '#/COPYING', '#/LICENSE', '#/README', ], 849 MakeAction(makeInfoPyFile, Transform("INFO"))) 850PySource('m5', 'python/m5/info.py') 851 852######################################################################## 853# 854# Create all of the SimObject param headers and enum headers 855# 856 857def createSimObjectParamStruct(target, source, env): 858 assert len(target) == 1 and len(source) == 1 859 860 name = source[0].get_text_contents() 861 obj = sim_objects[name] 862 863 code = code_formatter() 864 obj.cxx_param_decl(code) 865 code.write(target[0].abspath) 866 867def createSimObjectCxxConfig(is_header): 868 def body(target, source, env): 869 assert len(target) == 1 and len(source) == 1 870 871 name = str(source[0].get_contents()) 872 obj = sim_objects[name] 873 874 code = code_formatter() 875 obj.cxx_config_param_file(code, is_header) 876 code.write(target[0].abspath) 877 return body 878 879def createEnumStrings(target, source, env): 880 assert len(target) == 1 and len(source) == 2 881 882 name = source[0].get_text_contents() 883 use_python = source[1].read() 884 obj = all_enums[name] 885 886 code = code_formatter() 887 obj.cxx_def(code) 888 if use_python: 889 obj.pybind_def(code) 890 code.write(target[0].abspath) 891 892def createEnumDecls(target, source, env): 893 assert len(target) == 1 and len(source) == 1 894 895 name = source[0].get_text_contents() 896 obj = all_enums[name] 897 898 code = code_formatter() 899 obj.cxx_decl(code) 900 code.write(target[0].abspath) 901 902def createSimObjectPyBindWrapper(target, source, env): 903 name = source[0].get_text_contents() 904 obj = sim_objects[name] 905 906 code = code_formatter() 907 obj.pybind_decl(code) 908 code.write(target[0].abspath) 909 910# Generate all of the SimObject param C++ struct header files 911params_hh_files = [] 912for name,simobj in sorted(sim_objects.iteritems()): 913 py_source = PySource.modules[simobj.__module__] 914 extra_deps = [ py_source.tnode ] 915 916 hh_file = File('params/%s.hh' % name) 917 params_hh_files.append(hh_file) 918 env.Command(hh_file, Value(name), 919 MakeAction(createSimObjectParamStruct, Transform("SO PARAM"))) 920 env.Depends(hh_file, depends + extra_deps) 921 922# C++ parameter description files 923if GetOption('with_cxx_config'): 924 for name,simobj in sorted(sim_objects.iteritems()): 925 py_source = PySource.modules[simobj.__module__] 926 extra_deps = [ py_source.tnode ] 927 928 cxx_config_hh_file = File('cxx_config/%s.hh' % name) 929 cxx_config_cc_file = File('cxx_config/%s.cc' % name) 930 env.Command(cxx_config_hh_file, Value(name), 931 MakeAction(createSimObjectCxxConfig(True), 932 Transform("CXXCPRHH"))) 933 env.Command(cxx_config_cc_file, Value(name), 934 MakeAction(createSimObjectCxxConfig(False), 935 Transform("CXXCPRCC"))) 936 env.Depends(cxx_config_hh_file, depends + extra_deps + 937 [File('params/%s.hh' % name), File('sim/cxx_config.hh')]) 938 env.Depends(cxx_config_cc_file, depends + extra_deps + 939 [cxx_config_hh_file]) 940 Source(cxx_config_cc_file) 941 942 cxx_config_init_cc_file = File('cxx_config/init.cc') 943 944 def createCxxConfigInitCC(target, source, env): 945 assert len(target) == 1 and len(source) == 1 946 947 code = code_formatter() 948 949 for name,simobj in sorted(sim_objects.iteritems()): 950 if not hasattr(simobj, 'abstract') or not simobj.abstract: 951 code('#include "cxx_config/${name}.hh"') 952 code() 953 code('void cxxConfigInit()') 954 code('{') 955 code.indent() 956 for name,simobj in sorted(sim_objects.iteritems()): 957 not_abstract = not hasattr(simobj, 'abstract') or \ 958 not simobj.abstract 959 if not_abstract and 'type' in simobj.__dict__: 960 code('cxx_config_directory["${name}"] = ' 961 '${name}CxxConfigParams::makeDirectoryEntry();') 962 code.dedent() 963 code('}') 964 code.write(target[0].abspath) 965 966 py_source = PySource.modules[simobj.__module__] 967 extra_deps = [ py_source.tnode ] 968 env.Command(cxx_config_init_cc_file, Value(name), 969 MakeAction(createCxxConfigInitCC, Transform("CXXCINIT"))) 970 cxx_param_hh_files = ["cxx_config/%s.hh" % simobj 971 for name,simobj in sorted(sim_objects.iteritems()) 972 if not hasattr(simobj, 'abstract') or not simobj.abstract] 973 Depends(cxx_config_init_cc_file, cxx_param_hh_files + 974 [File('sim/cxx_config.hh')]) 975 Source(cxx_config_init_cc_file) 976 977# Generate all enum header files 978for name,enum in sorted(all_enums.iteritems()): 979 py_source = PySource.modules[enum.__module__] 980 extra_deps = [ py_source.tnode ] 981 982 cc_file = File('enums/%s.cc' % name) 983 env.Command(cc_file, [Value(name), Value(env['USE_PYTHON'])], 984 MakeAction(createEnumStrings, Transform("ENUM STR"))) 985 env.Depends(cc_file, depends + extra_deps) 986 Source(cc_file) 987 988 hh_file = File('enums/%s.hh' % name) 989 env.Command(hh_file, Value(name), 990 MakeAction(createEnumDecls, Transform("ENUMDECL"))) 991 env.Depends(hh_file, depends + extra_deps) 992 993# Generate SimObject Python bindings wrapper files 994if env['USE_PYTHON']: 995 for name,simobj in sorted(sim_objects.iteritems()): 996 py_source = PySource.modules[simobj.__module__] 997 extra_deps = [ py_source.tnode ] 998 cc_file = File('python/_m5/param_%s.cc' % name) 999 env.Command(cc_file, Value(name), 1000 MakeAction(createSimObjectPyBindWrapper, 1001 Transform("SO PyBind"))) 1002 env.Depends(cc_file, depends + extra_deps) 1003 Source(cc_file) 1004 1005# Build all protocol buffers if we have got protoc and protobuf available 1006if env['HAVE_PROTOBUF']: 1007 for proto in ProtoBuf.all: 1008 # Use both the source and header as the target, and the .proto 1009 # file as the source. When executing the protoc compiler, also 1010 # specify the proto_path to avoid having the generated files 1011 # include the path. 1012 env.Command([proto.cc_file, proto.hh_file], proto.tnode, 1013 MakeAction('$PROTOC --cpp_out ${TARGET.dir} ' 1014 '--proto_path ${SOURCE.dir} $SOURCE', 1015 Transform("PROTOC"))) 1016 1017 # Add the C++ source file 1018 Source(proto.cc_file, tags=proto.tags) 1019elif ProtoBuf.all: 1020 print('Got protobuf to build, but lacks support!') 1021 Exit(1) 1022 1023# 1024# Handle debug flags 1025# 1026def makeDebugFlagCC(target, source, env): 1027 assert(len(target) == 1 and len(source) == 1) 1028 1029 code = code_formatter() 1030 1031 # delay definition of CompoundFlags until after all the definition 1032 # of all constituent SimpleFlags 1033 comp_code = code_formatter() 1034 1035 # file header 1036 code(''' 1037/* 1038 * DO NOT EDIT THIS FILE! Automatically generated by SCons. 1039 */ 1040 1041#include "base/debug.hh" 1042 1043namespace Debug { 1044 1045''') 1046 1047 for name, flag in sorted(source[0].read().iteritems()): 1048 n, compound, desc = flag 1049 assert n == name 1050 1051 if not compound: 1052 code('SimpleFlag $name("$name", "$desc");') 1053 else: 1054 comp_code('CompoundFlag $name("$name", "$desc",') 1055 comp_code.indent() 1056 last = len(compound) - 1 1057 for i,flag in enumerate(compound): 1058 if i != last: 1059 comp_code('&$flag,') 1060 else: 1061 comp_code('&$flag);') 1062 comp_code.dedent() 1063 1064 code.append(comp_code) 1065 code() 1066 code('} // namespace Debug') 1067 1068 code.write(str(target[0])) 1069 1070def makeDebugFlagHH(target, source, env): 1071 assert(len(target) == 1 and len(source) == 1) 1072 1073 val = eval(source[0].get_contents()) 1074 name, compound, desc = val 1075 1076 code = code_formatter() 1077 1078 # file header boilerplate 1079 code('''\ 1080/* 1081 * DO NOT EDIT THIS FILE! Automatically generated by SCons. 1082 */ 1083 1084#ifndef __DEBUG_${name}_HH__ 1085#define __DEBUG_${name}_HH__ 1086 1087namespace Debug { 1088''') 1089 1090 if compound: 1091 code('class CompoundFlag;') 1092 code('class SimpleFlag;') 1093 1094 if compound: 1095 code('extern CompoundFlag $name;') 1096 for flag in compound: 1097 code('extern SimpleFlag $flag;') 1098 else: 1099 code('extern SimpleFlag $name;') 1100 1101 code(''' 1102} 1103 1104#endif // __DEBUG_${name}_HH__ 1105''') 1106 1107 code.write(str(target[0])) 1108 1109for name,flag in sorted(debug_flags.iteritems()): 1110 n, compound, desc = flag 1111 assert n == name 1112 1113 hh_file = 'debug/%s.hh' % name 1114 env.Command(hh_file, Value(flag), 1115 MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) 1116 1117env.Command('debug/flags.cc', Value(debug_flags), 1118 MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) 1119Source('debug/flags.cc') 1120 1121# version tags 1122tags = \ 1123env.Command('sim/tags.cc', None, 1124 MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET', 1125 Transform("VER TAGS"))) 1126env.AlwaysBuild(tags) 1127 1128# Embed python files. All .py files that have been indicated by a 1129# PySource() call in a SConscript need to be embedded into the M5 1130# library. To do that, we compile the file to byte code, marshal the 1131# byte code, compress it, and then generate a c++ file that 1132# inserts the result into an array. 1133def embedPyFile(target, source, env): 1134 def c_str(string): 1135 if string is None: 1136 return "0" 1137 return '"%s"' % string 1138 1139 '''Action function to compile a .py into a code object, marshal 1140 it, compress it, and stick it into an asm file so the code appears 1141 as just bytes with a label in the data section''' 1142 1143 src = file(str(source[0]), 'r').read() 1144 1145 pysource = PySource.tnodes[source[0]] 1146 compiled = compile(src, pysource.abspath, 'exec') 1147 marshalled = marshal.dumps(compiled) 1148 compressed = zlib.compress(marshalled) 1149 data = compressed 1150 sym = pysource.symname 1151 1152 code = code_formatter() 1153 code('''\ 1154#include "sim/init.hh" 1155 1156namespace { 1157 1158''') 1159 blobToCpp(data, 'data_' + sym, code) 1160 code('''\ 1161 1162 1163EmbeddedPython embedded_${sym}( 1164 ${{c_str(pysource.arcname)}}, 1165 ${{c_str(pysource.abspath)}}, 1166 ${{c_str(pysource.modpath)}}, 1167 data_${sym}, 1168 ${{len(data)}}, 1169 ${{len(marshalled)}}); 1170 1171} // anonymous namespace 1172''') 1173 code.write(str(target[0])) 1174 1175for source in PySource.all: 1176 env.Command(source.cpp, source.tnode, 1177 MakeAction(embedPyFile, Transform("EMBED PY"))) 1178 Source(source.cpp, tags=source.tags, add_tags='python') 1179 1180######################################################################## 1181# 1182# Define binaries. Each different build type (debug, opt, etc.) gets 1183# a slightly different build environment. 1184# 1185 1186# List of constructed environments to pass back to SConstruct 1187date_source = Source('base/date.cc', tags=[]) 1188 1189gem5_binary = Gem5('gem5') 1190 1191# Function to create a new build environment as clone of current 1192# environment 'env' with modified object suffix and optional stripped 1193# binary. Additional keyword arguments are appended to corresponding 1194# build environment vars. 1195def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs): 1196 # SCons doesn't know to append a library suffix when there is a '.' in the 1197 # name. Use '_' instead. 1198 libname = 'gem5_' + label 1199 secondary_exename = 'm5.' + label 1200 1201 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 1202 new_env.Label = label 1203 new_env.Append(**kwargs) 1204 1205 lib_sources = Source.all.with_tag('gem5 lib') 1206 1207 # Without Python, leave out all Python content from the library 1208 # builds. The option doesn't affect gem5 built as a program 1209 if GetOption('without_python'): 1210 lib_sources = lib_sources.without_tag('python') 1211 1212 static_objs = [] 1213 shared_objs = [] 1214 1215 for s in lib_sources.with_tag(Source.ungrouped_tag): 1216 static_objs.append(s.static(new_env)) 1217 shared_objs.append(s.shared(new_env)) 1218 1219 for group in Source.source_groups: 1220 srcs = lib_sources.with_tag(Source.link_group_tag(group)) 1221 if not srcs: 1222 continue 1223 1224 group_static = [ s.static(new_env) for s in srcs ] 1225 group_shared = [ s.shared(new_env) for s in srcs ] 1226 1227 # If partial linking is disabled, add these sources to the build 1228 # directly, and short circuit this loop. 1229 if disable_partial: 1230 static_objs.extend(group_static) 1231 shared_objs.extend(group_shared) 1232 continue 1233 1234 # Set up the static partially linked objects. 1235 file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial") 1236 target = File(joinpath(group, file_name)) 1237 partial = env.PartialStatic(target=target, source=group_static) 1238 static_objs.extend(partial) 1239 1240 # Set up the shared partially linked objects. 1241 file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial") 1242 target = File(joinpath(group, file_name)) 1243 partial = env.PartialShared(target=target, source=group_shared) 1244 shared_objs.extend(partial) 1245 1246 static_date = date_source.static(new_env) 1247 new_env.Depends(static_date, static_objs) 1248 static_objs.extend(static_date) 1249 1250 shared_date = date_source.shared(new_env) 1251 new_env.Depends(shared_date, shared_objs) 1252 shared_objs.extend(shared_date) 1253 1254 main_objs = [ s.static(new_env) for s in Source.all.with_tag('main') ] 1255 1256 # First make a library of everything but main() so other programs can 1257 # link against m5. 1258 static_lib = new_env.StaticLibrary(libname, static_objs) 1259 shared_lib = new_env.SharedLibrary(libname, shared_objs) 1260 1261 # Keep track of the object files generated so far so Executables can 1262 # include them. 1263 new_env['STATIC_OBJS'] = static_objs 1264 new_env['SHARED_OBJS'] = shared_objs 1265 new_env['MAIN_OBJS'] = main_objs 1266 1267 new_env['STATIC_LIB'] = static_lib 1268 new_env['SHARED_LIB'] = shared_lib 1269 1270 # Record some settings for building Executables. 1271 new_env['EXE_SUFFIX'] = label 1272 new_env['STRIP_EXES'] = strip 1273 1274 for cls in ExecutableMeta.all: 1275 cls.declare_all(new_env) 1276 1277 new_env.M5Binary = File(gem5_binary.path(new_env)) 1278 1279 new_env.Command(secondary_exename, new_env.M5Binary, 1280 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK"))) 1281 1282 # Set up regression tests. 1283 SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'), 1284 variant_dir=Dir('tests').Dir(new_env.Label), 1285 exports={ 'env' : new_env }, duplicate=False) 1286 1287# Start out with the compiler flags common to all compilers, 1288# i.e. they all use -g for opt and -g -pg for prof 1289ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'], 1290 'perf' : ['-g']} 1291 1292# Start out with the linker flags common to all linkers, i.e. -pg for 1293# prof, and -lprofiler for perf. The -lprofile flag is surrounded by 1294# no-as-needed and as-needed as the binutils linker is too clever and 1295# simply doesn't link to the library otherwise. 1296ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'], 1297 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']} 1298 1299# For Link Time Optimization, the optimisation flags used to compile 1300# individual files are decoupled from those used at link time 1301# (i.e. you can compile with -O3 and perform LTO with -O0), so we need 1302# to also update the linker flags based on the target. 1303if env['GCC']: 1304 if sys.platform == 'sunos5': 1305 ccflags['debug'] += ['-gstabs+'] 1306 else: 1307 ccflags['debug'] += ['-ggdb3'] 1308 ldflags['debug'] += ['-O0'] 1309 # opt, fast, prof and perf all share the same cc flags, also add 1310 # the optimization to the ldflags as LTO defers the optimization 1311 # to link time 1312 for target in ['opt', 'fast', 'prof', 'perf']: 1313 ccflags[target] += ['-O3'] 1314 ldflags[target] += ['-O3'] 1315 1316 ccflags['fast'] += env['LTO_CCFLAGS'] 1317 ldflags['fast'] += env['LTO_LDFLAGS'] 1318elif env['CLANG']: 1319 ccflags['debug'] += ['-g', '-O0'] 1320 # opt, fast, prof and perf all share the same cc flags 1321 for target in ['opt', 'fast', 'prof', 'perf']: 1322 ccflags[target] += ['-O3'] 1323else: 1324 print('Unknown compiler, please fix compiler options') 1325 Exit(1) 1326 1327 1328# To speed things up, we only instantiate the build environments we 1329# need. We try to identify the needed environment for each target; if 1330# we can't, we fall back on instantiating all the environments just to 1331# be safe. 1332target_types = ['debug', 'opt', 'fast', 'prof', 'perf'] 1333obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof', 1334 'gpo' : 'perf'} 1335 1336def identifyTarget(t): 1337 ext = t.split('.')[-1] 1338 if ext in target_types: 1339 return ext 1340 if obj2target.has_key(ext): 1341 return obj2target[ext] 1342 match = re.search(r'/tests/([^/]+)/', t) 1343 if match and match.group(1) in target_types: 1344 return match.group(1) 1345 return 'all' 1346 1347needed_envs = [identifyTarget(target) for target in BUILD_TARGETS] 1348if 'all' in needed_envs: 1349 needed_envs += target_types 1350 1351disable_partial = False 1352if env['PLATFORM'] == 'darwin': 1353 # Up until Apple LLVM version 10.0.0 (clang-1000.11.45.5), partial 1354 # linked objects do not expose symbols that are marked with the 1355 # hidden visibility and consequently building gem5 on Mac OS 1356 # fails. As a workaround, we disable partial linking, however, we 1357 # may want to revisit in the future. 1358 disable_partial = True 1359 1360# Debug binary 1361if 'debug' in needed_envs: 1362 makeEnv(env, 'debug', '.do', 1363 CCFLAGS = Split(ccflags['debug']), 1364 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'], 1365 LINKFLAGS = Split(ldflags['debug']), 1366 disable_partial=disable_partial) 1367 1368# Optimized binary 1369if 'opt' in needed_envs: 1370 makeEnv(env, 'opt', '.o', 1371 CCFLAGS = Split(ccflags['opt']), 1372 CPPDEFINES = ['TRACING_ON=1'], 1373 LINKFLAGS = Split(ldflags['opt']), 1374 disable_partial=disable_partial) 1375 1376# "Fast" binary 1377if 'fast' in needed_envs: 1378 disable_partial = disable_partial and \ 1379 env.get('BROKEN_INCREMENTAL_LTO', False) and \ 1380 GetOption('force_lto') 1381 makeEnv(env, 'fast', '.fo', strip = True, 1382 CCFLAGS = Split(ccflags['fast']), 1383 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1384 LINKFLAGS = Split(ldflags['fast']), 1385 disable_partial=disable_partial) 1386 1387# Profiled binary using gprof 1388if 'prof' in needed_envs: 1389 makeEnv(env, 'prof', '.po', 1390 CCFLAGS = Split(ccflags['prof']), 1391 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1392 LINKFLAGS = Split(ldflags['prof']), 1393 disable_partial=disable_partial) 1394 1395# Profiled binary using google-pprof 1396if 'perf' in needed_envs: 1397 makeEnv(env, 'perf', '.gpo', 1398 CCFLAGS = Split(ccflags['perf']), 1399 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 1400 LINKFLAGS = Split(ldflags['perf']), 1401 disable_partial=disable_partial) 1402