SConscript revision 8334:483e936f44f0
13520Sgblack@eecs.umich.edu# -*- mode:python -*- 23520Sgblack@eecs.umich.edu 33520Sgblack@eecs.umich.edu# Copyright (c) 2004-2005 The Regents of The University of Michigan 43520Sgblack@eecs.umich.edu# All rights reserved. 53520Sgblack@eecs.umich.edu# 63520Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 73520Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are 83520Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright 93520Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 103520Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 113520Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 123520Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution; 133520Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its 143520Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from 153520Sgblack@eecs.umich.edu# this software without specific prior written permission. 163520Sgblack@eecs.umich.edu# 173520Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 183520Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 193520Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 203520Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 213520Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 223520Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 233520Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 243520Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 253520Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 263520Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 273520Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 283520Sgblack@eecs.umich.edu# 293520Sgblack@eecs.umich.edu# Authors: Nathan Binkert 303520Sgblack@eecs.umich.edu 313520Sgblack@eecs.umich.eduimport array 323520Sgblack@eecs.umich.eduimport bisect 333520Sgblack@eecs.umich.eduimport imp 343520Sgblack@eecs.umich.eduimport marshal 3510474Sandreas.hansson@arm.comimport os 3610474Sandreas.hansson@arm.comimport re 373520Sgblack@eecs.umich.eduimport sys 383520Sgblack@eecs.umich.eduimport zlib 394103Ssaidi@eecs.umich.edu 405647Sgblack@eecs.umich.edufrom os.path import basename, dirname, exists, isdir, isfile, join as joinpath 413520Sgblack@eecs.umich.edu 428232Snate@binkert.orgimport SCons 438232Snate@binkert.org 445647Sgblack@eecs.umich.edu# This file defines how to build a particular configuration of gem5 455647Sgblack@eecs.umich.edu# based on variable settings in the 'env' build environment. 463520Sgblack@eecs.umich.edu 475565Snate@binkert.orgImport('*') 485565Snate@binkert.org 495647Sgblack@eecs.umich.edu# Children need to see the environment 503520Sgblack@eecs.umich.eduExport('env') 515565Snate@binkert.org 525565Snate@binkert.orgbuild_env = [(opt, env[opt]) for opt in export_vars] 535565Snate@binkert.org 545565Snate@binkert.orgfrom m5.util import code_formatter 555810Sgblack@eecs.umich.edu 565565Snate@binkert.org######################################################################## 575565Snate@binkert.org# Code for adding source files of various types 585565Snate@binkert.org# 595565Snate@binkert.org# When specifying a source file of some type, a set of guards can be 605565Snate@binkert.org# specified for that file. When get() is used to find the files, if 615565Snate@binkert.org# get specifies a set of filters, only files that match those filters 625647Sgblack@eecs.umich.edu# will be accepted (unspecified filters on files are assumed to be 635647Sgblack@eecs.umich.edu# false). Current filters are: 645647Sgblack@eecs.umich.edu# main -- specifies the gem5 main() function 655647Sgblack@eecs.umich.edu# skip_lib -- do not put this file into the gem5 library 665647Sgblack@eecs.umich.edu# <unittest> -- unit tests use filters based on the unit test name 675647Sgblack@eecs.umich.edu# 685647Sgblack@eecs.umich.edu# A parent can now be specified for a source file and default filter 695647Sgblack@eecs.umich.edu# values will be retrieved recursively from parents (children override 705810Sgblack@eecs.umich.edu# parents). 713520Sgblack@eecs.umich.edu# 725565Snate@binkert.orgclass SourceMeta(type): 735565Snate@binkert.org '''Meta class for source files that keeps track of all files of a 745565Snate@binkert.org particular type and has a get function for finding all functions 755565Snate@binkert.org of a certain type that match a set of guards''' 763520Sgblack@eecs.umich.edu def __init__(cls, name, bases, dict): 775565Snate@binkert.org super(SourceMeta, cls).__init__(name, bases, dict) 785810Sgblack@eecs.umich.edu cls.all = [] 795810Sgblack@eecs.umich.edu 805810Sgblack@eecs.umich.edu def get(cls, **guards): 815810Sgblack@eecs.umich.edu '''Find all files that match the specified guards. If a source 825810Sgblack@eecs.umich.edu file does not specify a flag, the default is False''' 835810Sgblack@eecs.umich.edu for src in cls.all: 845565Snate@binkert.org for flag,value in guards.iteritems(): 855565Snate@binkert.org # if the flag is found and has a different value, skip 865565Snate@binkert.org # this file 873520Sgblack@eecs.umich.edu if src.all_guards.get(flag, False) != value: 885565Snate@binkert.org break 895565Snate@binkert.org else: 903520Sgblack@eecs.umich.edu yield src 915565Snate@binkert.org 925565Snate@binkert.orgclass SourceFile(object): 933520Sgblack@eecs.umich.edu '''Base object that encapsulates the notion of a source file. 945565Snate@binkert.org This includes, the source node, target node, various manipulations 955565Snate@binkert.org of those. A source file also specifies a set of guards which 965565Snate@binkert.org describing which builds the source file applies to. A parent can 973520Sgblack@eecs.umich.edu also be specified to get default guards from''' 985565Snate@binkert.org __metaclass__ = SourceMeta 995565Snate@binkert.org def __init__(self, source, parent=None, **guards): 1005565Snate@binkert.org self.guards = guards 1015565Snate@binkert.org self.parent = parent 1023520Sgblack@eecs.umich.edu 1035568Snate@binkert.org tnode = source 1045565Snate@binkert.org if not isinstance(source, SCons.Node.FS.File): 1053520Sgblack@eecs.umich.edu tnode = File(source) 1065565Snate@binkert.org 1075565Snate@binkert.org self.tnode = tnode 1083520Sgblack@eecs.umich.edu self.snode = tnode.srcnode() 1095565Snate@binkert.org 1105565Snate@binkert.org for base in type(self).__mro__: 1115565Snate@binkert.org if issubclass(base, SourceFile): 1125565Snate@binkert.org base.all.append(self) 1133520Sgblack@eecs.umich.edu 1145565Snate@binkert.org @property 1155704Snate@binkert.org def filename(self): 1165565Snate@binkert.org return str(self.tnode) 1175565Snate@binkert.org 1183520Sgblack@eecs.umich.edu @property 1195565Snate@binkert.org def dirname(self): 1205565Snate@binkert.org return dirname(self.filename) 1215565Snate@binkert.org 1223520Sgblack@eecs.umich.edu @property 1235565Snate@binkert.org def basename(self): 1245565Snate@binkert.org return basename(self.filename) 1255565Snate@binkert.org 1265565Snate@binkert.org @property 1275565Snate@binkert.org def extname(self): 1285565Snate@binkert.org index = self.basename.rfind('.') 1293520Sgblack@eecs.umich.edu if index <= 0: 1305565Snate@binkert.org # dot files aren't extensions 1315565Snate@binkert.org return self.basename, None 1325565Snate@binkert.org 1335565Snate@binkert.org return self.basename[:index], self.basename[index+1:] 1345565Snate@binkert.org 1355565Snate@binkert.org @property 1363520Sgblack@eecs.umich.edu def all_guards(self): 1375565Snate@binkert.org '''find all guards for this object getting default values 1385704Snate@binkert.org recursively from its parents''' 1395565Snate@binkert.org guards = {} 1407720Sgblack@eecs.umich.edu if self.parent: 1415565Snate@binkert.org guards.update(self.parent.guards) 1423520Sgblack@eecs.umich.edu guards.update(self.guards) 1435565Snate@binkert.org return guards 1445565Snate@binkert.org 1455565Snate@binkert.org def __lt__(self, other): return self.filename < other.filename 1466227Snate@binkert.org def __le__(self, other): return self.filename <= other.filename 1476227Snate@binkert.org def __gt__(self, other): return self.filename > other.filename 1483521Sgblack@eecs.umich.edu def __ge__(self, other): return self.filename >= other.filename 1495565Snate@binkert.org def __eq__(self, other): return self.filename == other.filename 1505565Snate@binkert.org def __ne__(self, other): return self.filename != other.filename 1513520Sgblack@eecs.umich.edu 1525565Snate@binkert.orgclass Source(SourceFile): 1536227Snate@binkert.org '''Add a c/c++ source file to the build''' 1545565Snate@binkert.org def __init__(self, source, Werror=True, swig=False, **guards): 1555565Snate@binkert.org '''specify the source file, and any guards''' 1565565Snate@binkert.org super(Source, self).__init__(source, **guards) 1575565Snate@binkert.org 1585565Snate@binkert.org self.Werror = Werror 1593520Sgblack@eecs.umich.edu self.swig = swig 1603520Sgblack@eecs.umich.edu 1613520Sgblack@eecs.umich.educlass PySource(SourceFile): 1623520Sgblack@eecs.umich.edu '''Add a python source file to the named package''' 1639550Sandreas.hansson@arm.com invalid_sym_char = re.compile('[^A-z0-9_]') 1646227Snate@binkert.org modules = {} 1655565Snate@binkert.org tnodes = {} 1669550Sandreas.hansson@arm.com symnames = {} 1675565Snate@binkert.org 1685565Snate@binkert.org def __init__(self, package, source, **guards): 1695565Snate@binkert.org '''specify the python package, the source file, and any guards''' 1705565Snate@binkert.org super(PySource, self).__init__(source, **guards) 1715565Snate@binkert.org 1723633Sktlim@umich.edu modname,ext = self.extname 1733633Sktlim@umich.edu assert ext == 'py' 1745565Snate@binkert.org 1755565Snate@binkert.org if package: 1765565Snate@binkert.org path = package.split('.') 1775565Snate@binkert.org else: 1785565Snate@binkert.org path = [] 1795565Snate@binkert.org 1805565Snate@binkert.org modpath = path[:] 18110474Sandreas.hansson@arm.com if modname != '__init__': 1825565Snate@binkert.org modpath += [ modname ] 1835565Snate@binkert.org modpath = '.'.join(modpath) 1844103Ssaidi@eecs.umich.edu 1855565Snate@binkert.org arcpath = path + [ self.basename ] 1864103Ssaidi@eecs.umich.edu abspath = self.snode.abspath 1875565Snate@binkert.org if not exists(abspath): 1885565Snate@binkert.org abspath = self.tnode.abspath 1895565Snate@binkert.org 1905565Snate@binkert.org self.package = package 1915565Snate@binkert.org self.modname = modname 1925565Snate@binkert.org self.modpath = modpath 1935565Snate@binkert.org self.arcname = joinpath(*arcpath) 1945565Snate@binkert.org self.abspath = abspath 1955565Snate@binkert.org self.compiled = File(self.filename + 'c') 1963520Sgblack@eecs.umich.edu self.cpp = File(self.filename + '.cc') 1975565Snate@binkert.org self.symname = PySource.invalid_sym_char.sub('_', modpath) 1985565Snate@binkert.org 1995565Snate@binkert.org PySource.modules[modpath] = self 2005565Snate@binkert.org PySource.tnodes[self.tnode] = self 201 PySource.symnames[self.symname] = self 202 203class SimObject(PySource): 204 '''Add a SimObject python file as a python source object and add 205 it to a list of sim object modules''' 206 207 fixed = False 208 modnames = [] 209 210 def __init__(self, source, **guards): 211 '''Specify the source file and any guards (automatically in 212 the m5.objects package)''' 213 super(SimObject, self).__init__('m5.objects', source, **guards) 214 if self.fixed: 215 raise AttributeError, "Too late to call SimObject now." 216 217 bisect.insort_right(SimObject.modnames, self.modname) 218 219class SwigSource(SourceFile): 220 '''Add a swig file to build''' 221 222 def __init__(self, package, source, **guards): 223 '''Specify the python package, the source file, and any guards''' 224 super(SwigSource, self).__init__(source, **guards) 225 226 modname,ext = self.extname 227 assert ext == 'i' 228 229 self.module = modname 230 cc_file = joinpath(self.dirname, modname + '_wrap.cc') 231 py_file = joinpath(self.dirname, modname + '.py') 232 233 self.cc_source = Source(cc_file, swig=True, parent=self) 234 self.py_source = PySource(package, py_file, parent=self) 235 236class UnitTest(object): 237 '''Create a UnitTest''' 238 239 all = [] 240 def __init__(self, target, *sources): 241 '''Specify the target name and any sources. Sources that are 242 not SourceFiles are evalued with Source(). All files are 243 guarded with a guard of the same name as the UnitTest 244 target.''' 245 246 srcs = [] 247 for src in sources: 248 if not isinstance(src, SourceFile): 249 src = Source(src, skip_lib=True) 250 src.guards[target] = True 251 srcs.append(src) 252 253 self.sources = srcs 254 self.target = target 255 UnitTest.all.append(self) 256 257# Children should have access 258Export('Source') 259Export('PySource') 260Export('SimObject') 261Export('SwigSource') 262Export('UnitTest') 263 264######################################################################## 265# 266# Debug Flags 267# 268debug_flags = {} 269def DebugFlag(name, desc=None): 270 if name in debug_flags: 271 raise AttributeError, "Flag %s already specified" % name 272 debug_flags[name] = (name, (), desc) 273TraceFlag = DebugFlag 274 275def CompoundFlag(name, flags, desc=None): 276 if name in debug_flags: 277 raise AttributeError, "Flag %s already specified" % name 278 279 compound = tuple(flags) 280 debug_flags[name] = (name, compound, desc) 281 282Export('DebugFlag') 283Export('TraceFlag') 284Export('CompoundFlag') 285 286######################################################################## 287# 288# Set some compiler variables 289# 290 291# Include file paths are rooted in this directory. SCons will 292# automatically expand '.' to refer to both the source directory and 293# the corresponding build directory to pick up generated include 294# files. 295env.Append(CPPPATH=Dir('.')) 296 297for extra_dir in extras_dir_list: 298 env.Append(CPPPATH=Dir(extra_dir)) 299 300# Workaround for bug in SCons version > 0.97d20071212 301# Scons bug id: 2006 gem5 Bug id: 308 302for root, dirs, files in os.walk(base_dir, topdown=True): 303 Dir(root[len(base_dir) + 1:]) 304 305######################################################################## 306# 307# Walk the tree and execute all SConscripts in subdirectories 308# 309 310here = Dir('.').srcnode().abspath 311for root, dirs, files in os.walk(base_dir, topdown=True): 312 if root == here: 313 # we don't want to recurse back into this SConscript 314 continue 315 316 if 'SConscript' in files: 317 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 318 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 319 320for extra_dir in extras_dir_list: 321 prefix_len = len(dirname(extra_dir)) + 1 322 for root, dirs, files in os.walk(extra_dir, topdown=True): 323 # if build lives in the extras directory, don't walk down it 324 if 'build' in dirs: 325 dirs.remove('build') 326 327 if 'SConscript' in files: 328 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 329 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 330 331for opt in export_vars: 332 env.ConfigFile(opt) 333 334def makeTheISA(source, target, env): 335 isas = [ src.get_contents() for src in source ] 336 target_isa = env['TARGET_ISA'] 337 def define(isa): 338 return isa.upper() + '_ISA' 339 340 def namespace(isa): 341 return isa[0].upper() + isa[1:].lower() + 'ISA' 342 343 344 code = code_formatter() 345 code('''\ 346#ifndef __CONFIG_THE_ISA_HH__ 347#define __CONFIG_THE_ISA_HH__ 348 349''') 350 351 for i,isa in enumerate(isas): 352 code('#define $0 $1', define(isa), i + 1) 353 354 code(''' 355 356#define THE_ISA ${{define(target_isa)}} 357#define TheISA ${{namespace(target_isa)}} 358 359#endif // __CONFIG_THE_ISA_HH__''') 360 361 code.write(str(target[0])) 362 363env.Command('config/the_isa.hh', map(Value, all_isa_list), 364 MakeAction(makeTheISA, Transform("CFG ISA", 0))) 365 366######################################################################## 367# 368# Prevent any SimObjects from being added after this point, they 369# should all have been added in the SConscripts above 370# 371SimObject.fixed = True 372 373class DictImporter(object): 374 '''This importer takes a dictionary of arbitrary module names that 375 map to arbitrary filenames.''' 376 def __init__(self, modules): 377 self.modules = modules 378 self.installed = set() 379 380 def __del__(self): 381 self.unload() 382 383 def unload(self): 384 import sys 385 for module in self.installed: 386 del sys.modules[module] 387 self.installed = set() 388 389 def find_module(self, fullname, path): 390 if fullname == 'm5.defines': 391 return self 392 393 if fullname == 'm5.objects': 394 return self 395 396 if fullname.startswith('m5.internal'): 397 return None 398 399 source = self.modules.get(fullname, None) 400 if source is not None and fullname.startswith('m5.objects'): 401 return self 402 403 return None 404 405 def load_module(self, fullname): 406 mod = imp.new_module(fullname) 407 sys.modules[fullname] = mod 408 self.installed.add(fullname) 409 410 mod.__loader__ = self 411 if fullname == 'm5.objects': 412 mod.__path__ = fullname.split('.') 413 return mod 414 415 if fullname == 'm5.defines': 416 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 417 return mod 418 419 source = self.modules[fullname] 420 if source.modname == '__init__': 421 mod.__path__ = source.modpath 422 mod.__file__ = source.abspath 423 424 exec file(source.abspath, 'r') in mod.__dict__ 425 426 return mod 427 428import m5.SimObject 429import m5.params 430from m5.util import code_formatter 431 432m5.SimObject.clear() 433m5.params.clear() 434 435# install the python importer so we can grab stuff from the source 436# tree itself. We can't have SimObjects added after this point or 437# else we won't know about them for the rest of the stuff. 438importer = DictImporter(PySource.modules) 439sys.meta_path[0:0] = [ importer ] 440 441# import all sim objects so we can populate the all_objects list 442# make sure that we're working with a list, then let's sort it 443for modname in SimObject.modnames: 444 exec('from m5.objects import %s' % modname) 445 446# we need to unload all of the currently imported modules so that they 447# will be re-imported the next time the sconscript is run 448importer.unload() 449sys.meta_path.remove(importer) 450 451sim_objects = m5.SimObject.allClasses 452all_enums = m5.params.allEnums 453 454all_params = {} 455for name,obj in sorted(sim_objects.iteritems()): 456 for param in obj._params.local.values(): 457 # load the ptype attribute now because it depends on the 458 # current version of SimObject.allClasses, but when scons 459 # actually uses the value, all versions of 460 # SimObject.allClasses will have been loaded 461 param.ptype 462 463 if not hasattr(param, 'swig_decl'): 464 continue 465 pname = param.ptype_str 466 if pname not in all_params: 467 all_params[pname] = param 468 469######################################################################## 470# 471# calculate extra dependencies 472# 473module_depends = ["m5", "m5.SimObject", "m5.params"] 474depends = [ PySource.modules[dep].snode for dep in module_depends ] 475 476######################################################################## 477# 478# Commands for the basic automatically generated python files 479# 480 481# Generate Python file containing a dict specifying the current 482# buildEnv flags. 483def makeDefinesPyFile(target, source, env): 484 build_env = source[0].get_contents() 485 486 code = code_formatter() 487 code(""" 488import m5.internal 489import m5.util 490 491buildEnv = m5.util.SmartDict($build_env) 492 493compileDate = m5.internal.core.compileDate 494_globals = globals() 495for key,val in m5.internal.core.__dict__.iteritems(): 496 if key.startswith('flag_'): 497 flag = key[5:] 498 _globals[flag] = val 499del _globals 500""") 501 code.write(target[0].abspath) 502 503defines_info = Value(build_env) 504# Generate a file with all of the compile options in it 505env.Command('python/m5/defines.py', defines_info, 506 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 507PySource('m5', 'python/m5/defines.py') 508 509# Generate python file containing info about the M5 source code 510def makeInfoPyFile(target, source, env): 511 code = code_formatter() 512 for src in source: 513 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 514 code('$src = ${{repr(data)}}') 515 code.write(str(target[0])) 516 517# Generate a file that wraps the basic top level files 518env.Command('python/m5/info.py', 519 [ '#/COPYING', '#/LICENSE', '#/README', ], 520 MakeAction(makeInfoPyFile, Transform("INFO"))) 521PySource('m5', 'python/m5/info.py') 522 523######################################################################## 524# 525# Create all of the SimObject param headers and enum headers 526# 527 528def createSimObjectParam(target, source, env): 529 assert len(target) == 1 and len(source) == 1 530 531 name = str(source[0].get_contents()) 532 obj = sim_objects[name] 533 534 code = code_formatter() 535 obj.cxx_decl(code) 536 code.write(target[0].abspath) 537 538def createSwigParam(target, source, env): 539 assert len(target) == 1 and len(source) == 1 540 541 name = str(source[0].get_contents()) 542 param = all_params[name] 543 544 code = code_formatter() 545 code('%module(package="m5.internal") $0_${name}', param.file_ext) 546 param.swig_decl(code) 547 code.write(target[0].abspath) 548 549def createEnumStrings(target, source, env): 550 assert len(target) == 1 and len(source) == 1 551 552 name = str(source[0].get_contents()) 553 obj = all_enums[name] 554 555 code = code_formatter() 556 obj.cxx_def(code) 557 code.write(target[0].abspath) 558 559def createEnumParam(target, source, env): 560 assert len(target) == 1 and len(source) == 1 561 562 name = str(source[0].get_contents()) 563 obj = all_enums[name] 564 565 code = code_formatter() 566 obj.cxx_decl(code) 567 code.write(target[0].abspath) 568 569def createEnumSwig(target, source, env): 570 assert len(target) == 1 and len(source) == 1 571 572 name = str(source[0].get_contents()) 573 obj = all_enums[name] 574 575 code = code_formatter() 576 code('''\ 577%module(package="m5.internal") enum_$name 578 579%{ 580#include "enums/$name.hh" 581%} 582 583%include "enums/$name.hh" 584''') 585 code.write(target[0].abspath) 586 587# Generate all of the SimObject param struct header files 588params_hh_files = [] 589for name,simobj in sorted(sim_objects.iteritems()): 590 py_source = PySource.modules[simobj.__module__] 591 extra_deps = [ py_source.tnode ] 592 593 hh_file = File('params/%s.hh' % name) 594 params_hh_files.append(hh_file) 595 env.Command(hh_file, Value(name), 596 MakeAction(createSimObjectParam, Transform("SO PARAM"))) 597 env.Depends(hh_file, depends + extra_deps) 598 599# Generate any parameter header files needed 600params_i_files = [] 601for name,param in all_params.iteritems(): 602 i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name)) 603 params_i_files.append(i_file) 604 env.Command(i_file, Value(name), 605 MakeAction(createSwigParam, Transform("SW PARAM"))) 606 env.Depends(i_file, depends) 607 SwigSource('m5.internal', i_file) 608 609# Generate all enum header files 610for name,enum in sorted(all_enums.iteritems()): 611 py_source = PySource.modules[enum.__module__] 612 extra_deps = [ py_source.tnode ] 613 614 cc_file = File('enums/%s.cc' % name) 615 env.Command(cc_file, Value(name), 616 MakeAction(createEnumStrings, Transform("ENUM STR"))) 617 env.Depends(cc_file, depends + extra_deps) 618 Source(cc_file) 619 620 hh_file = File('enums/%s.hh' % name) 621 env.Command(hh_file, Value(name), 622 MakeAction(createEnumParam, Transform("EN PARAM"))) 623 env.Depends(hh_file, depends + extra_deps) 624 625 i_file = File('python/m5/internal/enum_%s.i' % name) 626 env.Command(i_file, Value(name), 627 MakeAction(createEnumSwig, Transform("ENUMSWIG"))) 628 env.Depends(i_file, depends + extra_deps) 629 SwigSource('m5.internal', i_file) 630 631def buildParam(target, source, env): 632 name = source[0].get_contents() 633 obj = sim_objects[name] 634 class_path = obj.cxx_class.split('::') 635 classname = class_path[-1] 636 namespaces = class_path[:-1] 637 params = obj._params.local.values() 638 639 code = code_formatter() 640 641 code('%module(package="m5.internal") param_$name') 642 code() 643 code('%{') 644 code('#include "params/$obj.hh"') 645 for param in params: 646 param.cxx_predecls(code) 647 code('%}') 648 code() 649 650 for param in params: 651 param.swig_predecls(code) 652 653 code() 654 if obj._base: 655 code('%import "python/m5/internal/param_${{obj._base}}.i"') 656 code() 657 obj.swig_objdecls(code) 658 code() 659 660 code('%include "params/$obj.hh"') 661 662 code.write(target[0].abspath) 663 664for name in sim_objects.iterkeys(): 665 params_file = File('python/m5/internal/param_%s.i' % name) 666 env.Command(params_file, Value(name), 667 MakeAction(buildParam, Transform("BLDPARAM"))) 668 env.Depends(params_file, depends) 669 SwigSource('m5.internal', params_file) 670 671# Generate the main swig init file 672def makeEmbeddedSwigInit(target, source, env): 673 code = code_formatter() 674 module = source[0].get_contents() 675 code('''\ 676#include "sim/init.hh" 677 678extern "C" { 679 void init_${module}(); 680} 681 682EmbeddedSwig embed_swig_${module}(init_${module}); 683''') 684 code.write(str(target[0])) 685 686# Build all swig modules 687for swig in SwigSource.all: 688 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 689 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 690 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG"))) 691 cc_file = str(swig.tnode) 692 init_file = '%s/init_%s.cc' % (dirname(cc_file), basename(cc_file)) 693 env.Command(init_file, Value(swig.module), 694 MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW"))) 695 Source(init_file, **swig.guards) 696 697# 698# Handle debug flags 699# 700def makeDebugFlagCC(target, source, env): 701 assert(len(target) == 1 and len(source) == 1) 702 703 val = eval(source[0].get_contents()) 704 name, compound, desc = val 705 compound = list(sorted(compound)) 706 707 code = code_formatter() 708 709 # file header 710 code(''' 711/* 712 * DO NOT EDIT THIS FILE! Automatically generated 713 */ 714 715#include "base/debug.hh" 716''') 717 718 for flag in compound: 719 code('#include "debug/$flag.hh"') 720 code() 721 code('namespace Debug {') 722 code() 723 724 if not compound: 725 code('SimpleFlag $name("$name", "$desc");') 726 else: 727 code('CompoundFlag $name("$name", "$desc",') 728 code.indent() 729 last = len(compound) - 1 730 for i,flag in enumerate(compound): 731 if i != last: 732 code('$flag,') 733 else: 734 code('$flag);') 735 code.dedent() 736 737 code() 738 code('} // namespace Debug') 739 740 code.write(str(target[0])) 741 742def makeDebugFlagHH(target, source, env): 743 assert(len(target) == 1 and len(source) == 1) 744 745 val = eval(source[0].get_contents()) 746 name, compound, desc = val 747 748 code = code_formatter() 749 750 # file header boilerplate 751 code('''\ 752/* 753 * DO NOT EDIT THIS FILE! 754 * 755 * Automatically generated by SCons 756 */ 757 758#ifndef __DEBUG_${name}_HH__ 759#define __DEBUG_${name}_HH__ 760 761namespace Debug { 762''') 763 764 if compound: 765 code('class CompoundFlag;') 766 code('class SimpleFlag;') 767 768 if compound: 769 code('extern CompoundFlag $name;') 770 for flag in compound: 771 code('extern SimpleFlag $flag;') 772 else: 773 code('extern SimpleFlag $name;') 774 775 code(''' 776} 777 778#endif // __DEBUG_${name}_HH__ 779''') 780 781 code.write(str(target[0])) 782 783for name,flag in sorted(debug_flags.iteritems()): 784 n, compound, desc = flag 785 assert n == name 786 787 env.Command('debug/%s.hh' % name, Value(flag), 788 MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) 789 env.Command('debug/%s.cc' % name, Value(flag), 790 MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) 791 Source('debug/%s.cc' % name) 792 793# Embed python files. All .py files that have been indicated by a 794# PySource() call in a SConscript need to be embedded into the M5 795# library. To do that, we compile the file to byte code, marshal the 796# byte code, compress it, and then generate a c++ file that 797# inserts the result into an array. 798def embedPyFile(target, source, env): 799 def c_str(string): 800 if string is None: 801 return "0" 802 return '"%s"' % string 803 804 '''Action function to compile a .py into a code object, marshal 805 it, compress it, and stick it into an asm file so the code appears 806 as just bytes with a label in the data section''' 807 808 src = file(str(source[0]), 'r').read() 809 810 pysource = PySource.tnodes[source[0]] 811 compiled = compile(src, pysource.abspath, 'exec') 812 marshalled = marshal.dumps(compiled) 813 compressed = zlib.compress(marshalled) 814 data = compressed 815 sym = pysource.symname 816 817 code = code_formatter() 818 code('''\ 819#include "sim/init.hh" 820 821namespace { 822 823const char data_${sym}[] = { 824''') 825 code.indent() 826 step = 16 827 for i in xrange(0, len(data), step): 828 x = array.array('B', data[i:i+step]) 829 code(''.join('%d,' % d for d in x)) 830 code.dedent() 831 832 code('''}; 833 834EmbeddedPython embedded_${sym}( 835 ${{c_str(pysource.arcname)}}, 836 ${{c_str(pysource.abspath)}}, 837 ${{c_str(pysource.modpath)}}, 838 data_${sym}, 839 ${{len(data)}}, 840 ${{len(marshalled)}}); 841 842} // anonymous namespace 843''') 844 code.write(str(target[0])) 845 846for source in PySource.all: 847 env.Command(source.cpp, source.tnode, 848 MakeAction(embedPyFile, Transform("EMBED PY"))) 849 Source(source.cpp) 850 851######################################################################## 852# 853# Define binaries. Each different build type (debug, opt, etc.) gets 854# a slightly different build environment. 855# 856 857# List of constructed environments to pass back to SConstruct 858envList = [] 859 860date_source = Source('base/date.cc', skip_lib=True) 861 862# Function to create a new build environment as clone of current 863# environment 'env' with modified object suffix and optional stripped 864# binary. Additional keyword arguments are appended to corresponding 865# build environment vars. 866def makeEnv(label, objsfx, strip = False, **kwargs): 867 # SCons doesn't know to append a library suffix when there is a '.' in the 868 # name. Use '_' instead. 869 libname = 'gem5_' + label 870 exename = 'gem5.' + label 871 secondary_exename = 'm5.' + label 872 873 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 874 new_env.Label = label 875 new_env.Append(**kwargs) 876 877 swig_env = new_env.Clone() 878 swig_env.Append(CCFLAGS='-Werror') 879 if env['GCC']: 880 swig_env.Append(CCFLAGS='-Wno-uninitialized') 881 swig_env.Append(CCFLAGS='-Wno-sign-compare') 882 swig_env.Append(CCFLAGS='-Wno-parentheses') 883 884 werror_env = new_env.Clone() 885 werror_env.Append(CCFLAGS='-Werror') 886 887 def make_obj(source, static, extra_deps = None): 888 '''This function adds the specified source to the correct 889 build environment, and returns the corresponding SCons Object 890 nodes''' 891 892 if source.swig: 893 env = swig_env 894 elif source.Werror: 895 env = werror_env 896 else: 897 env = new_env 898 899 if static: 900 obj = env.StaticObject(source.tnode) 901 else: 902 obj = env.SharedObject(source.tnode) 903 904 if extra_deps: 905 env.Depends(obj, extra_deps) 906 907 return obj 908 909 sources = Source.get(main=False, skip_lib=False) 910 static_objs = [ make_obj(s, True) for s in sources ] 911 shared_objs = [ make_obj(s, False) for s in sources ] 912 913 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 914 static_objs.append(static_date) 915 916 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 917 shared_objs.append(shared_date) 918 919 # First make a library of everything but main() so other programs can 920 # link against m5. 921 static_lib = new_env.StaticLibrary(libname, static_objs) 922 shared_lib = new_env.SharedLibrary(libname, shared_objs) 923 924 # Now link a stub with main() and the static library. 925 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ] 926 927 for test in UnitTest.all: 928 flags = { test.target : True } 929 test_sources = Source.get(**flags) 930 test_objs = [ make_obj(s, static=True) for s in test_sources ] 931 testname = "unittest/%s.%s" % (test.target, label) 932 new_env.Program(testname, main_objs + test_objs + static_objs) 933 934 progname = exename 935 if strip: 936 progname += '.unstripped' 937 938 targets = new_env.Program(progname, main_objs + static_objs) 939 940 if strip: 941 if sys.platform == 'sunos5': 942 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 943 else: 944 cmd = 'strip $SOURCE -o $TARGET' 945 targets = new_env.Command(exename, progname, 946 MakeAction(cmd, Transform("STRIP"))) 947 948 new_env.Command(secondary_exename, exename, 949 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK"))) 950 951 new_env.M5Binary = targets[0] 952 envList.append(new_env) 953 954# Debug binary 955ccflags = {} 956if env['GCC']: 957 if sys.platform == 'sunos5': 958 ccflags['debug'] = '-gstabs+' 959 else: 960 ccflags['debug'] = '-ggdb3' 961 ccflags['opt'] = '-g -O3' 962 ccflags['fast'] = '-O3' 963 ccflags['prof'] = '-O3 -g -pg' 964elif env['SUNCC']: 965 ccflags['debug'] = '-g0' 966 ccflags['opt'] = '-g -O' 967 ccflags['fast'] = '-fast' 968 ccflags['prof'] = '-fast -g -pg' 969elif env['ICC']: 970 ccflags['debug'] = '-g -O0' 971 ccflags['opt'] = '-g -O' 972 ccflags['fast'] = '-fast' 973 ccflags['prof'] = '-fast -g -pg' 974else: 975 print 'Unknown compiler, please fix compiler options' 976 Exit(1) 977 978makeEnv('debug', '.do', 979 CCFLAGS = Split(ccflags['debug']), 980 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 981 982# Optimized binary 983makeEnv('opt', '.o', 984 CCFLAGS = Split(ccflags['opt']), 985 CPPDEFINES = ['TRACING_ON=1']) 986 987# "Fast" binary 988makeEnv('fast', '.fo', strip = True, 989 CCFLAGS = Split(ccflags['fast']), 990 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 991 992# Profiled binary 993makeEnv('prof', '.po', 994 CCFLAGS = Split(ccflags['prof']), 995 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 996 LINKFLAGS = '-pg') 997 998Return('envList') 999