3 # Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
29 # Authors: Nathan Binkert
42 from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
46 from gem5_scons import Transform
48 # This file defines how to build a particular configuration of gem5
49 # based on variable settings in the 'env' build environment.
53 # Children need to see the environment
56 build_env = [(opt, env[opt]) for opt in export_vars]
58 from m5.util import code_formatter, compareVersions
60 ########################################################################
61 # Code for adding source files of various types
63 # When specifying a source file of some type, a set of tags can be
64 # specified for that file.
66 class SourceFilter(object):
67 def __init__(self, predicate):
68 self.predicate = predicate
70 def __or__(self, other):
71 return SourceFilter(lambda tags: self.predicate(tags) or
72 other.predicate(tags))
74 def __and__(self, other):
75 return SourceFilter(lambda tags: self.predicate(tags) and
76 other.predicate(tags))
78 def with_tags_that(predicate):
79 '''Return a list of sources with tags that satisfy a predicate.'''
80 return SourceFilter(predicate)
82 def with_any_tags(*tags):
83 '''Return a list of sources with any of the supplied tags.'''
84 return SourceFilter(lambda stags: len(set(tags) & stags) > 0)
86 def with_all_tags(*tags):
87 '''Return a list of sources with all of the supplied tags.'''
88 return SourceFilter(lambda stags: set(tags) <= stags)
91 '''Return a list of sources with the supplied tag.'''
92 return SourceFilter(lambda stags: tag in stags)
94 def without_tags(*tags):
95 '''Return a list of sources without any of the supplied tags.'''
96 return SourceFilter(lambda stags: len(set(tags) & stags) == 0)
99 '''Return a list of sources with the supplied tag.'''
100 return SourceFilter(lambda stags: tag not in stags)
102 source_filter_factories = {
103 'with_tags_that': with_tags_that,
104 'with_any_tags': with_any_tags,
105 'with_all_tags': with_all_tags,
106 'with_tag': with_tag,
107 'without_tags': without_tags,
108 'without_tag': without_tag,
111 Export(source_filter_factories)
113 class SourceList(list):
114 def apply_filter(self, f):
116 return f.predicate(source.tags)
117 return SourceList(filter(match, self))
119 def __getattr__(self, name):
120 func = source_filter_factories.get(name, None)
124 @functools.wraps(func)
125 def wrapper(*args, **kwargs):
126 return self.apply_filter(func(*args, **kwargs))
129 class SourceMeta(type):
130 '''Meta class for source files that keeps track of all files of a
132 def __init__(cls, name, bases, dict):
133 super(SourceMeta, cls).__init__(name, bases, dict)
134 cls.all = SourceList()
136 class SourceFile(object):
137 '''Base object that encapsulates the notion of a source file.
138 This includes, the source node, target node, various manipulations
139 of those. A source file also specifies a set of tags which
140 describing arbitrary properties of the source file.'''
141 __metaclass__ = SourceMeta
146 def __init__(self, source, tags=None, add_tags=None):
149 if isinstance(tags, basestring):
151 if not isinstance(tags, set):
156 if isinstance(add_tags, basestring):
157 add_tags = set([add_tags])
158 if not isinstance(add_tags, set):
159 add_tags = set(add_tags)
160 self.tags |= add_tags
163 if not isinstance(source, SCons.Node.FS.File):
167 self.snode = tnode.srcnode()
169 for base in type(self).__mro__:
170 if issubclass(base, SourceFile):
171 base.all.append(self)
173 def static(self, env):
174 key = (self.tnode, env['OBJSUFFIX'])
175 if not key in self.static_objs:
176 self.static_objs[key] = env.StaticObject(self.tnode)
177 return self.static_objs[key]
179 def shared(self, env):
180 key = (self.tnode, env['OBJSUFFIX'])
181 if not key in self.shared_objs:
182 self.shared_objs[key] = env.SharedObject(self.tnode)
183 return self.shared_objs[key]
187 return str(self.tnode)
191 return dirname(self.filename)
195 return basename(self.filename)
199 index = self.basename.rfind('.')
201 # dot files aren't extensions
202 return self.basename, None
204 return self.basename[:index], self.basename[index+1:]
206 def __lt__(self, other): return self.filename < other.filename
207 def __le__(self, other): return self.filename <= other.filename
208 def __gt__(self, other): return self.filename > other.filename
209 def __ge__(self, other): return self.filename >= other.filename
210 def __eq__(self, other): return self.filename == other.filename
211 def __ne__(self, other): return self.filename != other.filename
213 class Source(SourceFile):
214 ungrouped_tag = 'No link group'
215 source_groups = set()
217 _current_group_tag = ungrouped_tag
220 def link_group_tag(group):
221 return 'link group: %s' % group
224 def set_group(cls, group):
225 new_tag = Source.link_group_tag(group)
226 Source._current_group_tag = new_tag
227 Source.source_groups.add(group)
229 def _add_link_group_tag(self):
230 self.tags.add(Source._current_group_tag)
232 '''Add a c/c++ source file to the build'''
233 def __init__(self, source, tags=None, add_tags=None):
234 '''specify the source file, and any tags'''
235 super(Source, self).__init__(source, tags, add_tags)
236 self._add_link_group_tag()
238 class PySource(SourceFile):
239 '''Add a python source file to the named package'''
240 invalid_sym_char = re.compile('[^A-z0-9_]')
245 def __init__(self, package, source, tags=None, add_tags=None):
246 '''specify the python package, the source file, and any tags'''
247 super(PySource, self).__init__(source, tags, add_tags)
249 modname,ext = self.extname
253 path = package.split('.')
258 if modname != '__init__':
259 modpath += [ modname ]
260 modpath = '.'.join(modpath)
262 arcpath = path + [ self.basename ]
263 abspath = self.snode.abspath
264 if not exists(abspath):
265 abspath = self.tnode.abspath
267 self.package = package
268 self.modname = modname
269 self.modpath = modpath
270 self.arcname = joinpath(*arcpath)
271 self.abspath = abspath
272 self.compiled = File(self.filename + 'c')
273 self.cpp = File(self.filename + '.cc')
274 self.symname = PySource.invalid_sym_char.sub('_', modpath)
276 PySource.modules[modpath] = self
277 PySource.tnodes[self.tnode] = self
278 PySource.symnames[self.symname] = self
280 class SimObject(PySource):
281 '''Add a SimObject python file as a python source object and add
282 it to a list of sim object modules'''
287 def __init__(self, source, tags=None, add_tags=None):
288 '''Specify the source file and any tags (automatically in
289 the m5.objects package)'''
290 super(SimObject, self).__init__('m5.objects', source, tags, add_tags)
292 raise AttributeError, "Too late to call SimObject now."
294 bisect.insort_right(SimObject.modnames, self.modname)
296 class ProtoBuf(SourceFile):
297 '''Add a Protocol Buffer to build'''
299 def __init__(self, source, tags=None, add_tags=None):
300 '''Specify the source file, and any tags'''
301 super(ProtoBuf, self).__init__(source, tags, add_tags)
303 # Get the file name and the extension
304 modname,ext = self.extname
305 assert ext == 'proto'
307 # Currently, we stick to generating the C++ headers, so we
308 # only need to track the source and header.
309 self.cc_file = File(modname + '.pb.cc')
310 self.hh_file = File(modname + '.pb.h')
312 class UnitTest(object):
313 '''Create a UnitTest'''
316 def __init__(self, target, *sources, **kwargs):
317 '''Specify the target name and any sources. Sources that are
318 not SourceFiles are evalued with Source(). All files are
319 tagged with the name of the UnitTest target.'''
323 if not isinstance(src, SourceFile):
324 src = Source(src, tags=str(target))
329 self.main = kwargs.get('main', False)
330 self.all.append(self)
332 class GTest(UnitTest):
333 '''Create a unit test based on the google test framework.'''
335 def __init__(self, *args, **kwargs):
336 isFilter = lambda arg: isinstance(arg, SourceFilter)
337 self.filters = filter(isFilter, args)
338 args = filter(lambda a: not isFilter(a), args)
339 super(GTest, self).__init__(*args, **kwargs)
341 self.skip_lib = kwargs.pop('skip_lib', False)
343 # Children should have access
351 ########################################################################
356 def DebugFlag(name, desc=None):
357 if name in debug_flags:
358 raise AttributeError, "Flag %s already specified" % name
359 debug_flags[name] = (name, (), desc)
361 def CompoundFlag(name, flags, desc=None):
362 if name in debug_flags:
363 raise AttributeError, "Flag %s already specified" % name
365 compound = tuple(flags)
366 debug_flags[name] = (name, compound, desc)
369 Export('CompoundFlag')
371 ########################################################################
373 # Set some compiler variables
376 # Include file paths are rooted in this directory. SCons will
377 # automatically expand '.' to refer to both the source directory and
378 # the corresponding build directory to pick up generated include
380 env.Append(CPPPATH=Dir('.'))
382 for extra_dir in extras_dir_list:
383 env.Append(CPPPATH=Dir(extra_dir))
385 # Workaround for bug in SCons version > 0.97d20071212
386 # Scons bug id: 2006 gem5 Bug id: 308
387 for root, dirs, files in os.walk(base_dir, topdown=True):
388 Dir(root[len(base_dir) + 1:])
390 ########################################################################
392 # Walk the tree and execute all SConscripts in subdirectories
395 here = Dir('.').srcnode().abspath
396 for root, dirs, files in os.walk(base_dir, topdown=True):
398 # we don't want to recurse back into this SConscript
401 if 'SConscript' in files:
402 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
403 Source.set_group(build_dir)
404 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
406 for extra_dir in extras_dir_list:
407 prefix_len = len(dirname(extra_dir)) + 1
409 # Also add the corresponding build directory to pick up generated
411 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:])))
413 for root, dirs, files in os.walk(extra_dir, topdown=True):
414 # if build lives in the extras directory, don't walk down it
418 if 'SConscript' in files:
419 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
420 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
422 for opt in export_vars:
425 def makeTheISA(source, target, env):
426 isas = [ src.get_contents() for src in source ]
427 target_isa = env['TARGET_ISA']
429 return isa.upper() + '_ISA'
432 return isa[0].upper() + isa[1:].lower() + 'ISA'
435 code = code_formatter()
437 #ifndef __CONFIG_THE_ISA_HH__
438 #define __CONFIG_THE_ISA_HH__
442 # create defines for the preprocessing and compile-time determination
443 for i,isa in enumerate(isas):
444 code('#define $0 $1', define(isa), i + 1)
447 # create an enum for any run-time determination of the ISA, we
448 # reuse the same name as the namespaces
449 code('enum class Arch {')
450 for i,isa in enumerate(isas):
451 if i + 1 == len(isas):
452 code(' $0 = $1', namespace(isa), define(isa))
454 code(' $0 = $1,', namespace(isa), define(isa))
459 #define THE_ISA ${{define(target_isa)}}
460 #define TheISA ${{namespace(target_isa)}}
461 #define THE_ISA_STR "${{target_isa}}"
463 #endif // __CONFIG_THE_ISA_HH__''')
465 code.write(str(target[0]))
467 env.Command('config/the_isa.hh', map(Value, all_isa_list),
468 MakeAction(makeTheISA, Transform("CFG ISA", 0)))
470 def makeTheGPUISA(source, target, env):
471 isas = [ src.get_contents() for src in source ]
472 target_gpu_isa = env['TARGET_GPU_ISA']
474 return isa.upper() + '_ISA'
477 return isa[0].upper() + isa[1:].lower() + 'ISA'
480 code = code_formatter()
482 #ifndef __CONFIG_THE_GPU_ISA_HH__
483 #define __CONFIG_THE_GPU_ISA_HH__
487 # create defines for the preprocessing and compile-time determination
488 for i,isa in enumerate(isas):
489 code('#define $0 $1', define(isa), i + 1)
492 # create an enum for any run-time determination of the ISA, we
493 # reuse the same name as the namespaces
494 code('enum class GPUArch {')
495 for i,isa in enumerate(isas):
496 if i + 1 == len(isas):
497 code(' $0 = $1', namespace(isa), define(isa))
499 code(' $0 = $1,', namespace(isa), define(isa))
504 #define THE_GPU_ISA ${{define(target_gpu_isa)}}
505 #define TheGpuISA ${{namespace(target_gpu_isa)}}
506 #define THE_GPU_ISA_STR "${{target_gpu_isa}}"
508 #endif // __CONFIG_THE_GPU_ISA_HH__''')
510 code.write(str(target[0]))
512 env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list),
513 MakeAction(makeTheGPUISA, Transform("CFG ISA", 0)))
515 ########################################################################
517 # Prevent any SimObjects from being added after this point, they
518 # should all have been added in the SConscripts above
520 SimObject.fixed = True
522 class DictImporter(object):
523 '''This importer takes a dictionary of arbitrary module names that
524 map to arbitrary filenames.'''
525 def __init__(self, modules):
526 self.modules = modules
527 self.installed = set()
534 for module in self.installed:
535 del sys.modules[module]
536 self.installed = set()
538 def find_module(self, fullname, path):
539 if fullname == 'm5.defines':
542 if fullname == 'm5.objects':
545 if fullname.startswith('_m5'):
548 source = self.modules.get(fullname, None)
549 if source is not None and fullname.startswith('m5.objects'):
554 def load_module(self, fullname):
555 mod = imp.new_module(fullname)
556 sys.modules[fullname] = mod
557 self.installed.add(fullname)
559 mod.__loader__ = self
560 if fullname == 'm5.objects':
561 mod.__path__ = fullname.split('.')
564 if fullname == 'm5.defines':
565 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
568 source = self.modules[fullname]
569 if source.modname == '__init__':
570 mod.__path__ = source.modpath
571 mod.__file__ = source.abspath
573 exec file(source.abspath, 'r') in mod.__dict__
579 from m5.util import code_formatter
584 # install the python importer so we can grab stuff from the source
585 # tree itself. We can't have SimObjects added after this point or
586 # else we won't know about them for the rest of the stuff.
587 importer = DictImporter(PySource.modules)
588 sys.meta_path[0:0] = [ importer ]
590 # import all sim objects so we can populate the all_objects list
591 # make sure that we're working with a list, then let's sort it
592 for modname in SimObject.modnames:
593 exec('from m5.objects import %s' % modname)
595 # we need to unload all of the currently imported modules so that they
596 # will be re-imported the next time the sconscript is run
598 sys.meta_path.remove(importer)
600 sim_objects = m5.SimObject.allClasses
601 all_enums = m5.params.allEnums
603 for name,obj in sorted(sim_objects.iteritems()):
604 for param in obj._params.local.values():
605 # load the ptype attribute now because it depends on the
606 # current version of SimObject.allClasses, but when scons
607 # actually uses the value, all versions of
608 # SimObject.allClasses will have been loaded
611 ########################################################################
613 # calculate extra dependencies
615 module_depends = ["m5", "m5.SimObject", "m5.params"]
616 depends = [ PySource.modules[dep].snode for dep in module_depends ]
617 depends.sort(key = lambda x: x.name)
619 ########################################################################
621 # Commands for the basic automatically generated python files
624 # Generate Python file containing a dict specifying the current
626 def makeDefinesPyFile(target, source, env):
627 build_env = source[0].get_contents()
629 code = code_formatter()
634 buildEnv = m5.util.SmartDict($build_env)
636 compileDate = _m5.core.compileDate
638 for key,val in _m5.core.__dict__.iteritems():
639 if key.startswith('flag_'):
644 code.write(target[0].abspath)
646 defines_info = Value(build_env)
647 # Generate a file with all of the compile options in it
648 env.Command('python/m5/defines.py', defines_info,
649 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
650 PySource('m5', 'python/m5/defines.py')
652 # Generate python file containing info about the M5 source code
653 def makeInfoPyFile(target, source, env):
654 code = code_formatter()
656 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
657 code('$src = ${{repr(data)}}')
658 code.write(str(target[0]))
660 # Generate a file that wraps the basic top level files
661 env.Command('python/m5/info.py',
662 [ '#/COPYING', '#/LICENSE', '#/README', ],
663 MakeAction(makeInfoPyFile, Transform("INFO")))
664 PySource('m5', 'python/m5/info.py')
666 ########################################################################
668 # Create all of the SimObject param headers and enum headers
671 def createSimObjectParamStruct(target, source, env):
672 assert len(target) == 1 and len(source) == 1
674 name = source[0].get_text_contents()
675 obj = sim_objects[name]
677 code = code_formatter()
678 obj.cxx_param_decl(code)
679 code.write(target[0].abspath)
681 def createSimObjectCxxConfig(is_header):
682 def body(target, source, env):
683 assert len(target) == 1 and len(source) == 1
685 name = str(source[0].get_contents())
686 obj = sim_objects[name]
688 code = code_formatter()
689 obj.cxx_config_param_file(code, is_header)
690 code.write(target[0].abspath)
693 def createEnumStrings(target, source, env):
694 assert len(target) == 1 and len(source) == 2
696 name = source[0].get_text_contents()
697 use_python = source[1].read()
698 obj = all_enums[name]
700 code = code_formatter()
704 code.write(target[0].abspath)
706 def createEnumDecls(target, source, env):
707 assert len(target) == 1 and len(source) == 1
709 name = source[0].get_text_contents()
710 obj = all_enums[name]
712 code = code_formatter()
714 code.write(target[0].abspath)
716 def createSimObjectPyBindWrapper(target, source, env):
717 name = source[0].get_text_contents()
718 obj = sim_objects[name]
720 code = code_formatter()
721 obj.pybind_decl(code)
722 code.write(target[0].abspath)
724 # Generate all of the SimObject param C++ struct header files
726 for name,simobj in sorted(sim_objects.iteritems()):
727 py_source = PySource.modules[simobj.__module__]
728 extra_deps = [ py_source.tnode ]
730 hh_file = File('params/%s.hh' % name)
731 params_hh_files.append(hh_file)
732 env.Command(hh_file, Value(name),
733 MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
734 env.Depends(hh_file, depends + extra_deps)
736 # C++ parameter description files
737 if GetOption('with_cxx_config'):
738 for name,simobj in sorted(sim_objects.iteritems()):
739 py_source = PySource.modules[simobj.__module__]
740 extra_deps = [ py_source.tnode ]
742 cxx_config_hh_file = File('cxx_config/%s.hh' % name)
743 cxx_config_cc_file = File('cxx_config/%s.cc' % name)
744 env.Command(cxx_config_hh_file, Value(name),
745 MakeAction(createSimObjectCxxConfig(True),
746 Transform("CXXCPRHH")))
747 env.Command(cxx_config_cc_file, Value(name),
748 MakeAction(createSimObjectCxxConfig(False),
749 Transform("CXXCPRCC")))
750 env.Depends(cxx_config_hh_file, depends + extra_deps +
751 [File('params/%s.hh' % name), File('sim/cxx_config.hh')])
752 env.Depends(cxx_config_cc_file, depends + extra_deps +
753 [cxx_config_hh_file])
754 Source(cxx_config_cc_file)
756 cxx_config_init_cc_file = File('cxx_config/init.cc')
758 def createCxxConfigInitCC(target, source, env):
759 assert len(target) == 1 and len(source) == 1
761 code = code_formatter()
763 for name,simobj in sorted(sim_objects.iteritems()):
764 if not hasattr(simobj, 'abstract') or not simobj.abstract:
765 code('#include "cxx_config/${name}.hh"')
767 code('void cxxConfigInit()')
770 for name,simobj in sorted(sim_objects.iteritems()):
771 not_abstract = not hasattr(simobj, 'abstract') or \
773 if not_abstract and 'type' in simobj.__dict__:
774 code('cxx_config_directory["${name}"] = '
775 '${name}CxxConfigParams::makeDirectoryEntry();')
778 code.write(target[0].abspath)
780 py_source = PySource.modules[simobj.__module__]
781 extra_deps = [ py_source.tnode ]
782 env.Command(cxx_config_init_cc_file, Value(name),
783 MakeAction(createCxxConfigInitCC, Transform("CXXCINIT")))
784 cxx_param_hh_files = ["cxx_config/%s.hh" % simobj
785 for name,simobj in sorted(sim_objects.iteritems())
786 if not hasattr(simobj, 'abstract') or not simobj.abstract]
787 Depends(cxx_config_init_cc_file, cxx_param_hh_files +
788 [File('sim/cxx_config.hh')])
789 Source(cxx_config_init_cc_file)
791 # Generate all enum header files
792 for name,enum in sorted(all_enums.iteritems()):
793 py_source = PySource.modules[enum.__module__]
794 extra_deps = [ py_source.tnode ]
796 cc_file = File('enums/%s.cc' % name)
797 env.Command(cc_file, [Value(name), Value(env['USE_PYTHON'])],
798 MakeAction(createEnumStrings, Transform("ENUM STR")))
799 env.Depends(cc_file, depends + extra_deps)
802 hh_file = File('enums/%s.hh' % name)
803 env.Command(hh_file, Value(name),
804 MakeAction(createEnumDecls, Transform("ENUMDECL")))
805 env.Depends(hh_file, depends + extra_deps)
807 # Generate SimObject Python bindings wrapper files
808 if env['USE_PYTHON']:
809 for name,simobj in sorted(sim_objects.iteritems()):
810 py_source = PySource.modules[simobj.__module__]
811 extra_deps = [ py_source.tnode ]
812 cc_file = File('python/_m5/param_%s.cc' % name)
813 env.Command(cc_file, Value(name),
814 MakeAction(createSimObjectPyBindWrapper,
815 Transform("SO PyBind")))
816 env.Depends(cc_file, depends + extra_deps)
819 # Build all protocol buffers if we have got protoc and protobuf available
820 if env['HAVE_PROTOBUF']:
821 for proto in ProtoBuf.all:
822 # Use both the source and header as the target, and the .proto
823 # file as the source. When executing the protoc compiler, also
824 # specify the proto_path to avoid having the generated files
826 env.Command([proto.cc_file, proto.hh_file], proto.tnode,
827 MakeAction('$PROTOC --cpp_out ${TARGET.dir} '
828 '--proto_path ${SOURCE.dir} $SOURCE',
829 Transform("PROTOC")))
831 # Add the C++ source file
832 Source(proto.cc_file, tags=proto.tags)
834 print 'Got protobuf to build, but lacks support!'
840 def makeDebugFlagCC(target, source, env):
841 assert(len(target) == 1 and len(source) == 1)
843 code = code_formatter()
845 # delay definition of CompoundFlags until after all the definition
846 # of all constituent SimpleFlags
847 comp_code = code_formatter()
852 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
855 #include "base/debug.hh"
861 for name, flag in sorted(source[0].read().iteritems()):
862 n, compound, desc = flag
866 code('SimpleFlag $name("$name", "$desc");')
868 comp_code('CompoundFlag $name("$name", "$desc",')
870 last = len(compound) - 1
871 for i,flag in enumerate(compound):
875 comp_code('&$flag);')
878 code.append(comp_code)
880 code('} // namespace Debug')
882 code.write(str(target[0]))
884 def makeDebugFlagHH(target, source, env):
885 assert(len(target) == 1 and len(source) == 1)
887 val = eval(source[0].get_contents())
888 name, compound, desc = val
890 code = code_formatter()
892 # file header boilerplate
895 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
898 #ifndef __DEBUG_${name}_HH__
899 #define __DEBUG_${name}_HH__
905 code('class CompoundFlag;')
906 code('class SimpleFlag;')
909 code('extern CompoundFlag $name;')
910 for flag in compound:
911 code('extern SimpleFlag $flag;')
913 code('extern SimpleFlag $name;')
918 #endif // __DEBUG_${name}_HH__
921 code.write(str(target[0]))
923 for name,flag in sorted(debug_flags.iteritems()):
924 n, compound, desc = flag
927 hh_file = 'debug/%s.hh' % name
928 env.Command(hh_file, Value(flag),
929 MakeAction(makeDebugFlagHH, Transform("TRACING", 0)))
931 env.Command('debug/flags.cc', Value(debug_flags),
932 MakeAction(makeDebugFlagCC, Transform("TRACING", 0)))
933 Source('debug/flags.cc')
937 env.Command('sim/tags.cc', None,
938 MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET',
939 Transform("VER TAGS")))
940 env.AlwaysBuild(tags)
942 # Embed python files. All .py files that have been indicated by a
943 # PySource() call in a SConscript need to be embedded into the M5
944 # library. To do that, we compile the file to byte code, marshal the
945 # byte code, compress it, and then generate a c++ file that
946 # inserts the result into an array.
947 def embedPyFile(target, source, env):
951 return '"%s"' % string
953 '''Action function to compile a .py into a code object, marshal
954 it, compress it, and stick it into an asm file so the code appears
955 as just bytes with a label in the data section'''
957 src = file(str(source[0]), 'r').read()
959 pysource = PySource.tnodes[source[0]]
960 compiled = compile(src, pysource.abspath, 'exec')
961 marshalled = marshal.dumps(compiled)
962 compressed = zlib.compress(marshalled)
964 sym = pysource.symname
966 code = code_formatter()
968 #include "sim/init.hh"
972 const uint8_t data_${sym}[] = {
976 for i in xrange(0, len(data), step):
977 x = array.array('B', data[i:i+step])
978 code(''.join('%d,' % d for d in x))
983 EmbeddedPython embedded_${sym}(
984 ${{c_str(pysource.arcname)}},
985 ${{c_str(pysource.abspath)}},
986 ${{c_str(pysource.modpath)}},
989 ${{len(marshalled)}});
991 } // anonymous namespace
993 code.write(str(target[0]))
995 for source in PySource.all:
996 env.Command(source.cpp, source.tnode,
997 MakeAction(embedPyFile, Transform("EMBED PY")))
998 Source(source.cpp, tags=source.tags, add_tags='python')
1000 ########################################################################
1002 # Define binaries. Each different build type (debug, opt, etc.) gets
1003 # a slightly different build environment.
1006 # List of constructed environments to pass back to SConstruct
1007 date_source = Source('base/date.cc', tags=[])
1009 # Function to create a new build environment as clone of current
1010 # environment 'env' with modified object suffix and optional stripped
1011 # binary. Additional keyword arguments are appended to corresponding
1012 # build environment vars.
1013 def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs):
1014 # SCons doesn't know to append a library suffix when there is a '.' in the
1015 # name. Use '_' instead.
1016 libname = 'gem5_' + label
1017 exename = 'gem5.' + label
1018 secondary_exename = 'm5.' + label
1020 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
1021 new_env.Label = label
1022 new_env.Append(**kwargs)
1024 lib_sources = Source.all.with_tag('gem5 lib')
1026 # Without Python, leave out all Python content from the library
1027 # builds. The option doesn't affect gem5 built as a program
1028 if GetOption('without_python'):
1029 lib_sources = lib_sources.without_tag('python')
1034 for s in lib_sources.with_tag(Source.ungrouped_tag):
1035 static_objs.append(s.static(new_env))
1036 shared_objs.append(s.shared(new_env))
1038 for group in Source.source_groups:
1039 srcs = lib_sources.with_tag(Source.link_group_tag(group))
1043 group_static = [ s.static(new_env) for s in srcs ]
1044 group_shared = [ s.shared(new_env) for s in srcs ]
1046 # If partial linking is disabled, add these sources to the build
1047 # directly, and short circuit this loop.
1049 static_objs.extend(group_static)
1050 shared_objs.extend(group_shared)
1053 # Set up the static partially linked objects.
1054 file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial")
1055 target = File(joinpath(group, file_name))
1056 partial = env.PartialStatic(target=target, source=group_static)
1057 static_objs.extend(partial)
1059 # Set up the shared partially linked objects.
1060 file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial")
1061 target = File(joinpath(group, file_name))
1062 partial = env.PartialShared(target=target, source=group_shared)
1063 shared_objs.extend(partial)
1065 static_date = date_source.static(new_env)
1066 new_env.Depends(static_date, static_objs)
1067 static_objs.extend(static_date)
1069 shared_date = date_source.shared(new_env)
1070 new_env.Depends(shared_date, shared_objs)
1071 shared_objs.extend(shared_date)
1073 # First make a library of everything but main() so other programs can
1075 static_lib = new_env.StaticLibrary(libname, static_objs)
1076 shared_lib = new_env.SharedLibrary(libname, shared_objs)
1078 # Now link a stub with main() and the static library.
1079 main_objs = [ s.static(new_env) for s in Source.all.with_tag('main') ]
1081 for test in UnitTest.all:
1082 test_sources = Source.all.with_tag(str(test.target))
1083 test_objs = [ s.static(new_env) for s in test_sources ]
1085 test_objs += main_objs
1086 path = 'unittest/%s.%s' % (test.target, label)
1087 new_env.Program(path, test_objs + static_objs)
1089 gtest_env = new_env.Clone()
1090 gtest_env.Append(LIBS=gtest_env['GTEST_LIBS'])
1091 gtest_env.Append(CPPFLAGS=gtest_env['GTEST_CPPFLAGS'])
1092 gtestlib_sources = Source.all.with_tag('gtest lib')
1094 for test in GTest.all:
1095 test_sources = test.sources
1096 if not test.skip_lib:
1097 test_sources += gtestlib_sources
1098 for f in test.filters:
1099 test_sources += Source.all.apply_filter(f)
1100 test_objs = [ s.static(gtest_env) for s in test_sources ]
1101 gtests.append(gtest_env.Program(
1102 test.dir.File('%s.%s' % (test.target, label)), test_objs))
1104 gtest_target = Dir(new_env['BUILDDIR']).File('unittests.%s' % label)
1105 AlwaysBuild(gtest_env.Command(gtest_target, gtests, gtests))
1109 progname += '.unstripped'
1111 targets = new_env.Program(progname, main_objs + static_objs)
1114 if sys.platform == 'sunos5':
1115 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1117 cmd = 'strip $SOURCE -o $TARGET'
1118 targets = new_env.Command(exename, progname,
1119 MakeAction(cmd, Transform("STRIP")))
1121 new_env.Command(secondary_exename, exename,
1122 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK")))
1124 new_env.M5Binary = targets[0]
1126 # Set up regression tests.
1127 SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'),
1128 variant_dir=Dir('tests').Dir(new_env.Label),
1129 exports={ 'env' : new_env }, duplicate=False)
1131 # Start out with the compiler flags common to all compilers,
1132 # i.e. they all use -g for opt and -g -pg for prof
1133 ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'],
1136 # Start out with the linker flags common to all linkers, i.e. -pg for
1137 # prof, and -lprofiler for perf. The -lprofile flag is surrounded by
1138 # no-as-needed and as-needed as the binutils linker is too clever and
1139 # simply doesn't link to the library otherwise.
1140 ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'],
1141 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']}
1143 # For Link Time Optimization, the optimisation flags used to compile
1144 # individual files are decoupled from those used at link time
1145 # (i.e. you can compile with -O3 and perform LTO with -O0), so we need
1146 # to also update the linker flags based on the target.
1148 if sys.platform == 'sunos5':
1149 ccflags['debug'] += ['-gstabs+']
1151 ccflags['debug'] += ['-ggdb3']
1152 ldflags['debug'] += ['-O0']
1153 # opt, fast, prof and perf all share the same cc flags, also add
1154 # the optimization to the ldflags as LTO defers the optimization
1156 for target in ['opt', 'fast', 'prof', 'perf']:
1157 ccflags[target] += ['-O3']
1158 ldflags[target] += ['-O3']
1160 ccflags['fast'] += env['LTO_CCFLAGS']
1161 ldflags['fast'] += env['LTO_LDFLAGS']
1163 ccflags['debug'] += ['-g', '-O0']
1164 # opt, fast, prof and perf all share the same cc flags
1165 for target in ['opt', 'fast', 'prof', 'perf']:
1166 ccflags[target] += ['-O3']
1168 print 'Unknown compiler, please fix compiler options'
1172 # To speed things up, we only instantiate the build environments we
1173 # need. We try to identify the needed environment for each target; if
1174 # we can't, we fall back on instantiating all the environments just to
1176 target_types = ['debug', 'opt', 'fast', 'prof', 'perf']
1177 obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof',
1180 def identifyTarget(t):
1181 ext = t.split('.')[-1]
1182 if ext in target_types:
1184 if obj2target.has_key(ext):
1185 return obj2target[ext]
1186 match = re.search(r'/tests/([^/]+)/', t)
1187 if match and match.group(1) in target_types:
1188 return match.group(1)
1191 needed_envs = [identifyTarget(target) for target in BUILD_TARGETS]
1192 if 'all' in needed_envs:
1193 needed_envs += target_types
1196 if 'debug' in needed_envs:
1197 makeEnv(env, 'debug', '.do',
1198 CCFLAGS = Split(ccflags['debug']),
1199 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'],
1200 LINKFLAGS = Split(ldflags['debug']))
1203 if 'opt' in needed_envs:
1204 makeEnv(env, 'opt', '.o',
1205 CCFLAGS = Split(ccflags['opt']),
1206 CPPDEFINES = ['TRACING_ON=1'],
1207 LINKFLAGS = Split(ldflags['opt']))
1210 if 'fast' in needed_envs:
1212 env.get('BROKEN_INCREMENTAL_LTO', False) and \
1213 GetOption('force_lto')
1214 makeEnv(env, 'fast', '.fo', strip = True,
1215 CCFLAGS = Split(ccflags['fast']),
1216 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1217 LINKFLAGS = Split(ldflags['fast']),
1218 disable_partial=disable_partial)
1220 # Profiled binary using gprof
1221 if 'prof' in needed_envs:
1222 makeEnv(env, 'prof', '.po',
1223 CCFLAGS = Split(ccflags['prof']),
1224 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1225 LINKFLAGS = Split(ldflags['prof']))
1227 # Profiled binary using google-pprof
1228 if 'perf' in needed_envs:
1229 makeEnv(env, 'perf', '.gpo',
1230 CCFLAGS = Split(ccflags['perf']),
1231 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1232 LINKFLAGS = Split(ldflags['perf']))