SConscript (10238:b21b3aad6bd1) SConscript (10278:362875aec1ba)
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, compareVersions
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
152 @staticmethod
153 def done():
154 def disabled(cls, name, *ignored):
155 raise RuntimeError("Additional SourceFile '%s'" % name,\
156 "declared, but targets deps are already fixed.")
157 SourceFile.__init__ = disabled
158
159
160class Source(SourceFile):
161 '''Add a c/c++ source file to the build'''
162 def __init__(self, source, Werror=True, swig=False, **guards):
163 '''specify the source file, and any guards'''
164 super(Source, self).__init__(source, **guards)
165
166 self.Werror = Werror
167 self.swig = swig
168
169class PySource(SourceFile):
170 '''Add a python source file to the named package'''
171 invalid_sym_char = re.compile('[^A-z0-9_]')
172 modules = {}
173 tnodes = {}
174 symnames = {}
175
176 def __init__(self, package, source, **guards):
177 '''specify the python package, the source file, and any guards'''
178 super(PySource, self).__init__(source, **guards)
179
180 modname,ext = self.extname
181 assert ext == 'py'
182
183 if package:
184 path = package.split('.')
185 else:
186 path = []
187
188 modpath = path[:]
189 if modname != '__init__':
190 modpath += [ modname ]
191 modpath = '.'.join(modpath)
192
193 arcpath = path + [ self.basename ]
194 abspath = self.snode.abspath
195 if not exists(abspath):
196 abspath = self.tnode.abspath
197
198 self.package = package
199 self.modname = modname
200 self.modpath = modpath
201 self.arcname = joinpath(*arcpath)
202 self.abspath = abspath
203 self.compiled = File(self.filename + 'c')
204 self.cpp = File(self.filename + '.cc')
205 self.symname = PySource.invalid_sym_char.sub('_', modpath)
206
207 PySource.modules[modpath] = self
208 PySource.tnodes[self.tnode] = self
209 PySource.symnames[self.symname] = self
210
211class SimObject(PySource):
212 '''Add a SimObject python file as a python source object and add
213 it to a list of sim object modules'''
214
215 fixed = False
216 modnames = []
217
218 def __init__(self, source, **guards):
219 '''Specify the source file and any guards (automatically in
220 the m5.objects package)'''
221 super(SimObject, self).__init__('m5.objects', source, **guards)
222 if self.fixed:
223 raise AttributeError, "Too late to call SimObject now."
224
225 bisect.insort_right(SimObject.modnames, self.modname)
226
227class SwigSource(SourceFile):
228 '''Add a swig file to build'''
229
230 def __init__(self, package, source, **guards):
231 '''Specify the python package, the source file, and any guards'''
232 super(SwigSource, self).__init__(source, **guards)
233
234 modname,ext = self.extname
235 assert ext == 'i'
236
237 self.module = modname
238 cc_file = joinpath(self.dirname, modname + '_wrap.cc')
239 py_file = joinpath(self.dirname, modname + '.py')
240
241 self.cc_source = Source(cc_file, swig=True, parent=self)
242 self.py_source = PySource(package, py_file, parent=self)
243
244class ProtoBuf(SourceFile):
245 '''Add a Protocol Buffer to build'''
246
247 def __init__(self, source, **guards):
248 '''Specify the source file, and any guards'''
249 super(ProtoBuf, self).__init__(source, **guards)
250
251 # Get the file name and the extension
252 modname,ext = self.extname
253 assert ext == 'proto'
254
255 # Currently, we stick to generating the C++ headers, so we
256 # only need to track the source and header.
257 self.cc_file = File(modname + '.pb.cc')
258 self.hh_file = File(modname + '.pb.h')
259
260class UnitTest(object):
261 '''Create a UnitTest'''
262
263 all = []
264 def __init__(self, target, *sources, **kwargs):
265 '''Specify the target name and any sources. Sources that are
266 not SourceFiles are evalued with Source(). All files are
267 guarded with a guard of the same name as the UnitTest
268 target.'''
269
270 srcs = []
271 for src in sources:
272 if not isinstance(src, SourceFile):
273 src = Source(src, skip_lib=True)
274 src.guards[target] = True
275 srcs.append(src)
276
277 self.sources = srcs
278 self.target = target
279 self.main = kwargs.get('main', False)
280 UnitTest.all.append(self)
281
282# Children should have access
283Export('Source')
284Export('PySource')
285Export('SimObject')
286Export('SwigSource')
287Export('ProtoBuf')
288Export('UnitTest')
289
290########################################################################
291#
292# Debug Flags
293#
294debug_flags = {}
295def DebugFlag(name, desc=None):
296 if name in debug_flags:
297 raise AttributeError, "Flag %s already specified" % name
298 debug_flags[name] = (name, (), desc)
299
300def CompoundFlag(name, flags, desc=None):
301 if name in debug_flags:
302 raise AttributeError, "Flag %s already specified" % name
303
304 compound = tuple(flags)
305 debug_flags[name] = (name, compound, desc)
306
307Export('DebugFlag')
308Export('CompoundFlag')
309
310########################################################################
311#
312# Set some compiler variables
313#
314
315# Include file paths are rooted in this directory. SCons will
316# automatically expand '.' to refer to both the source directory and
317# the corresponding build directory to pick up generated include
318# files.
319env.Append(CPPPATH=Dir('.'))
320
321for extra_dir in extras_dir_list:
322 env.Append(CPPPATH=Dir(extra_dir))
323
324# Workaround for bug in SCons version > 0.97d20071212
325# Scons bug id: 2006 gem5 Bug id: 308
326for root, dirs, files in os.walk(base_dir, topdown=True):
327 Dir(root[len(base_dir) + 1:])
328
329########################################################################
330#
331# Walk the tree and execute all SConscripts in subdirectories
332#
333
334here = Dir('.').srcnode().abspath
335for root, dirs, files in os.walk(base_dir, topdown=True):
336 if root == here:
337 # we don't want to recurse back into this SConscript
338 continue
339
340 if 'SConscript' in files:
341 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
342 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
343
344for extra_dir in extras_dir_list:
345 prefix_len = len(dirname(extra_dir)) + 1
346
347 # Also add the corresponding build directory to pick up generated
348 # include files.
349 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:])))
350
351 for root, dirs, files in os.walk(extra_dir, topdown=True):
352 # if build lives in the extras directory, don't walk down it
353 if 'build' in dirs:
354 dirs.remove('build')
355
356 if 'SConscript' in files:
357 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
358 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
359
360for opt in export_vars:
361 env.ConfigFile(opt)
362
363def makeTheISA(source, target, env):
364 isas = [ src.get_contents() for src in source ]
365 target_isa = env['TARGET_ISA']
366 def define(isa):
367 return isa.upper() + '_ISA'
368
369 def namespace(isa):
370 return isa[0].upper() + isa[1:].lower() + 'ISA'
371
372
373 code = code_formatter()
374 code('''\
375#ifndef __CONFIG_THE_ISA_HH__
376#define __CONFIG_THE_ISA_HH__
377
378''')
379
380 for i,isa in enumerate(isas):
381 code('#define $0 $1', define(isa), i + 1)
382
383 code('''
384
385#define THE_ISA ${{define(target_isa)}}
386#define TheISA ${{namespace(target_isa)}}
387#define THE_ISA_STR "${{target_isa}}"
388
389#endif // __CONFIG_THE_ISA_HH__''')
390
391 code.write(str(target[0]))
392
393env.Command('config/the_isa.hh', map(Value, all_isa_list),
394 MakeAction(makeTheISA, Transform("CFG ISA", 0)))
395
396########################################################################
397#
398# Prevent any SimObjects from being added after this point, they
399# should all have been added in the SConscripts above
400#
401SimObject.fixed = True
402
403class DictImporter(object):
404 '''This importer takes a dictionary of arbitrary module names that
405 map to arbitrary filenames.'''
406 def __init__(self, modules):
407 self.modules = modules
408 self.installed = set()
409
410 def __del__(self):
411 self.unload()
412
413 def unload(self):
414 import sys
415 for module in self.installed:
416 del sys.modules[module]
417 self.installed = set()
418
419 def find_module(self, fullname, path):
420 if fullname == 'm5.defines':
421 return self
422
423 if fullname == 'm5.objects':
424 return self
425
426 if fullname.startswith('m5.internal'):
427 return None
428
429 source = self.modules.get(fullname, None)
430 if source is not None and fullname.startswith('m5.objects'):
431 return self
432
433 return None
434
435 def load_module(self, fullname):
436 mod = imp.new_module(fullname)
437 sys.modules[fullname] = mod
438 self.installed.add(fullname)
439
440 mod.__loader__ = self
441 if fullname == 'm5.objects':
442 mod.__path__ = fullname.split('.')
443 return mod
444
445 if fullname == 'm5.defines':
446 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
447 return mod
448
449 source = self.modules[fullname]
450 if source.modname == '__init__':
451 mod.__path__ = source.modpath
452 mod.__file__ = source.abspath
453
454 exec file(source.abspath, 'r') in mod.__dict__
455
456 return mod
457
458import m5.SimObject
459import m5.params
460from m5.util import code_formatter
461
462m5.SimObject.clear()
463m5.params.clear()
464
465# install the python importer so we can grab stuff from the source
466# tree itself. We can't have SimObjects added after this point or
467# else we won't know about them for the rest of the stuff.
468importer = DictImporter(PySource.modules)
469sys.meta_path[0:0] = [ importer ]
470
471# import all sim objects so we can populate the all_objects list
472# make sure that we're working with a list, then let's sort it
473for modname in SimObject.modnames:
474 exec('from m5.objects import %s' % modname)
475
476# we need to unload all of the currently imported modules so that they
477# will be re-imported the next time the sconscript is run
478importer.unload()
479sys.meta_path.remove(importer)
480
481sim_objects = m5.SimObject.allClasses
482all_enums = m5.params.allEnums
483
484if m5.SimObject.noCxxHeader:
485 print >> sys.stderr, \
486 "warning: At least one SimObject lacks a header specification. " \
487 "This can cause unexpected results in the generated SWIG " \
488 "wrappers."
489
490# Find param types that need to be explicitly wrapped with swig.
491# These will be recognized because the ParamDesc will have a
492# swig_decl() method. Most param types are based on types that don't
493# need this, either because they're based on native types (like Int)
494# or because they're SimObjects (which get swigged independently).
495# For now the only things handled here are VectorParam types.
496params_to_swig = {}
497for name,obj in sorted(sim_objects.iteritems()):
498 for param in obj._params.local.values():
499 # load the ptype attribute now because it depends on the
500 # current version of SimObject.allClasses, but when scons
501 # actually uses the value, all versions of
502 # SimObject.allClasses will have been loaded
503 param.ptype
504
505 if not hasattr(param, 'swig_decl'):
506 continue
507 pname = param.ptype_str
508 if pname not in params_to_swig:
509 params_to_swig[pname] = param
510
511########################################################################
512#
513# calculate extra dependencies
514#
515module_depends = ["m5", "m5.SimObject", "m5.params"]
516depends = [ PySource.modules[dep].snode for dep in module_depends ]
517
518########################################################################
519#
520# Commands for the basic automatically generated python files
521#
522
523# Generate Python file containing a dict specifying the current
524# buildEnv flags.
525def makeDefinesPyFile(target, source, env):
526 build_env = source[0].get_contents()
527
528 code = code_formatter()
529 code("""
530import m5.internal
531import m5.util
532
533buildEnv = m5.util.SmartDict($build_env)
534
535compileDate = m5.internal.core.compileDate
536_globals = globals()
537for key,val in m5.internal.core.__dict__.iteritems():
538 if key.startswith('flag_'):
539 flag = key[5:]
540 _globals[flag] = val
541del _globals
542""")
543 code.write(target[0].abspath)
544
545defines_info = Value(build_env)
546# Generate a file with all of the compile options in it
547env.Command('python/m5/defines.py', defines_info,
548 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
549PySource('m5', 'python/m5/defines.py')
550
551# Generate python file containing info about the M5 source code
552def makeInfoPyFile(target, source, env):
553 code = code_formatter()
554 for src in source:
555 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
556 code('$src = ${{repr(data)}}')
557 code.write(str(target[0]))
558
559# Generate a file that wraps the basic top level files
560env.Command('python/m5/info.py',
561 [ '#/COPYING', '#/LICENSE', '#/README', ],
562 MakeAction(makeInfoPyFile, Transform("INFO")))
563PySource('m5', 'python/m5/info.py')
564
565########################################################################
566#
567# Create all of the SimObject param headers and enum headers
568#
569
570def createSimObjectParamStruct(target, source, env):
571 assert len(target) == 1 and len(source) == 1
572
573 name = str(source[0].get_contents())
574 obj = sim_objects[name]
575
576 code = code_formatter()
577 obj.cxx_param_decl(code)
578 code.write(target[0].abspath)
579
580def createParamSwigWrapper(target, source, env):
581 assert len(target) == 1 and len(source) == 1
582
583 name = str(source[0].get_contents())
584 param = params_to_swig[name]
585
586 code = code_formatter()
587 param.swig_decl(code)
588 code.write(target[0].abspath)
589
590def createEnumStrings(target, source, env):
591 assert len(target) == 1 and len(source) == 1
592
593 name = str(source[0].get_contents())
594 obj = all_enums[name]
595
596 code = code_formatter()
597 obj.cxx_def(code)
598 code.write(target[0].abspath)
599
600def createEnumDecls(target, source, env):
601 assert len(target) == 1 and len(source) == 1
602
603 name = str(source[0].get_contents())
604 obj = all_enums[name]
605
606 code = code_formatter()
607 obj.cxx_decl(code)
608 code.write(target[0].abspath)
609
610def createEnumSwigWrapper(target, source, env):
611 assert len(target) == 1 and len(source) == 1
612
613 name = str(source[0].get_contents())
614 obj = all_enums[name]
615
616 code = code_formatter()
617 obj.swig_decl(code)
618 code.write(target[0].abspath)
619
620def createSimObjectSwigWrapper(target, source, env):
621 name = source[0].get_contents()
622 obj = sim_objects[name]
623
624 code = code_formatter()
625 obj.swig_decl(code)
626 code.write(target[0].abspath)
627
628# Generate all of the SimObject param C++ struct header files
629params_hh_files = []
630for name,simobj in sorted(sim_objects.iteritems()):
631 py_source = PySource.modules[simobj.__module__]
632 extra_deps = [ py_source.tnode ]
633
634 hh_file = File('params/%s.hh' % name)
635 params_hh_files.append(hh_file)
636 env.Command(hh_file, Value(name),
637 MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
638 env.Depends(hh_file, depends + extra_deps)
639
640# Generate any needed param SWIG wrapper files
641params_i_files = []
642for name,param in params_to_swig.iteritems():
643 i_file = File('python/m5/internal/%s.i' % (param.swig_module_name()))
644 params_i_files.append(i_file)
645 env.Command(i_file, Value(name),
646 MakeAction(createParamSwigWrapper, Transform("SW PARAM")))
647 env.Depends(i_file, depends)
648 SwigSource('m5.internal', i_file)
649
650# Generate all enum header files
651for name,enum in sorted(all_enums.iteritems()):
652 py_source = PySource.modules[enum.__module__]
653 extra_deps = [ py_source.tnode ]
654
655 cc_file = File('enums/%s.cc' % name)
656 env.Command(cc_file, Value(name),
657 MakeAction(createEnumStrings, Transform("ENUM STR")))
658 env.Depends(cc_file, depends + extra_deps)
659 Source(cc_file)
660
661 hh_file = File('enums/%s.hh' % name)
662 env.Command(hh_file, Value(name),
663 MakeAction(createEnumDecls, Transform("ENUMDECL")))
664 env.Depends(hh_file, depends + extra_deps)
665
666 i_file = File('python/m5/internal/enum_%s.i' % name)
667 env.Command(i_file, Value(name),
668 MakeAction(createEnumSwigWrapper, Transform("ENUMSWIG")))
669 env.Depends(i_file, depends + extra_deps)
670 SwigSource('m5.internal', i_file)
671
672# Generate SimObject SWIG wrapper files
673for name,simobj in sim_objects.iteritems():
674 py_source = PySource.modules[simobj.__module__]
675 extra_deps = [ py_source.tnode ]
676
677 i_file = File('python/m5/internal/param_%s.i' % name)
678 env.Command(i_file, Value(name),
679 MakeAction(createSimObjectSwigWrapper, Transform("SO SWIG")))
680 env.Depends(i_file, depends + extra_deps)
681 SwigSource('m5.internal', i_file)
682
683# Generate the main swig init file
684def makeEmbeddedSwigInit(target, source, env):
685 code = code_formatter()
686 module = source[0].get_contents()
687 code('''\
688#include "sim/init.hh"
689
690extern "C" {
691 void init_${module}();
692}
693
694EmbeddedSwig embed_swig_${module}(init_${module});
695''')
696 code.write(str(target[0]))
697
698# Build all swig modules
699for swig in SwigSource.all:
700 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
701 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
702 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG")))
703 cc_file = str(swig.tnode)
704 init_file = '%s/%s_init.cc' % (dirname(cc_file), basename(cc_file))
705 env.Command(init_file, Value(swig.module),
706 MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW")))
707 Source(init_file, **swig.guards)
708
709# Build all protocol buffers if we have got protoc and protobuf available
710if env['HAVE_PROTOBUF']:
711 for proto in ProtoBuf.all:
712 # Use both the source and header as the target, and the .proto
713 # file as the source. When executing the protoc compiler, also
714 # specify the proto_path to avoid having the generated files
715 # include the path.
716 env.Command([proto.cc_file, proto.hh_file], proto.tnode,
717 MakeAction('$PROTOC --cpp_out ${TARGET.dir} '
718 '--proto_path ${SOURCE.dir} $SOURCE',
719 Transform("PROTOC")))
720
721 # Add the C++ source file
722 Source(proto.cc_file, **proto.guards)
723elif ProtoBuf.all:
724 print 'Got protobuf to build, but lacks support!'
725 Exit(1)
726
727#
728# Handle debug flags
729#
730def makeDebugFlagCC(target, source, env):
731 assert(len(target) == 1 and len(source) == 1)
732
733 val = eval(source[0].get_contents())
734 name, compound, desc = val
735 compound = list(sorted(compound))
736
737 code = code_formatter()
738
739 # file header
740 code('''
741/*
742 * DO NOT EDIT THIS FILE! Automatically generated
743 */
744
745#include "base/debug.hh"
746''')
747
748 for flag in compound:
749 code('#include "debug/$flag.hh"')
750 code()
751 code('namespace Debug {')
752 code()
753
754 if not compound:
755 code('SimpleFlag $name("$name", "$desc");')
756 else:
757 code('CompoundFlag $name("$name", "$desc",')
758 code.indent()
759 last = len(compound) - 1
760 for i,flag in enumerate(compound):
761 if i != last:
762 code('$flag,')
763 else:
764 code('$flag);')
765 code.dedent()
766
767 code()
768 code('} // namespace Debug')
769
770 code.write(str(target[0]))
771
772def makeDebugFlagHH(target, source, env):
773 assert(len(target) == 1 and len(source) == 1)
774
775 val = eval(source[0].get_contents())
776 name, compound, desc = val
777
778 code = code_formatter()
779
780 # file header boilerplate
781 code('''\
782/*
783 * DO NOT EDIT THIS FILE!
784 *
785 * Automatically generated by SCons
786 */
787
788#ifndef __DEBUG_${name}_HH__
789#define __DEBUG_${name}_HH__
790
791namespace Debug {
792''')
793
794 if compound:
795 code('class CompoundFlag;')
796 code('class SimpleFlag;')
797
798 if compound:
799 code('extern CompoundFlag $name;')
800 for flag in compound:
801 code('extern SimpleFlag $flag;')
802 else:
803 code('extern SimpleFlag $name;')
804
805 code('''
806}
807
808#endif // __DEBUG_${name}_HH__
809''')
810
811 code.write(str(target[0]))
812
813for name,flag in sorted(debug_flags.iteritems()):
814 n, compound, desc = flag
815 assert n == name
816
817 env.Command('debug/%s.hh' % name, Value(flag),
818 MakeAction(makeDebugFlagHH, Transform("TRACING", 0)))
819 env.Command('debug/%s.cc' % name, Value(flag),
820 MakeAction(makeDebugFlagCC, Transform("TRACING", 0)))
821 Source('debug/%s.cc' % name)
822
823# Embed python files. All .py files that have been indicated by a
824# PySource() call in a SConscript need to be embedded into the M5
825# library. To do that, we compile the file to byte code, marshal the
826# byte code, compress it, and then generate a c++ file that
827# inserts the result into an array.
828def embedPyFile(target, source, env):
829 def c_str(string):
830 if string is None:
831 return "0"
832 return '"%s"' % string
833
834 '''Action function to compile a .py into a code object, marshal
835 it, compress it, and stick it into an asm file so the code appears
836 as just bytes with a label in the data section'''
837
838 src = file(str(source[0]), 'r').read()
839
840 pysource = PySource.tnodes[source[0]]
841 compiled = compile(src, pysource.abspath, 'exec')
842 marshalled = marshal.dumps(compiled)
843 compressed = zlib.compress(marshalled)
844 data = compressed
845 sym = pysource.symname
846
847 code = code_formatter()
848 code('''\
849#include "sim/init.hh"
850
851namespace {
852
853const uint8_t data_${sym}[] = {
854''')
855 code.indent()
856 step = 16
857 for i in xrange(0, len(data), step):
858 x = array.array('B', data[i:i+step])
859 code(''.join('%d,' % d for d in x))
860 code.dedent()
861
862 code('''};
863
864EmbeddedPython embedded_${sym}(
865 ${{c_str(pysource.arcname)}},
866 ${{c_str(pysource.abspath)}},
867 ${{c_str(pysource.modpath)}},
868 data_${sym},
869 ${{len(data)}},
870 ${{len(marshalled)}});
871
872} // anonymous namespace
873''')
874 code.write(str(target[0]))
875
876for source in PySource.all:
877 env.Command(source.cpp, source.tnode,
878 MakeAction(embedPyFile, Transform("EMBED PY")))
879 Source(source.cpp)
880
881########################################################################
882#
883# Define binaries. Each different build type (debug, opt, etc.) gets
884# a slightly different build environment.
885#
886
887# List of constructed environments to pass back to SConstruct
888date_source = Source('base/date.cc', skip_lib=True)
889
890# Capture this directory for the closure makeEnv, otherwise when it is
891# called, it won't know what directory it should use.
892variant_dir = Dir('.').path
893def variant(*path):
894 return os.path.join(variant_dir, *path)
895def variantd(*path):
896 return variant(*path)+'/'
897
898# Function to create a new build environment as clone of current
899# environment 'env' with modified object suffix and optional stripped
900# binary. Additional keyword arguments are appended to corresponding
901# build environment vars.
902def makeEnv(env, label, objsfx, strip = False, **kwargs):
903 # SCons doesn't know to append a library suffix when there is a '.' in the
904 # name. Use '_' instead.
905 libname = variant('gem5_' + label)
906 exename = variant('gem5.' + label)
907 secondary_exename = variant('m5.' + label)
908
909 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
910 new_env.Label = label
911 new_env.Append(**kwargs)
912
913 swig_env = new_env.Clone()
914
915 # Both gcc and clang have issues with unused labels and values in
916 # the SWIG generated code
917 swig_env.Append(CCFLAGS=['-Wno-unused-label', '-Wno-unused-value'])
918
919 # Add additional warnings here that should not be applied to
920 # the SWIG generated code
921 new_env.Append(CXXFLAGS='-Wmissing-declarations')
922
923 if env['GCC']:
924 # Depending on the SWIG version, we also need to supress
925 # warnings about uninitialized variables and missing field
926 # initializers.
927 swig_env.Append(CCFLAGS=['-Wno-uninitialized',
928 '-Wno-missing-field-initializers',
929 '-Wno-unused-but-set-variable'])
930
931 # If gcc supports it, also warn for deletion of derived
932 # classes with non-virtual desctructors. For gcc >= 4.7 we
933 # also have to disable warnings about the SWIG code having
934 # potentially uninitialized variables.
935 if compareVersions(env['GCC_VERSION'], '4.7') >= 0:
936 new_env.Append(CXXFLAGS='-Wdelete-non-virtual-dtor')
937 swig_env.Append(CCFLAGS='-Wno-maybe-uninitialized')
938 if env['CLANG']:
939 # Always enable the warning for deletion of derived classes
940 # with non-virtual destructors
941 new_env.Append(CXXFLAGS=['-Wdelete-non-virtual-dtor'])
942
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, compareVersions
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
152 @staticmethod
153 def done():
154 def disabled(cls, name, *ignored):
155 raise RuntimeError("Additional SourceFile '%s'" % name,\
156 "declared, but targets deps are already fixed.")
157 SourceFile.__init__ = disabled
158
159
160class Source(SourceFile):
161 '''Add a c/c++ source file to the build'''
162 def __init__(self, source, Werror=True, swig=False, **guards):
163 '''specify the source file, and any guards'''
164 super(Source, self).__init__(source, **guards)
165
166 self.Werror = Werror
167 self.swig = swig
168
169class PySource(SourceFile):
170 '''Add a python source file to the named package'''
171 invalid_sym_char = re.compile('[^A-z0-9_]')
172 modules = {}
173 tnodes = {}
174 symnames = {}
175
176 def __init__(self, package, source, **guards):
177 '''specify the python package, the source file, and any guards'''
178 super(PySource, self).__init__(source, **guards)
179
180 modname,ext = self.extname
181 assert ext == 'py'
182
183 if package:
184 path = package.split('.')
185 else:
186 path = []
187
188 modpath = path[:]
189 if modname != '__init__':
190 modpath += [ modname ]
191 modpath = '.'.join(modpath)
192
193 arcpath = path + [ self.basename ]
194 abspath = self.snode.abspath
195 if not exists(abspath):
196 abspath = self.tnode.abspath
197
198 self.package = package
199 self.modname = modname
200 self.modpath = modpath
201 self.arcname = joinpath(*arcpath)
202 self.abspath = abspath
203 self.compiled = File(self.filename + 'c')
204 self.cpp = File(self.filename + '.cc')
205 self.symname = PySource.invalid_sym_char.sub('_', modpath)
206
207 PySource.modules[modpath] = self
208 PySource.tnodes[self.tnode] = self
209 PySource.symnames[self.symname] = self
210
211class SimObject(PySource):
212 '''Add a SimObject python file as a python source object and add
213 it to a list of sim object modules'''
214
215 fixed = False
216 modnames = []
217
218 def __init__(self, source, **guards):
219 '''Specify the source file and any guards (automatically in
220 the m5.objects package)'''
221 super(SimObject, self).__init__('m5.objects', source, **guards)
222 if self.fixed:
223 raise AttributeError, "Too late to call SimObject now."
224
225 bisect.insort_right(SimObject.modnames, self.modname)
226
227class SwigSource(SourceFile):
228 '''Add a swig file to build'''
229
230 def __init__(self, package, source, **guards):
231 '''Specify the python package, the source file, and any guards'''
232 super(SwigSource, self).__init__(source, **guards)
233
234 modname,ext = self.extname
235 assert ext == 'i'
236
237 self.module = modname
238 cc_file = joinpath(self.dirname, modname + '_wrap.cc')
239 py_file = joinpath(self.dirname, modname + '.py')
240
241 self.cc_source = Source(cc_file, swig=True, parent=self)
242 self.py_source = PySource(package, py_file, parent=self)
243
244class ProtoBuf(SourceFile):
245 '''Add a Protocol Buffer to build'''
246
247 def __init__(self, source, **guards):
248 '''Specify the source file, and any guards'''
249 super(ProtoBuf, self).__init__(source, **guards)
250
251 # Get the file name and the extension
252 modname,ext = self.extname
253 assert ext == 'proto'
254
255 # Currently, we stick to generating the C++ headers, so we
256 # only need to track the source and header.
257 self.cc_file = File(modname + '.pb.cc')
258 self.hh_file = File(modname + '.pb.h')
259
260class UnitTest(object):
261 '''Create a UnitTest'''
262
263 all = []
264 def __init__(self, target, *sources, **kwargs):
265 '''Specify the target name and any sources. Sources that are
266 not SourceFiles are evalued with Source(). All files are
267 guarded with a guard of the same name as the UnitTest
268 target.'''
269
270 srcs = []
271 for src in sources:
272 if not isinstance(src, SourceFile):
273 src = Source(src, skip_lib=True)
274 src.guards[target] = True
275 srcs.append(src)
276
277 self.sources = srcs
278 self.target = target
279 self.main = kwargs.get('main', False)
280 UnitTest.all.append(self)
281
282# Children should have access
283Export('Source')
284Export('PySource')
285Export('SimObject')
286Export('SwigSource')
287Export('ProtoBuf')
288Export('UnitTest')
289
290########################################################################
291#
292# Debug Flags
293#
294debug_flags = {}
295def DebugFlag(name, desc=None):
296 if name in debug_flags:
297 raise AttributeError, "Flag %s already specified" % name
298 debug_flags[name] = (name, (), desc)
299
300def CompoundFlag(name, flags, desc=None):
301 if name in debug_flags:
302 raise AttributeError, "Flag %s already specified" % name
303
304 compound = tuple(flags)
305 debug_flags[name] = (name, compound, desc)
306
307Export('DebugFlag')
308Export('CompoundFlag')
309
310########################################################################
311#
312# Set some compiler variables
313#
314
315# Include file paths are rooted in this directory. SCons will
316# automatically expand '.' to refer to both the source directory and
317# the corresponding build directory to pick up generated include
318# files.
319env.Append(CPPPATH=Dir('.'))
320
321for extra_dir in extras_dir_list:
322 env.Append(CPPPATH=Dir(extra_dir))
323
324# Workaround for bug in SCons version > 0.97d20071212
325# Scons bug id: 2006 gem5 Bug id: 308
326for root, dirs, files in os.walk(base_dir, topdown=True):
327 Dir(root[len(base_dir) + 1:])
328
329########################################################################
330#
331# Walk the tree and execute all SConscripts in subdirectories
332#
333
334here = Dir('.').srcnode().abspath
335for root, dirs, files in os.walk(base_dir, topdown=True):
336 if root == here:
337 # we don't want to recurse back into this SConscript
338 continue
339
340 if 'SConscript' in files:
341 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
342 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
343
344for extra_dir in extras_dir_list:
345 prefix_len = len(dirname(extra_dir)) + 1
346
347 # Also add the corresponding build directory to pick up generated
348 # include files.
349 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:])))
350
351 for root, dirs, files in os.walk(extra_dir, topdown=True):
352 # if build lives in the extras directory, don't walk down it
353 if 'build' in dirs:
354 dirs.remove('build')
355
356 if 'SConscript' in files:
357 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
358 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
359
360for opt in export_vars:
361 env.ConfigFile(opt)
362
363def makeTheISA(source, target, env):
364 isas = [ src.get_contents() for src in source ]
365 target_isa = env['TARGET_ISA']
366 def define(isa):
367 return isa.upper() + '_ISA'
368
369 def namespace(isa):
370 return isa[0].upper() + isa[1:].lower() + 'ISA'
371
372
373 code = code_formatter()
374 code('''\
375#ifndef __CONFIG_THE_ISA_HH__
376#define __CONFIG_THE_ISA_HH__
377
378''')
379
380 for i,isa in enumerate(isas):
381 code('#define $0 $1', define(isa), i + 1)
382
383 code('''
384
385#define THE_ISA ${{define(target_isa)}}
386#define TheISA ${{namespace(target_isa)}}
387#define THE_ISA_STR "${{target_isa}}"
388
389#endif // __CONFIG_THE_ISA_HH__''')
390
391 code.write(str(target[0]))
392
393env.Command('config/the_isa.hh', map(Value, all_isa_list),
394 MakeAction(makeTheISA, Transform("CFG ISA", 0)))
395
396########################################################################
397#
398# Prevent any SimObjects from being added after this point, they
399# should all have been added in the SConscripts above
400#
401SimObject.fixed = True
402
403class DictImporter(object):
404 '''This importer takes a dictionary of arbitrary module names that
405 map to arbitrary filenames.'''
406 def __init__(self, modules):
407 self.modules = modules
408 self.installed = set()
409
410 def __del__(self):
411 self.unload()
412
413 def unload(self):
414 import sys
415 for module in self.installed:
416 del sys.modules[module]
417 self.installed = set()
418
419 def find_module(self, fullname, path):
420 if fullname == 'm5.defines':
421 return self
422
423 if fullname == 'm5.objects':
424 return self
425
426 if fullname.startswith('m5.internal'):
427 return None
428
429 source = self.modules.get(fullname, None)
430 if source is not None and fullname.startswith('m5.objects'):
431 return self
432
433 return None
434
435 def load_module(self, fullname):
436 mod = imp.new_module(fullname)
437 sys.modules[fullname] = mod
438 self.installed.add(fullname)
439
440 mod.__loader__ = self
441 if fullname == 'm5.objects':
442 mod.__path__ = fullname.split('.')
443 return mod
444
445 if fullname == 'm5.defines':
446 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
447 return mod
448
449 source = self.modules[fullname]
450 if source.modname == '__init__':
451 mod.__path__ = source.modpath
452 mod.__file__ = source.abspath
453
454 exec file(source.abspath, 'r') in mod.__dict__
455
456 return mod
457
458import m5.SimObject
459import m5.params
460from m5.util import code_formatter
461
462m5.SimObject.clear()
463m5.params.clear()
464
465# install the python importer so we can grab stuff from the source
466# tree itself. We can't have SimObjects added after this point or
467# else we won't know about them for the rest of the stuff.
468importer = DictImporter(PySource.modules)
469sys.meta_path[0:0] = [ importer ]
470
471# import all sim objects so we can populate the all_objects list
472# make sure that we're working with a list, then let's sort it
473for modname in SimObject.modnames:
474 exec('from m5.objects import %s' % modname)
475
476# we need to unload all of the currently imported modules so that they
477# will be re-imported the next time the sconscript is run
478importer.unload()
479sys.meta_path.remove(importer)
480
481sim_objects = m5.SimObject.allClasses
482all_enums = m5.params.allEnums
483
484if m5.SimObject.noCxxHeader:
485 print >> sys.stderr, \
486 "warning: At least one SimObject lacks a header specification. " \
487 "This can cause unexpected results in the generated SWIG " \
488 "wrappers."
489
490# Find param types that need to be explicitly wrapped with swig.
491# These will be recognized because the ParamDesc will have a
492# swig_decl() method. Most param types are based on types that don't
493# need this, either because they're based on native types (like Int)
494# or because they're SimObjects (which get swigged independently).
495# For now the only things handled here are VectorParam types.
496params_to_swig = {}
497for name,obj in sorted(sim_objects.iteritems()):
498 for param in obj._params.local.values():
499 # load the ptype attribute now because it depends on the
500 # current version of SimObject.allClasses, but when scons
501 # actually uses the value, all versions of
502 # SimObject.allClasses will have been loaded
503 param.ptype
504
505 if not hasattr(param, 'swig_decl'):
506 continue
507 pname = param.ptype_str
508 if pname not in params_to_swig:
509 params_to_swig[pname] = param
510
511########################################################################
512#
513# calculate extra dependencies
514#
515module_depends = ["m5", "m5.SimObject", "m5.params"]
516depends = [ PySource.modules[dep].snode for dep in module_depends ]
517
518########################################################################
519#
520# Commands for the basic automatically generated python files
521#
522
523# Generate Python file containing a dict specifying the current
524# buildEnv flags.
525def makeDefinesPyFile(target, source, env):
526 build_env = source[0].get_contents()
527
528 code = code_formatter()
529 code("""
530import m5.internal
531import m5.util
532
533buildEnv = m5.util.SmartDict($build_env)
534
535compileDate = m5.internal.core.compileDate
536_globals = globals()
537for key,val in m5.internal.core.__dict__.iteritems():
538 if key.startswith('flag_'):
539 flag = key[5:]
540 _globals[flag] = val
541del _globals
542""")
543 code.write(target[0].abspath)
544
545defines_info = Value(build_env)
546# Generate a file with all of the compile options in it
547env.Command('python/m5/defines.py', defines_info,
548 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
549PySource('m5', 'python/m5/defines.py')
550
551# Generate python file containing info about the M5 source code
552def makeInfoPyFile(target, source, env):
553 code = code_formatter()
554 for src in source:
555 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
556 code('$src = ${{repr(data)}}')
557 code.write(str(target[0]))
558
559# Generate a file that wraps the basic top level files
560env.Command('python/m5/info.py',
561 [ '#/COPYING', '#/LICENSE', '#/README', ],
562 MakeAction(makeInfoPyFile, Transform("INFO")))
563PySource('m5', 'python/m5/info.py')
564
565########################################################################
566#
567# Create all of the SimObject param headers and enum headers
568#
569
570def createSimObjectParamStruct(target, source, env):
571 assert len(target) == 1 and len(source) == 1
572
573 name = str(source[0].get_contents())
574 obj = sim_objects[name]
575
576 code = code_formatter()
577 obj.cxx_param_decl(code)
578 code.write(target[0].abspath)
579
580def createParamSwigWrapper(target, source, env):
581 assert len(target) == 1 and len(source) == 1
582
583 name = str(source[0].get_contents())
584 param = params_to_swig[name]
585
586 code = code_formatter()
587 param.swig_decl(code)
588 code.write(target[0].abspath)
589
590def createEnumStrings(target, source, env):
591 assert len(target) == 1 and len(source) == 1
592
593 name = str(source[0].get_contents())
594 obj = all_enums[name]
595
596 code = code_formatter()
597 obj.cxx_def(code)
598 code.write(target[0].abspath)
599
600def createEnumDecls(target, source, env):
601 assert len(target) == 1 and len(source) == 1
602
603 name = str(source[0].get_contents())
604 obj = all_enums[name]
605
606 code = code_formatter()
607 obj.cxx_decl(code)
608 code.write(target[0].abspath)
609
610def createEnumSwigWrapper(target, source, env):
611 assert len(target) == 1 and len(source) == 1
612
613 name = str(source[0].get_contents())
614 obj = all_enums[name]
615
616 code = code_formatter()
617 obj.swig_decl(code)
618 code.write(target[0].abspath)
619
620def createSimObjectSwigWrapper(target, source, env):
621 name = source[0].get_contents()
622 obj = sim_objects[name]
623
624 code = code_formatter()
625 obj.swig_decl(code)
626 code.write(target[0].abspath)
627
628# Generate all of the SimObject param C++ struct header files
629params_hh_files = []
630for name,simobj in sorted(sim_objects.iteritems()):
631 py_source = PySource.modules[simobj.__module__]
632 extra_deps = [ py_source.tnode ]
633
634 hh_file = File('params/%s.hh' % name)
635 params_hh_files.append(hh_file)
636 env.Command(hh_file, Value(name),
637 MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
638 env.Depends(hh_file, depends + extra_deps)
639
640# Generate any needed param SWIG wrapper files
641params_i_files = []
642for name,param in params_to_swig.iteritems():
643 i_file = File('python/m5/internal/%s.i' % (param.swig_module_name()))
644 params_i_files.append(i_file)
645 env.Command(i_file, Value(name),
646 MakeAction(createParamSwigWrapper, Transform("SW PARAM")))
647 env.Depends(i_file, depends)
648 SwigSource('m5.internal', i_file)
649
650# Generate all enum header files
651for name,enum in sorted(all_enums.iteritems()):
652 py_source = PySource.modules[enum.__module__]
653 extra_deps = [ py_source.tnode ]
654
655 cc_file = File('enums/%s.cc' % name)
656 env.Command(cc_file, Value(name),
657 MakeAction(createEnumStrings, Transform("ENUM STR")))
658 env.Depends(cc_file, depends + extra_deps)
659 Source(cc_file)
660
661 hh_file = File('enums/%s.hh' % name)
662 env.Command(hh_file, Value(name),
663 MakeAction(createEnumDecls, Transform("ENUMDECL")))
664 env.Depends(hh_file, depends + extra_deps)
665
666 i_file = File('python/m5/internal/enum_%s.i' % name)
667 env.Command(i_file, Value(name),
668 MakeAction(createEnumSwigWrapper, Transform("ENUMSWIG")))
669 env.Depends(i_file, depends + extra_deps)
670 SwigSource('m5.internal', i_file)
671
672# Generate SimObject SWIG wrapper files
673for name,simobj in sim_objects.iteritems():
674 py_source = PySource.modules[simobj.__module__]
675 extra_deps = [ py_source.tnode ]
676
677 i_file = File('python/m5/internal/param_%s.i' % name)
678 env.Command(i_file, Value(name),
679 MakeAction(createSimObjectSwigWrapper, Transform("SO SWIG")))
680 env.Depends(i_file, depends + extra_deps)
681 SwigSource('m5.internal', i_file)
682
683# Generate the main swig init file
684def makeEmbeddedSwigInit(target, source, env):
685 code = code_formatter()
686 module = source[0].get_contents()
687 code('''\
688#include "sim/init.hh"
689
690extern "C" {
691 void init_${module}();
692}
693
694EmbeddedSwig embed_swig_${module}(init_${module});
695''')
696 code.write(str(target[0]))
697
698# Build all swig modules
699for swig in SwigSource.all:
700 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
701 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
702 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG")))
703 cc_file = str(swig.tnode)
704 init_file = '%s/%s_init.cc' % (dirname(cc_file), basename(cc_file))
705 env.Command(init_file, Value(swig.module),
706 MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW")))
707 Source(init_file, **swig.guards)
708
709# Build all protocol buffers if we have got protoc and protobuf available
710if env['HAVE_PROTOBUF']:
711 for proto in ProtoBuf.all:
712 # Use both the source and header as the target, and the .proto
713 # file as the source. When executing the protoc compiler, also
714 # specify the proto_path to avoid having the generated files
715 # include the path.
716 env.Command([proto.cc_file, proto.hh_file], proto.tnode,
717 MakeAction('$PROTOC --cpp_out ${TARGET.dir} '
718 '--proto_path ${SOURCE.dir} $SOURCE',
719 Transform("PROTOC")))
720
721 # Add the C++ source file
722 Source(proto.cc_file, **proto.guards)
723elif ProtoBuf.all:
724 print 'Got protobuf to build, but lacks support!'
725 Exit(1)
726
727#
728# Handle debug flags
729#
730def makeDebugFlagCC(target, source, env):
731 assert(len(target) == 1 and len(source) == 1)
732
733 val = eval(source[0].get_contents())
734 name, compound, desc = val
735 compound = list(sorted(compound))
736
737 code = code_formatter()
738
739 # file header
740 code('''
741/*
742 * DO NOT EDIT THIS FILE! Automatically generated
743 */
744
745#include "base/debug.hh"
746''')
747
748 for flag in compound:
749 code('#include "debug/$flag.hh"')
750 code()
751 code('namespace Debug {')
752 code()
753
754 if not compound:
755 code('SimpleFlag $name("$name", "$desc");')
756 else:
757 code('CompoundFlag $name("$name", "$desc",')
758 code.indent()
759 last = len(compound) - 1
760 for i,flag in enumerate(compound):
761 if i != last:
762 code('$flag,')
763 else:
764 code('$flag);')
765 code.dedent()
766
767 code()
768 code('} // namespace Debug')
769
770 code.write(str(target[0]))
771
772def makeDebugFlagHH(target, source, env):
773 assert(len(target) == 1 and len(source) == 1)
774
775 val = eval(source[0].get_contents())
776 name, compound, desc = val
777
778 code = code_formatter()
779
780 # file header boilerplate
781 code('''\
782/*
783 * DO NOT EDIT THIS FILE!
784 *
785 * Automatically generated by SCons
786 */
787
788#ifndef __DEBUG_${name}_HH__
789#define __DEBUG_${name}_HH__
790
791namespace Debug {
792''')
793
794 if compound:
795 code('class CompoundFlag;')
796 code('class SimpleFlag;')
797
798 if compound:
799 code('extern CompoundFlag $name;')
800 for flag in compound:
801 code('extern SimpleFlag $flag;')
802 else:
803 code('extern SimpleFlag $name;')
804
805 code('''
806}
807
808#endif // __DEBUG_${name}_HH__
809''')
810
811 code.write(str(target[0]))
812
813for name,flag in sorted(debug_flags.iteritems()):
814 n, compound, desc = flag
815 assert n == name
816
817 env.Command('debug/%s.hh' % name, Value(flag),
818 MakeAction(makeDebugFlagHH, Transform("TRACING", 0)))
819 env.Command('debug/%s.cc' % name, Value(flag),
820 MakeAction(makeDebugFlagCC, Transform("TRACING", 0)))
821 Source('debug/%s.cc' % name)
822
823# Embed python files. All .py files that have been indicated by a
824# PySource() call in a SConscript need to be embedded into the M5
825# library. To do that, we compile the file to byte code, marshal the
826# byte code, compress it, and then generate a c++ file that
827# inserts the result into an array.
828def embedPyFile(target, source, env):
829 def c_str(string):
830 if string is None:
831 return "0"
832 return '"%s"' % string
833
834 '''Action function to compile a .py into a code object, marshal
835 it, compress it, and stick it into an asm file so the code appears
836 as just bytes with a label in the data section'''
837
838 src = file(str(source[0]), 'r').read()
839
840 pysource = PySource.tnodes[source[0]]
841 compiled = compile(src, pysource.abspath, 'exec')
842 marshalled = marshal.dumps(compiled)
843 compressed = zlib.compress(marshalled)
844 data = compressed
845 sym = pysource.symname
846
847 code = code_formatter()
848 code('''\
849#include "sim/init.hh"
850
851namespace {
852
853const uint8_t data_${sym}[] = {
854''')
855 code.indent()
856 step = 16
857 for i in xrange(0, len(data), step):
858 x = array.array('B', data[i:i+step])
859 code(''.join('%d,' % d for d in x))
860 code.dedent()
861
862 code('''};
863
864EmbeddedPython embedded_${sym}(
865 ${{c_str(pysource.arcname)}},
866 ${{c_str(pysource.abspath)}},
867 ${{c_str(pysource.modpath)}},
868 data_${sym},
869 ${{len(data)}},
870 ${{len(marshalled)}});
871
872} // anonymous namespace
873''')
874 code.write(str(target[0]))
875
876for source in PySource.all:
877 env.Command(source.cpp, source.tnode,
878 MakeAction(embedPyFile, Transform("EMBED PY")))
879 Source(source.cpp)
880
881########################################################################
882#
883# Define binaries. Each different build type (debug, opt, etc.) gets
884# a slightly different build environment.
885#
886
887# List of constructed environments to pass back to SConstruct
888date_source = Source('base/date.cc', skip_lib=True)
889
890# Capture this directory for the closure makeEnv, otherwise when it is
891# called, it won't know what directory it should use.
892variant_dir = Dir('.').path
893def variant(*path):
894 return os.path.join(variant_dir, *path)
895def variantd(*path):
896 return variant(*path)+'/'
897
898# Function to create a new build environment as clone of current
899# environment 'env' with modified object suffix and optional stripped
900# binary. Additional keyword arguments are appended to corresponding
901# build environment vars.
902def makeEnv(env, label, objsfx, strip = False, **kwargs):
903 # SCons doesn't know to append a library suffix when there is a '.' in the
904 # name. Use '_' instead.
905 libname = variant('gem5_' + label)
906 exename = variant('gem5.' + label)
907 secondary_exename = variant('m5.' + label)
908
909 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
910 new_env.Label = label
911 new_env.Append(**kwargs)
912
913 swig_env = new_env.Clone()
914
915 # Both gcc and clang have issues with unused labels and values in
916 # the SWIG generated code
917 swig_env.Append(CCFLAGS=['-Wno-unused-label', '-Wno-unused-value'])
918
919 # Add additional warnings here that should not be applied to
920 # the SWIG generated code
921 new_env.Append(CXXFLAGS='-Wmissing-declarations')
922
923 if env['GCC']:
924 # Depending on the SWIG version, we also need to supress
925 # warnings about uninitialized variables and missing field
926 # initializers.
927 swig_env.Append(CCFLAGS=['-Wno-uninitialized',
928 '-Wno-missing-field-initializers',
929 '-Wno-unused-but-set-variable'])
930
931 # If gcc supports it, also warn for deletion of derived
932 # classes with non-virtual desctructors. For gcc >= 4.7 we
933 # also have to disable warnings about the SWIG code having
934 # potentially uninitialized variables.
935 if compareVersions(env['GCC_VERSION'], '4.7') >= 0:
936 new_env.Append(CXXFLAGS='-Wdelete-non-virtual-dtor')
937 swig_env.Append(CCFLAGS='-Wno-maybe-uninitialized')
938 if env['CLANG']:
939 # Always enable the warning for deletion of derived classes
940 # with non-virtual destructors
941 new_env.Append(CXXFLAGS=['-Wdelete-non-virtual-dtor'])
942
943 swig_env.Append(CCFLAGS=[
944 # Some versions of SWIG can return uninitialized values
945 '-Wno-sometimes-uninitialized',
946 # Register storage is requested in a lot of places in
947 # SWIG-generated code.
948 '-Wno-deprecated-register',
949 ])
950
943 werror_env = new_env.Clone()
944 werror_env.Append(CCFLAGS='-Werror')
945
946 def make_obj(source, static, extra_deps = None):
947 '''This function adds the specified source to the correct
948 build environment, and returns the corresponding SCons Object
949 nodes'''
950
951 if source.swig:
952 env = swig_env
953 elif source.Werror:
954 env = werror_env
955 else:
956 env = new_env
957
958 if static:
959 obj = env.StaticObject(source.tnode)
960 else:
961 obj = env.SharedObject(source.tnode)
962
963 if extra_deps:
964 env.Depends(obj, extra_deps)
965
966 return obj
967
968 static_objs = \
969 [ make_obj(s, True) for s in Source.get(main=False, skip_lib=False) ]
970 shared_objs = \
971 [ make_obj(s, False) for s in Source.get(main=False, skip_lib=False) ]
972
973 static_date = make_obj(date_source, static=True, extra_deps=static_objs)
974 static_objs.append(static_date)
975
976 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
977 shared_objs.append(shared_date)
978
979 # First make a library of everything but main() so other programs can
980 # link against m5.
981 static_lib = new_env.StaticLibrary(libname, static_objs)
982 shared_lib = new_env.SharedLibrary(libname, shared_objs)
983
984 # Now link a stub with main() and the static library.
985 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ]
986
987 for test in UnitTest.all:
988 flags = { test.target : True }
989 test_sources = Source.get(**flags)
990 test_objs = [ make_obj(s, static=True) for s in test_sources ]
991 if test.main:
992 test_objs += main_objs
993 path = variant('unittest/%s.%s' % (test.target, label))
994 new_env.Program(path, test_objs + static_objs)
995
996 progname = exename
997 if strip:
998 progname += '.unstripped'
999
1000 targets = new_env.Program(progname, main_objs + static_objs)
1001
1002 if strip:
1003 if sys.platform == 'sunos5':
1004 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1005 else:
1006 cmd = 'strip $SOURCE -o $TARGET'
1007 targets = new_env.Command(exename, progname,
1008 MakeAction(cmd, Transform("STRIP")))
1009
1010 new_env.Command(secondary_exename, exename,
1011 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK")))
1012
1013 new_env.M5Binary = targets[0]
1014 return new_env
1015
1016# Start out with the compiler flags common to all compilers,
1017# i.e. they all use -g for opt and -g -pg for prof
1018ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'],
1019 'perf' : ['-g']}
1020
1021# Start out with the linker flags common to all linkers, i.e. -pg for
1022# prof, and -lprofiler for perf. The -lprofile flag is surrounded by
1023# no-as-needed and as-needed as the binutils linker is too clever and
1024# simply doesn't link to the library otherwise.
1025ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'],
1026 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']}
1027
1028# For Link Time Optimization, the optimisation flags used to compile
1029# individual files are decoupled from those used at link time
1030# (i.e. you can compile with -O3 and perform LTO with -O0), so we need
1031# to also update the linker flags based on the target.
1032if env['GCC']:
1033 if sys.platform == 'sunos5':
1034 ccflags['debug'] += ['-gstabs+']
1035 else:
1036 ccflags['debug'] += ['-ggdb3']
1037 ldflags['debug'] += ['-O0']
1038 # opt, fast, prof and perf all share the same cc flags, also add
1039 # the optimization to the ldflags as LTO defers the optimization
1040 # to link time
1041 for target in ['opt', 'fast', 'prof', 'perf']:
1042 ccflags[target] += ['-O3']
1043 ldflags[target] += ['-O3']
1044
1045 ccflags['fast'] += env['LTO_CCFLAGS']
1046 ldflags['fast'] += env['LTO_LDFLAGS']
1047elif env['CLANG']:
1048 ccflags['debug'] += ['-g', '-O0']
1049 # opt, fast, prof and perf all share the same cc flags
1050 for target in ['opt', 'fast', 'prof', 'perf']:
1051 ccflags[target] += ['-O3']
1052else:
1053 print 'Unknown compiler, please fix compiler options'
1054 Exit(1)
1055
1056
1057# To speed things up, we only instantiate the build environments we
1058# need. We try to identify the needed environment for each target; if
1059# we can't, we fall back on instantiating all the environments just to
1060# be safe.
1061target_types = ['debug', 'opt', 'fast', 'prof', 'perf']
1062obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof',
1063 'gpo' : 'perf'}
1064
1065def identifyTarget(t):
1066 ext = t.split('.')[-1]
1067 if ext in target_types:
1068 return ext
1069 if obj2target.has_key(ext):
1070 return obj2target[ext]
1071 match = re.search(r'/tests/([^/]+)/', t)
1072 if match and match.group(1) in target_types:
1073 return match.group(1)
1074 return 'all'
1075
1076needed_envs = [identifyTarget(target) for target in BUILD_TARGETS]
1077if 'all' in needed_envs:
1078 needed_envs += target_types
1079
1080gem5_root = Dir('.').up().up().abspath
1081def makeEnvirons(target, source, env):
1082 # cause any later Source() calls to be fatal, as a diagnostic.
1083 Source.done()
1084
1085 envList = []
1086
1087 # Debug binary
1088 if 'debug' in needed_envs:
1089 envList.append(
1090 makeEnv(env, 'debug', '.do',
1091 CCFLAGS = Split(ccflags['debug']),
1092 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'],
1093 LINKFLAGS = Split(ldflags['debug'])))
1094
1095 # Optimized binary
1096 if 'opt' in needed_envs:
1097 envList.append(
1098 makeEnv(env, 'opt', '.o',
1099 CCFLAGS = Split(ccflags['opt']),
1100 CPPDEFINES = ['TRACING_ON=1'],
1101 LINKFLAGS = Split(ldflags['opt'])))
1102
1103 # "Fast" binary
1104 if 'fast' in needed_envs:
1105 envList.append(
1106 makeEnv(env, 'fast', '.fo', strip = True,
1107 CCFLAGS = Split(ccflags['fast']),
1108 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1109 LINKFLAGS = Split(ldflags['fast'])))
1110
1111 # Profiled binary using gprof
1112 if 'prof' in needed_envs:
1113 envList.append(
1114 makeEnv(env, 'prof', '.po',
1115 CCFLAGS = Split(ccflags['prof']),
1116 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1117 LINKFLAGS = Split(ldflags['prof'])))
1118
1119 # Profiled binary using google-pprof
1120 if 'perf' in needed_envs:
1121 envList.append(
1122 makeEnv(env, 'perf', '.gpo',
1123 CCFLAGS = Split(ccflags['perf']),
1124 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1125 LINKFLAGS = Split(ldflags['perf'])))
1126
1127 # Set up the regression tests for each build.
1128 for e in envList:
1129 SConscript(os.path.join(gem5_root, 'tests', 'SConscript'),
1130 variant_dir = variantd('tests', e.Label),
1131 exports = { 'env' : e }, duplicate = False)
1132
1133# The MakeEnvirons Builder defers the full dependency collection until
1134# after processing the ISA definition (due to dynamically generated
1135# source files). Add this dependency to all targets so they will wait
1136# until the environments are completely set up. Otherwise, a second
1137# process (e.g. -j2 or higher) will try to compile the requested target,
1138# not know how, and fail.
1139env.Append(BUILDERS = {'MakeEnvirons' :
1140 Builder(action=MakeAction(makeEnvirons,
1141 Transform("ENVIRONS", 1)))})
1142
1143isa_target = env['PHONY_BASE'] + '-deps'
1144environs = env['PHONY_BASE'] + '-environs'
1145env.Depends('#all-deps', isa_target)
1146env.Depends('#all-environs', environs)
1147env.ScanISA(isa_target, File('arch/%s/generated/inc.d' % env['TARGET_ISA']))
1148envSetup = env.MakeEnvirons(environs, isa_target)
1149
1150# make sure no -deps targets occur before all ISAs are complete
1151env.Depends(isa_target, '#all-isas')
1152# likewise for -environs targets and all the -deps targets
1153env.Depends(environs, '#all-deps')
951 werror_env = new_env.Clone()
952 werror_env.Append(CCFLAGS='-Werror')
953
954 def make_obj(source, static, extra_deps = None):
955 '''This function adds the specified source to the correct
956 build environment, and returns the corresponding SCons Object
957 nodes'''
958
959 if source.swig:
960 env = swig_env
961 elif source.Werror:
962 env = werror_env
963 else:
964 env = new_env
965
966 if static:
967 obj = env.StaticObject(source.tnode)
968 else:
969 obj = env.SharedObject(source.tnode)
970
971 if extra_deps:
972 env.Depends(obj, extra_deps)
973
974 return obj
975
976 static_objs = \
977 [ make_obj(s, True) for s in Source.get(main=False, skip_lib=False) ]
978 shared_objs = \
979 [ make_obj(s, False) for s in Source.get(main=False, skip_lib=False) ]
980
981 static_date = make_obj(date_source, static=True, extra_deps=static_objs)
982 static_objs.append(static_date)
983
984 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
985 shared_objs.append(shared_date)
986
987 # First make a library of everything but main() so other programs can
988 # link against m5.
989 static_lib = new_env.StaticLibrary(libname, static_objs)
990 shared_lib = new_env.SharedLibrary(libname, shared_objs)
991
992 # Now link a stub with main() and the static library.
993 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ]
994
995 for test in UnitTest.all:
996 flags = { test.target : True }
997 test_sources = Source.get(**flags)
998 test_objs = [ make_obj(s, static=True) for s in test_sources ]
999 if test.main:
1000 test_objs += main_objs
1001 path = variant('unittest/%s.%s' % (test.target, label))
1002 new_env.Program(path, test_objs + static_objs)
1003
1004 progname = exename
1005 if strip:
1006 progname += '.unstripped'
1007
1008 targets = new_env.Program(progname, main_objs + static_objs)
1009
1010 if strip:
1011 if sys.platform == 'sunos5':
1012 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1013 else:
1014 cmd = 'strip $SOURCE -o $TARGET'
1015 targets = new_env.Command(exename, progname,
1016 MakeAction(cmd, Transform("STRIP")))
1017
1018 new_env.Command(secondary_exename, exename,
1019 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK")))
1020
1021 new_env.M5Binary = targets[0]
1022 return new_env
1023
1024# Start out with the compiler flags common to all compilers,
1025# i.e. they all use -g for opt and -g -pg for prof
1026ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'],
1027 'perf' : ['-g']}
1028
1029# Start out with the linker flags common to all linkers, i.e. -pg for
1030# prof, and -lprofiler for perf. The -lprofile flag is surrounded by
1031# no-as-needed and as-needed as the binutils linker is too clever and
1032# simply doesn't link to the library otherwise.
1033ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'],
1034 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']}
1035
1036# For Link Time Optimization, the optimisation flags used to compile
1037# individual files are decoupled from those used at link time
1038# (i.e. you can compile with -O3 and perform LTO with -O0), so we need
1039# to also update the linker flags based on the target.
1040if env['GCC']:
1041 if sys.platform == 'sunos5':
1042 ccflags['debug'] += ['-gstabs+']
1043 else:
1044 ccflags['debug'] += ['-ggdb3']
1045 ldflags['debug'] += ['-O0']
1046 # opt, fast, prof and perf all share the same cc flags, also add
1047 # the optimization to the ldflags as LTO defers the optimization
1048 # to link time
1049 for target in ['opt', 'fast', 'prof', 'perf']:
1050 ccflags[target] += ['-O3']
1051 ldflags[target] += ['-O3']
1052
1053 ccflags['fast'] += env['LTO_CCFLAGS']
1054 ldflags['fast'] += env['LTO_LDFLAGS']
1055elif env['CLANG']:
1056 ccflags['debug'] += ['-g', '-O0']
1057 # opt, fast, prof and perf all share the same cc flags
1058 for target in ['opt', 'fast', 'prof', 'perf']:
1059 ccflags[target] += ['-O3']
1060else:
1061 print 'Unknown compiler, please fix compiler options'
1062 Exit(1)
1063
1064
1065# To speed things up, we only instantiate the build environments we
1066# need. We try to identify the needed environment for each target; if
1067# we can't, we fall back on instantiating all the environments just to
1068# be safe.
1069target_types = ['debug', 'opt', 'fast', 'prof', 'perf']
1070obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof',
1071 'gpo' : 'perf'}
1072
1073def identifyTarget(t):
1074 ext = t.split('.')[-1]
1075 if ext in target_types:
1076 return ext
1077 if obj2target.has_key(ext):
1078 return obj2target[ext]
1079 match = re.search(r'/tests/([^/]+)/', t)
1080 if match and match.group(1) in target_types:
1081 return match.group(1)
1082 return 'all'
1083
1084needed_envs = [identifyTarget(target) for target in BUILD_TARGETS]
1085if 'all' in needed_envs:
1086 needed_envs += target_types
1087
1088gem5_root = Dir('.').up().up().abspath
1089def makeEnvirons(target, source, env):
1090 # cause any later Source() calls to be fatal, as a diagnostic.
1091 Source.done()
1092
1093 envList = []
1094
1095 # Debug binary
1096 if 'debug' in needed_envs:
1097 envList.append(
1098 makeEnv(env, 'debug', '.do',
1099 CCFLAGS = Split(ccflags['debug']),
1100 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'],
1101 LINKFLAGS = Split(ldflags['debug'])))
1102
1103 # Optimized binary
1104 if 'opt' in needed_envs:
1105 envList.append(
1106 makeEnv(env, 'opt', '.o',
1107 CCFLAGS = Split(ccflags['opt']),
1108 CPPDEFINES = ['TRACING_ON=1'],
1109 LINKFLAGS = Split(ldflags['opt'])))
1110
1111 # "Fast" binary
1112 if 'fast' in needed_envs:
1113 envList.append(
1114 makeEnv(env, 'fast', '.fo', strip = True,
1115 CCFLAGS = Split(ccflags['fast']),
1116 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1117 LINKFLAGS = Split(ldflags['fast'])))
1118
1119 # Profiled binary using gprof
1120 if 'prof' in needed_envs:
1121 envList.append(
1122 makeEnv(env, 'prof', '.po',
1123 CCFLAGS = Split(ccflags['prof']),
1124 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1125 LINKFLAGS = Split(ldflags['prof'])))
1126
1127 # Profiled binary using google-pprof
1128 if 'perf' in needed_envs:
1129 envList.append(
1130 makeEnv(env, 'perf', '.gpo',
1131 CCFLAGS = Split(ccflags['perf']),
1132 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1133 LINKFLAGS = Split(ldflags['perf'])))
1134
1135 # Set up the regression tests for each build.
1136 for e in envList:
1137 SConscript(os.path.join(gem5_root, 'tests', 'SConscript'),
1138 variant_dir = variantd('tests', e.Label),
1139 exports = { 'env' : e }, duplicate = False)
1140
1141# The MakeEnvirons Builder defers the full dependency collection until
1142# after processing the ISA definition (due to dynamically generated
1143# source files). Add this dependency to all targets so they will wait
1144# until the environments are completely set up. Otherwise, a second
1145# process (e.g. -j2 or higher) will try to compile the requested target,
1146# not know how, and fail.
1147env.Append(BUILDERS = {'MakeEnvirons' :
1148 Builder(action=MakeAction(makeEnvirons,
1149 Transform("ENVIRONS", 1)))})
1150
1151isa_target = env['PHONY_BASE'] + '-deps'
1152environs = env['PHONY_BASE'] + '-environs'
1153env.Depends('#all-deps', isa_target)
1154env.Depends('#all-environs', environs)
1155env.ScanISA(isa_target, File('arch/%s/generated/inc.d' % env['TARGET_ISA']))
1156envSetup = env.MakeEnvirons(environs, isa_target)
1157
1158# make sure no -deps targets occur before all ISAs are complete
1159env.Depends(isa_target, '#all-isas')
1160# likewise for -environs targets and all the -deps targets
1161env.Depends(environs, '#all-deps')