SConscript revision 8594
1# -*- mode:python -*- 2 3# Copyright (c) 2004-2005 The Regents of The University of Michigan 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are 8# met: redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer; 10# redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution; 13# neither the name of the copyright holders nor the names of its 14# contributors may be used to endorse or promote products derived from 15# this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28# 29# Authors: Nathan Binkert 30 31import array 32import bisect 33import imp 34import marshal 35import os 36import re 37import sys 38import zlib 39 40from os.path import basename, dirname, exists, isdir, isfile, join as joinpath 41 42import SCons 43 44# This file defines how to build a particular configuration of gem5 45# based on variable settings in the 'env' build environment. 46 47Import('*') 48 49# Children need to see the environment 50Export('env') 51 52build_env = [(opt, env[opt]) for opt in export_vars] 53 54from m5.util import code_formatter 55 56######################################################################## 57# Code for adding source files of various types 58# 59# When specifying a source file of some type, a set of guards can be 60# specified for that file. When get() is used to find the files, if 61# get specifies a set of filters, only files that match those filters 62# will be accepted (unspecified filters on files are assumed to be 63# false). Current filters are: 64# main -- specifies the gem5 main() function 65# skip_lib -- do not put this file into the gem5 library 66# <unittest> -- unit tests use filters based on the unit test name 67# 68# A parent can now be specified for a source file and default filter 69# values will be retrieved recursively from parents (children override 70# parents). 71# 72class SourceMeta(type): 73 '''Meta class for source files that keeps track of all files of a 74 particular type and has a get function for finding all functions 75 of a certain type that match a set of guards''' 76 def __init__(cls, name, bases, dict): 77 super(SourceMeta, cls).__init__(name, bases, dict) 78 cls.all = [] 79 80 def get(cls, **guards): 81 '''Find all files that match the specified guards. If a source 82 file does not specify a flag, the default is False''' 83 for src in cls.all: 84 for flag,value in guards.iteritems(): 85 # if the flag is found and has a different value, skip 86 # this file 87 if src.all_guards.get(flag, False) != value: 88 break 89 else: 90 yield src 91 92class SourceFile(object): 93 '''Base object that encapsulates the notion of a source file. 94 This includes, the source node, target node, various manipulations 95 of those. A source file also specifies a set of guards which 96 describing which builds the source file applies to. A parent can 97 also be specified to get default guards from''' 98 __metaclass__ = SourceMeta 99 def __init__(self, source, parent=None, **guards): 100 self.guards = guards 101 self.parent = parent 102 103 tnode = source 104 if not isinstance(source, SCons.Node.FS.File): 105 tnode = File(source) 106 107 self.tnode = tnode 108 self.snode = tnode.srcnode() 109 110 for base in type(self).__mro__: 111 if issubclass(base, SourceFile): 112 base.all.append(self) 113 114 @property 115 def filename(self): 116 return str(self.tnode) 117 118 @property 119 def dirname(self): 120 return dirname(self.filename) 121 122 @property 123 def basename(self): 124 return basename(self.filename) 125 126 @property 127 def extname(self): 128 index = self.basename.rfind('.') 129 if index <= 0: 130 # dot files aren't extensions 131 return self.basename, None 132 133 return self.basename[:index], self.basename[index+1:] 134 135 @property 136 def all_guards(self): 137 '''find all guards for this object getting default values 138 recursively from its parents''' 139 guards = {} 140 if self.parent: 141 guards.update(self.parent.guards) 142 guards.update(self.guards) 143 return guards 144 145 def __lt__(self, other): return self.filename < other.filename 146 def __le__(self, other): return self.filename <= other.filename 147 def __gt__(self, other): return self.filename > other.filename 148 def __ge__(self, other): return self.filename >= other.filename 149 def __eq__(self, other): return self.filename == other.filename 150 def __ne__(self, other): return self.filename != other.filename 151 152class Source(SourceFile): 153 '''Add a c/c++ source file to the build''' 154 def __init__(self, source, Werror=True, swig=False, **guards): 155 '''specify the source file, and any guards''' 156 super(Source, self).__init__(source, **guards) 157 158 self.Werror = Werror 159 self.swig = swig 160 161class PySource(SourceFile): 162 '''Add a python source file to the named package''' 163 invalid_sym_char = re.compile('[^A-z0-9_]') 164 modules = {} 165 tnodes = {} 166 symnames = {} 167 168 def __init__(self, package, source, **guards): 169 '''specify the python package, the source file, and any guards''' 170 super(PySource, self).__init__(source, **guards) 171 172 modname,ext = self.extname 173 assert ext == 'py' 174 175 if package: 176 path = package.split('.') 177 else: 178 path = [] 179 180 modpath = path[:] 181 if modname != '__init__': 182 modpath += [ modname ] 183 modpath = '.'.join(modpath) 184 185 arcpath = path + [ self.basename ] 186 abspath = self.snode.abspath 187 if not exists(abspath): 188 abspath = self.tnode.abspath 189 190 self.package = package 191 self.modname = modname 192 self.modpath = modpath 193 self.arcname = joinpath(*arcpath) 194 self.abspath = abspath 195 self.compiled = File(self.filename + 'c') 196 self.cpp = File(self.filename + '.cc') 197 self.symname = PySource.invalid_sym_char.sub('_', modpath) 198 199 PySource.modules[modpath] = self 200 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) 273 274def CompoundFlag(name, flags, desc=None): 275 if name in debug_flags: 276 raise AttributeError, "Flag %s already specified" % name 277 278 compound = tuple(flags) 279 debug_flags[name] = (name, compound, desc) 280 281Export('DebugFlag') 282Export('CompoundFlag') 283 284######################################################################## 285# 286# Set some compiler variables 287# 288 289# Include file paths are rooted in this directory. SCons will 290# automatically expand '.' to refer to both the source directory and 291# the corresponding build directory to pick up generated include 292# files. 293env.Append(CPPPATH=Dir('.')) 294 295for extra_dir in extras_dir_list: 296 env.Append(CPPPATH=Dir(extra_dir)) 297 298# Workaround for bug in SCons version > 0.97d20071212 299# Scons bug id: 2006 gem5 Bug id: 308 300for root, dirs, files in os.walk(base_dir, topdown=True): 301 Dir(root[len(base_dir) + 1:]) 302 303######################################################################## 304# 305# Walk the tree and execute all SConscripts in subdirectories 306# 307 308here = Dir('.').srcnode().abspath 309for root, dirs, files in os.walk(base_dir, topdown=True): 310 if root == here: 311 # we don't want to recurse back into this SConscript 312 continue 313 314 if 'SConscript' in files: 315 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 316 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 317 318for extra_dir in extras_dir_list: 319 prefix_len = len(dirname(extra_dir)) + 1 320 for root, dirs, files in os.walk(extra_dir, topdown=True): 321 # if build lives in the extras directory, don't walk down it 322 if 'build' in dirs: 323 dirs.remove('build') 324 325 if 'SConscript' in files: 326 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) 327 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) 328 329for opt in export_vars: 330 env.ConfigFile(opt) 331 332def makeTheISA(source, target, env): 333 isas = [ src.get_contents() for src in source ] 334 target_isa = env['TARGET_ISA'] 335 def define(isa): 336 return isa.upper() + '_ISA' 337 338 def namespace(isa): 339 return isa[0].upper() + isa[1:].lower() + 'ISA' 340 341 342 code = code_formatter() 343 code('''\ 344#ifndef __CONFIG_THE_ISA_HH__ 345#define __CONFIG_THE_ISA_HH__ 346 347''') 348 349 for i,isa in enumerate(isas): 350 code('#define $0 $1', define(isa), i + 1) 351 352 code(''' 353 354#define THE_ISA ${{define(target_isa)}} 355#define TheISA ${{namespace(target_isa)}} 356 357#endif // __CONFIG_THE_ISA_HH__''') 358 359 code.write(str(target[0])) 360 361env.Command('config/the_isa.hh', map(Value, all_isa_list), 362 MakeAction(makeTheISA, Transform("CFG ISA", 0))) 363 364######################################################################## 365# 366# Prevent any SimObjects from being added after this point, they 367# should all have been added in the SConscripts above 368# 369SimObject.fixed = True 370 371class DictImporter(object): 372 '''This importer takes a dictionary of arbitrary module names that 373 map to arbitrary filenames.''' 374 def __init__(self, modules): 375 self.modules = modules 376 self.installed = set() 377 378 def __del__(self): 379 self.unload() 380 381 def unload(self): 382 import sys 383 for module in self.installed: 384 del sys.modules[module] 385 self.installed = set() 386 387 def find_module(self, fullname, path): 388 if fullname == 'm5.defines': 389 return self 390 391 if fullname == 'm5.objects': 392 return self 393 394 if fullname.startswith('m5.internal'): 395 return None 396 397 source = self.modules.get(fullname, None) 398 if source is not None and fullname.startswith('m5.objects'): 399 return self 400 401 return None 402 403 def load_module(self, fullname): 404 mod = imp.new_module(fullname) 405 sys.modules[fullname] = mod 406 self.installed.add(fullname) 407 408 mod.__loader__ = self 409 if fullname == 'm5.objects': 410 mod.__path__ = fullname.split('.') 411 return mod 412 413 if fullname == 'm5.defines': 414 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env) 415 return mod 416 417 source = self.modules[fullname] 418 if source.modname == '__init__': 419 mod.__path__ = source.modpath 420 mod.__file__ = source.abspath 421 422 exec file(source.abspath, 'r') in mod.__dict__ 423 424 return mod 425 426import m5.SimObject 427import m5.params 428from m5.util import code_formatter 429 430m5.SimObject.clear() 431m5.params.clear() 432 433# install the python importer so we can grab stuff from the source 434# tree itself. We can't have SimObjects added after this point or 435# else we won't know about them for the rest of the stuff. 436importer = DictImporter(PySource.modules) 437sys.meta_path[0:0] = [ importer ] 438 439# import all sim objects so we can populate the all_objects list 440# make sure that we're working with a list, then let's sort it 441for modname in SimObject.modnames: 442 exec('from m5.objects import %s' % modname) 443 444# we need to unload all of the currently imported modules so that they 445# will be re-imported the next time the sconscript is run 446importer.unload() 447sys.meta_path.remove(importer) 448 449sim_objects = m5.SimObject.allClasses 450all_enums = m5.params.allEnums 451 452all_params = {} 453for name,obj in sorted(sim_objects.iteritems()): 454 for param in obj._params.local.values(): 455 # load the ptype attribute now because it depends on the 456 # current version of SimObject.allClasses, but when scons 457 # actually uses the value, all versions of 458 # SimObject.allClasses will have been loaded 459 param.ptype 460 461 if not hasattr(param, 'swig_decl'): 462 continue 463 pname = param.ptype_str 464 if pname not in all_params: 465 all_params[pname] = param 466 467######################################################################## 468# 469# calculate extra dependencies 470# 471module_depends = ["m5", "m5.SimObject", "m5.params"] 472depends = [ PySource.modules[dep].snode for dep in module_depends ] 473 474######################################################################## 475# 476# Commands for the basic automatically generated python files 477# 478 479# Generate Python file containing a dict specifying the current 480# buildEnv flags. 481def makeDefinesPyFile(target, source, env): 482 build_env = source[0].get_contents() 483 484 code = code_formatter() 485 code(""" 486import m5.internal 487import m5.util 488 489buildEnv = m5.util.SmartDict($build_env) 490 491compileDate = m5.internal.core.compileDate 492_globals = globals() 493for key,val in m5.internal.core.__dict__.iteritems(): 494 if key.startswith('flag_'): 495 flag = key[5:] 496 _globals[flag] = val 497del _globals 498""") 499 code.write(target[0].abspath) 500 501defines_info = Value(build_env) 502# Generate a file with all of the compile options in it 503env.Command('python/m5/defines.py', defines_info, 504 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0))) 505PySource('m5', 'python/m5/defines.py') 506 507# Generate python file containing info about the M5 source code 508def makeInfoPyFile(target, source, env): 509 code = code_formatter() 510 for src in source: 511 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) 512 code('$src = ${{repr(data)}}') 513 code.write(str(target[0])) 514 515# Generate a file that wraps the basic top level files 516env.Command('python/m5/info.py', 517 [ '#/COPYING', '#/LICENSE', '#/README', ], 518 MakeAction(makeInfoPyFile, Transform("INFO"))) 519PySource('m5', 'python/m5/info.py') 520 521######################################################################## 522# 523# Create all of the SimObject param headers and enum headers 524# 525 526def createSimObjectParam(target, source, env): 527 assert len(target) == 1 and len(source) == 1 528 529 name = str(source[0].get_contents()) 530 obj = sim_objects[name] 531 532 code = code_formatter() 533 obj.cxx_decl(code) 534 code.write(target[0].abspath) 535 536def createSwigParam(target, source, env): 537 assert len(target) == 1 and len(source) == 1 538 539 name = str(source[0].get_contents()) 540 param = all_params[name] 541 542 code = code_formatter() 543 code('%module(package="m5.internal") $0_${name}', param.file_ext) 544 param.swig_decl(code) 545 code.write(target[0].abspath) 546 547def createEnumStrings(target, source, env): 548 assert len(target) == 1 and len(source) == 1 549 550 name = str(source[0].get_contents()) 551 obj = all_enums[name] 552 553 code = code_formatter() 554 obj.cxx_def(code) 555 code.write(target[0].abspath) 556 557def createEnumParam(target, source, env): 558 assert len(target) == 1 and len(source) == 1 559 560 name = str(source[0].get_contents()) 561 obj = all_enums[name] 562 563 code = code_formatter() 564 obj.cxx_decl(code) 565 code.write(target[0].abspath) 566 567def createEnumSwig(target, source, env): 568 assert len(target) == 1 and len(source) == 1 569 570 name = str(source[0].get_contents()) 571 obj = all_enums[name] 572 573 code = code_formatter() 574 code('''\ 575%module(package="m5.internal") enum_$name 576 577%{ 578#include "enums/$name.hh" 579%} 580 581%include "enums/$name.hh" 582''') 583 code.write(target[0].abspath) 584 585# Generate all of the SimObject param struct header files 586params_hh_files = [] 587for name,simobj in sorted(sim_objects.iteritems()): 588 py_source = PySource.modules[simobj.__module__] 589 extra_deps = [ py_source.tnode ] 590 591 hh_file = File('params/%s.hh' % name) 592 params_hh_files.append(hh_file) 593 env.Command(hh_file, Value(name), 594 MakeAction(createSimObjectParam, Transform("SO PARAM"))) 595 env.Depends(hh_file, depends + extra_deps) 596 597# Generate any parameter header files needed 598params_i_files = [] 599for name,param in all_params.iteritems(): 600 i_file = File('python/m5/internal/%s_%s.i' % (param.file_ext, name)) 601 params_i_files.append(i_file) 602 env.Command(i_file, Value(name), 603 MakeAction(createSwigParam, Transform("SW PARAM"))) 604 env.Depends(i_file, depends) 605 SwigSource('m5.internal', i_file) 606 607# Generate all enum header files 608for name,enum in sorted(all_enums.iteritems()): 609 py_source = PySource.modules[enum.__module__] 610 extra_deps = [ py_source.tnode ] 611 612 cc_file = File('enums/%s.cc' % name) 613 env.Command(cc_file, Value(name), 614 MakeAction(createEnumStrings, Transform("ENUM STR"))) 615 env.Depends(cc_file, depends + extra_deps) 616 Source(cc_file) 617 618 hh_file = File('enums/%s.hh' % name) 619 env.Command(hh_file, Value(name), 620 MakeAction(createEnumParam, Transform("EN PARAM"))) 621 env.Depends(hh_file, depends + extra_deps) 622 623 i_file = File('python/m5/internal/enum_%s.i' % name) 624 env.Command(i_file, Value(name), 625 MakeAction(createEnumSwig, Transform("ENUMSWIG"))) 626 env.Depends(i_file, depends + extra_deps) 627 SwigSource('m5.internal', i_file) 628 629def buildParam(target, source, env): 630 name = source[0].get_contents() 631 obj = sim_objects[name] 632 class_path = obj.cxx_class.split('::') 633 classname = class_path[-1] 634 namespaces = class_path[:-1] 635 params = obj._params.local.values() 636 637 code = code_formatter() 638 639 code('%module(package="m5.internal") param_$name') 640 code() 641 code('%{') 642 code('#include "params/$obj.hh"') 643 for param in params: 644 param.cxx_predecls(code) 645 code('%}') 646 code() 647 648 for param in params: 649 param.swig_predecls(code) 650 651 code() 652 if obj._base: 653 code('%import "python/m5/internal/param_${{obj._base}}.i"') 654 code() 655 obj.swig_objdecls(code) 656 code() 657 658 code('%include "params/$obj.hh"') 659 660 code.write(target[0].abspath) 661 662for name in sim_objects.iterkeys(): 663 params_file = File('python/m5/internal/param_%s.i' % name) 664 env.Command(params_file, Value(name), 665 MakeAction(buildParam, Transform("BLDPARAM"))) 666 env.Depends(params_file, depends) 667 SwigSource('m5.internal', params_file) 668 669# Generate the main swig init file 670def makeEmbeddedSwigInit(target, source, env): 671 code = code_formatter() 672 module = source[0].get_contents() 673 code('''\ 674#include "sim/init.hh" 675 676extern "C" { 677 void init_${module}(); 678} 679 680EmbeddedSwig embed_swig_${module}(init_${module}); 681''') 682 code.write(str(target[0])) 683 684# Build all swig modules 685for swig in SwigSource.all: 686 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, 687 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 688 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG"))) 689 cc_file = str(swig.tnode) 690 init_file = '%s/init_%s.cc' % (dirname(cc_file), basename(cc_file)) 691 env.Command(init_file, Value(swig.module), 692 MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW"))) 693 Source(init_file, **swig.guards) 694 695# 696# Handle debug flags 697# 698def makeDebugFlagCC(target, source, env): 699 assert(len(target) == 1 and len(source) == 1) 700 701 val = eval(source[0].get_contents()) 702 name, compound, desc = val 703 compound = list(sorted(compound)) 704 705 code = code_formatter() 706 707 # file header 708 code(''' 709/* 710 * DO NOT EDIT THIS FILE! Automatically generated 711 */ 712 713#include "base/debug.hh" 714''') 715 716 for flag in compound: 717 code('#include "debug/$flag.hh"') 718 code() 719 code('namespace Debug {') 720 code() 721 722 if not compound: 723 code('SimpleFlag $name("$name", "$desc");') 724 else: 725 code('CompoundFlag $name("$name", "$desc",') 726 code.indent() 727 last = len(compound) - 1 728 for i,flag in enumerate(compound): 729 if i != last: 730 code('$flag,') 731 else: 732 code('$flag);') 733 code.dedent() 734 735 code() 736 code('} // namespace Debug') 737 738 code.write(str(target[0])) 739 740def makeDebugFlagHH(target, source, env): 741 assert(len(target) == 1 and len(source) == 1) 742 743 val = eval(source[0].get_contents()) 744 name, compound, desc = val 745 746 code = code_formatter() 747 748 # file header boilerplate 749 code('''\ 750/* 751 * DO NOT EDIT THIS FILE! 752 * 753 * Automatically generated by SCons 754 */ 755 756#ifndef __DEBUG_${name}_HH__ 757#define __DEBUG_${name}_HH__ 758 759namespace Debug { 760''') 761 762 if compound: 763 code('class CompoundFlag;') 764 code('class SimpleFlag;') 765 766 if compound: 767 code('extern CompoundFlag $name;') 768 for flag in compound: 769 code('extern SimpleFlag $flag;') 770 else: 771 code('extern SimpleFlag $name;') 772 773 code(''' 774} 775 776#endif // __DEBUG_${name}_HH__ 777''') 778 779 code.write(str(target[0])) 780 781for name,flag in sorted(debug_flags.iteritems()): 782 n, compound, desc = flag 783 assert n == name 784 785 env.Command('debug/%s.hh' % name, Value(flag), 786 MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) 787 env.Command('debug/%s.cc' % name, Value(flag), 788 MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) 789 Source('debug/%s.cc' % name) 790 791# Embed python files. All .py files that have been indicated by a 792# PySource() call in a SConscript need to be embedded into the M5 793# library. To do that, we compile the file to byte code, marshal the 794# byte code, compress it, and then generate a c++ file that 795# inserts the result into an array. 796def embedPyFile(target, source, env): 797 def c_str(string): 798 if string is None: 799 return "0" 800 return '"%s"' % string 801 802 '''Action function to compile a .py into a code object, marshal 803 it, compress it, and stick it into an asm file so the code appears 804 as just bytes with a label in the data section''' 805 806 src = file(str(source[0]), 'r').read() 807 808 pysource = PySource.tnodes[source[0]] 809 compiled = compile(src, pysource.abspath, 'exec') 810 marshalled = marshal.dumps(compiled) 811 compressed = zlib.compress(marshalled) 812 data = compressed 813 sym = pysource.symname 814 815 code = code_formatter() 816 code('''\ 817#include "sim/init.hh" 818 819namespace { 820 821const char data_${sym}[] = { 822''') 823 code.indent() 824 step = 16 825 for i in xrange(0, len(data), step): 826 x = array.array('B', data[i:i+step]) 827 code(''.join('%d,' % d for d in x)) 828 code.dedent() 829 830 code('''}; 831 832EmbeddedPython embedded_${sym}( 833 ${{c_str(pysource.arcname)}}, 834 ${{c_str(pysource.abspath)}}, 835 ${{c_str(pysource.modpath)}}, 836 data_${sym}, 837 ${{len(data)}}, 838 ${{len(marshalled)}}); 839 840} // anonymous namespace 841''') 842 code.write(str(target[0])) 843 844for source in PySource.all: 845 env.Command(source.cpp, source.tnode, 846 MakeAction(embedPyFile, Transform("EMBED PY"))) 847 Source(source.cpp) 848 849######################################################################## 850# 851# Define binaries. Each different build type (debug, opt, etc.) gets 852# a slightly different build environment. 853# 854 855# List of constructed environments to pass back to SConstruct 856envList = [] 857 858date_source = Source('base/date.cc', skip_lib=True) 859 860# Function to create a new build environment as clone of current 861# environment 'env' with modified object suffix and optional stripped 862# binary. Additional keyword arguments are appended to corresponding 863# build environment vars. 864def makeEnv(label, objsfx, strip = False, **kwargs): 865 # SCons doesn't know to append a library suffix when there is a '.' in the 866 # name. Use '_' instead. 867 libname = 'gem5_' + label 868 exename = 'gem5.' + label 869 secondary_exename = 'm5.' + label 870 871 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') 872 new_env.Label = label 873 new_env.Append(**kwargs) 874 875 swig_env = new_env.Clone() 876 swig_env.Append(CCFLAGS='-Werror') 877 if env['GCC']: 878 swig_env.Append(CCFLAGS='-Wno-uninitialized') 879 swig_env.Append(CCFLAGS='-Wno-sign-compare') 880 swig_env.Append(CCFLAGS='-Wno-parentheses') 881 882 werror_env = new_env.Clone() 883 werror_env.Append(CCFLAGS='-Werror') 884 885 def make_obj(source, static, extra_deps = None): 886 '''This function adds the specified source to the correct 887 build environment, and returns the corresponding SCons Object 888 nodes''' 889 890 if source.swig: 891 env = swig_env 892 elif source.Werror: 893 env = werror_env 894 else: 895 env = new_env 896 897 if static: 898 obj = env.StaticObject(source.tnode) 899 else: 900 obj = env.SharedObject(source.tnode) 901 902 if extra_deps: 903 env.Depends(obj, extra_deps) 904 905 return obj 906 907 static_objs = \ 908 [ make_obj(s, True) for s in Source.get(main=False, skip_lib=False) ] 909 shared_objs = \ 910 [ make_obj(s, False) for s in Source.get(main=False, skip_lib=False) ] 911 912 static_date = make_obj(date_source, static=True, extra_deps=static_objs) 913 static_objs.append(static_date) 914 915 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) 916 shared_objs.append(shared_date) 917 918 # First make a library of everything but main() so other programs can 919 # link against m5. 920 static_lib = new_env.StaticLibrary(libname, static_objs) 921 shared_lib = new_env.SharedLibrary(libname, shared_objs) 922 923 # Now link a stub with main() and the static library. 924 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ] 925 926 for test in UnitTest.all: 927 flags = { test.target : True } 928 test_sources = Source.get(**flags) 929 test_objs = [ make_obj(s, static=True) for s in test_sources ] 930 testname = "unittest/%s.%s" % (test.target, label) 931 new_env.Program(testname, main_objs + test_objs + static_objs) 932 933 progname = exename 934 if strip: 935 progname += '.unstripped' 936 937 targets = new_env.Program(progname, main_objs + static_objs) 938 939 if strip: 940 if sys.platform == 'sunos5': 941 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 942 else: 943 cmd = 'strip $SOURCE -o $TARGET' 944 targets = new_env.Command(exename, progname, 945 MakeAction(cmd, Transform("STRIP"))) 946 947 new_env.Command(secondary_exename, exename, 948 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK"))) 949 950 new_env.M5Binary = targets[0] 951 envList.append(new_env) 952 953# Debug binary 954ccflags = {} 955if env['GCC']: 956 if sys.platform == 'sunos5': 957 ccflags['debug'] = '-gstabs+' 958 else: 959 ccflags['debug'] = '-ggdb3' 960 ccflags['opt'] = '-g -O3' 961 ccflags['fast'] = '-O3' 962 ccflags['prof'] = '-O3 -g -pg' 963elif env['SUNCC']: 964 ccflags['debug'] = '-g0' 965 ccflags['opt'] = '-g -O' 966 ccflags['fast'] = '-fast' 967 ccflags['prof'] = '-fast -g -pg' 968elif env['ICC']: 969 ccflags['debug'] = '-g -O0' 970 ccflags['opt'] = '-g -O' 971 ccflags['fast'] = '-fast' 972 ccflags['prof'] = '-fast -g -pg' 973else: 974 print 'Unknown compiler, please fix compiler options' 975 Exit(1) 976 977makeEnv('debug', '.do', 978 CCFLAGS = Split(ccflags['debug']), 979 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 980 981# Optimized binary 982makeEnv('opt', '.o', 983 CCFLAGS = Split(ccflags['opt']), 984 CPPDEFINES = ['TRACING_ON=1']) 985 986# "Fast" binary 987makeEnv('fast', '.fo', strip = True, 988 CCFLAGS = Split(ccflags['fast']), 989 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 990 991# Profiled binary 992makeEnv('prof', '.po', 993 CCFLAGS = Split(ccflags['prof']), 994 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 995 LINKFLAGS = '-pg') 996 997Return('envList') 998