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
41 from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
45 from gem5_scons import Transform
47 # This file defines how to build a particular configuration of gem5
48 # based on variable settings in the 'env' build environment.
52 # Children need to see the environment
55 build_env = [(opt, env[opt]) for opt in export_vars]
57 from m5.util import code_formatter, compareVersions
59 ########################################################################
60 # Code for adding source files of various types
62 # When specifying a source file of some type, a set of tags can be
63 # specified for that file.
65 class SourceList(list):
66 def with_tags_that(self, predicate):
67 '''Return a list of sources with tags that satisfy a predicate.'''
69 return predicate(source.tags)
70 return SourceList(filter(match, self))
72 def with_any_tags(self, *tags):
73 '''Return a list of sources with any of the supplied tags.'''
74 return self.with_tags_that(lambda stags: len(tags & stags) > 0)
76 def with_all_tags(self, *tags):
77 '''Return a list of sources with all of the supplied tags.'''
78 return self.with_tags_that(lambda stags: tags <= stags)
80 def with_tag(self, tag):
81 '''Return a list of sources with the supplied tag.'''
82 return self.with_tags_that(lambda stags: tag in stags)
84 def without_tags(self, *tags):
85 '''Return a list of sources without any of the supplied tags.'''
86 return self.with_tags_that(lambda stags: len(tags & stags) == 0)
88 def without_tag(self, tag):
89 '''Return a list of sources with the supplied tag.'''
90 return self.with_tags_that(lambda stags: tag not in stags)
92 class SourceMeta(type):
93 '''Meta class for source files that keeps track of all files of a
95 def __init__(cls, name, bases, dict):
96 super(SourceMeta, cls).__init__(name, bases, dict)
97 cls.all = SourceList()
99 class SourceFile(object):
100 '''Base object that encapsulates the notion of a source file.
101 This includes, the source node, target node, various manipulations
102 of those. A source file also specifies a set of tags which
103 describing arbitrary properties of the source file.'''
104 __metaclass__ = SourceMeta
105 def __init__(self, source, tags=None, add_tags=None):
108 if isinstance(tags, basestring):
110 if isinstance(add_tags, basestring):
111 add_tags = set([add_tags])
113 tags = tags | add_tags
114 self.tags = set(tags)
117 if not isinstance(source, SCons.Node.FS.File):
121 self.snode = tnode.srcnode()
123 for base in type(self).__mro__:
124 if issubclass(base, SourceFile):
125 base.all.append(self)
129 return str(self.tnode)
133 return dirname(self.filename)
137 return basename(self.filename)
141 index = self.basename.rfind('.')
143 # dot files aren't extensions
144 return self.basename, None
146 return self.basename[:index], self.basename[index+1:]
148 def __lt__(self, other): return self.filename < other.filename
149 def __le__(self, other): return self.filename <= other.filename
150 def __gt__(self, other): return self.filename > other.filename
151 def __ge__(self, other): return self.filename >= other.filename
152 def __eq__(self, other): return self.filename == other.filename
153 def __ne__(self, other): return self.filename != other.filename
155 class Source(SourceFile):
156 ungrouped_tag = 'No link group'
157 source_groups = set()
159 _current_group_tag = ungrouped_tag
162 def link_group_tag(group):
163 return 'link group: %s' % group
166 def set_group(cls, group):
167 new_tag = Source.link_group_tag(group)
168 Source._current_group_tag = new_tag
169 Source.source_groups.add(group)
171 def _add_link_group_tag(self):
172 self.tags.add(Source._current_group_tag)
174 '''Add a c/c++ source file to the build'''
175 def __init__(self, source, tags=None, add_tags=None):
176 '''specify the source file, and any tags'''
177 super(Source, self).__init__(source, tags, add_tags)
178 self._add_link_group_tag()
180 class PySource(SourceFile):
181 '''Add a python source file to the named package'''
182 invalid_sym_char = re.compile('[^A-z0-9_]')
187 def __init__(self, package, source, tags=None, add_tags=None):
188 '''specify the python package, the source file, and any tags'''
189 super(PySource, self).__init__(source, tags, add_tags)
191 modname,ext = self.extname
195 path = package.split('.')
200 if modname != '__init__':
201 modpath += [ modname ]
202 modpath = '.'.join(modpath)
204 arcpath = path + [ self.basename ]
205 abspath = self.snode.abspath
206 if not exists(abspath):
207 abspath = self.tnode.abspath
209 self.package = package
210 self.modname = modname
211 self.modpath = modpath
212 self.arcname = joinpath(*arcpath)
213 self.abspath = abspath
214 self.compiled = File(self.filename + 'c')
215 self.cpp = File(self.filename + '.cc')
216 self.symname = PySource.invalid_sym_char.sub('_', modpath)
218 PySource.modules[modpath] = self
219 PySource.tnodes[self.tnode] = self
220 PySource.symnames[self.symname] = self
222 class SimObject(PySource):
223 '''Add a SimObject python file as a python source object and add
224 it to a list of sim object modules'''
229 def __init__(self, source, tags=None, add_tags=None):
230 '''Specify the source file and any tags (automatically in
231 the m5.objects package)'''
232 super(SimObject, self).__init__('m5.objects', source, tags, add_tags)
234 raise AttributeError, "Too late to call SimObject now."
236 bisect.insort_right(SimObject.modnames, self.modname)
238 class ProtoBuf(SourceFile):
239 '''Add a Protocol Buffer to build'''
241 def __init__(self, source, tags=None, add_tags=None):
242 '''Specify the source file, and any tags'''
243 super(ProtoBuf, self).__init__(source, tags, add_tags)
245 # Get the file name and the extension
246 modname,ext = self.extname
247 assert ext == 'proto'
249 # Currently, we stick to generating the C++ headers, so we
250 # only need to track the source and header.
251 self.cc_file = File(modname + '.pb.cc')
252 self.hh_file = File(modname + '.pb.h')
254 class UnitTest(object):
255 '''Create a UnitTest'''
258 def __init__(self, target, *sources, **kwargs):
259 '''Specify the target name and any sources. Sources that are
260 not SourceFiles are evalued with Source(). All files are
261 tagged with the name of the UnitTest target.'''
265 if not isinstance(src, SourceFile):
266 src = Source(src, tags=str(target))
271 self.main = kwargs.get('main', False)
272 UnitTest.all.append(self)
274 # Children should have access
281 ########################################################################
286 def DebugFlag(name, desc=None):
287 if name in debug_flags:
288 raise AttributeError, "Flag %s already specified" % name
289 debug_flags[name] = (name, (), desc)
291 def CompoundFlag(name, flags, desc=None):
292 if name in debug_flags:
293 raise AttributeError, "Flag %s already specified" % name
295 compound = tuple(flags)
296 debug_flags[name] = (name, compound, desc)
299 Export('CompoundFlag')
301 ########################################################################
303 # Set some compiler variables
306 # Include file paths are rooted in this directory. SCons will
307 # automatically expand '.' to refer to both the source directory and
308 # the corresponding build directory to pick up generated include
310 env.Append(CPPPATH=Dir('.'))
312 for extra_dir in extras_dir_list:
313 env.Append(CPPPATH=Dir(extra_dir))
315 # Workaround for bug in SCons version > 0.97d20071212
316 # Scons bug id: 2006 gem5 Bug id: 308
317 for root, dirs, files in os.walk(base_dir, topdown=True):
318 Dir(root[len(base_dir) + 1:])
320 ########################################################################
322 # Walk the tree and execute all SConscripts in subdirectories
325 here = Dir('.').srcnode().abspath
326 for root, dirs, files in os.walk(base_dir, topdown=True):
328 # we don't want to recurse back into this SConscript
331 if 'SConscript' in files:
332 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
333 Source.set_group(build_dir)
334 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
336 for extra_dir in extras_dir_list:
337 prefix_len = len(dirname(extra_dir)) + 1
339 # Also add the corresponding build directory to pick up generated
341 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:])))
343 for root, dirs, files in os.walk(extra_dir, topdown=True):
344 # if build lives in the extras directory, don't walk down it
348 if 'SConscript' in files:
349 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
350 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
352 for opt in export_vars:
355 def makeTheISA(source, target, env):
356 isas = [ src.get_contents() for src in source ]
357 target_isa = env['TARGET_ISA']
359 return isa.upper() + '_ISA'
362 return isa[0].upper() + isa[1:].lower() + 'ISA'
365 code = code_formatter()
367 #ifndef __CONFIG_THE_ISA_HH__
368 #define __CONFIG_THE_ISA_HH__
372 # create defines for the preprocessing and compile-time determination
373 for i,isa in enumerate(isas):
374 code('#define $0 $1', define(isa), i + 1)
377 # create an enum for any run-time determination of the ISA, we
378 # reuse the same name as the namespaces
379 code('enum class Arch {')
380 for i,isa in enumerate(isas):
381 if i + 1 == len(isas):
382 code(' $0 = $1', namespace(isa), define(isa))
384 code(' $0 = $1,', namespace(isa), define(isa))
389 #define THE_ISA ${{define(target_isa)}}
390 #define TheISA ${{namespace(target_isa)}}
391 #define THE_ISA_STR "${{target_isa}}"
393 #endif // __CONFIG_THE_ISA_HH__''')
395 code.write(str(target[0]))
397 env.Command('config/the_isa.hh', map(Value, all_isa_list),
398 MakeAction(makeTheISA, Transform("CFG ISA", 0)))
400 def makeTheGPUISA(source, target, env):
401 isas = [ src.get_contents() for src in source ]
402 target_gpu_isa = env['TARGET_GPU_ISA']
404 return isa.upper() + '_ISA'
407 return isa[0].upper() + isa[1:].lower() + 'ISA'
410 code = code_formatter()
412 #ifndef __CONFIG_THE_GPU_ISA_HH__
413 #define __CONFIG_THE_GPU_ISA_HH__
417 # create defines for the preprocessing and compile-time determination
418 for i,isa in enumerate(isas):
419 code('#define $0 $1', define(isa), i + 1)
422 # create an enum for any run-time determination of the ISA, we
423 # reuse the same name as the namespaces
424 code('enum class GPUArch {')
425 for i,isa in enumerate(isas):
426 if i + 1 == len(isas):
427 code(' $0 = $1', namespace(isa), define(isa))
429 code(' $0 = $1,', namespace(isa), define(isa))
434 #define THE_GPU_ISA ${{define(target_gpu_isa)}}
435 #define TheGpuISA ${{namespace(target_gpu_isa)}}
436 #define THE_GPU_ISA_STR "${{target_gpu_isa}}"
438 #endif // __CONFIG_THE_GPU_ISA_HH__''')
440 code.write(str(target[0]))
442 env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list),
443 MakeAction(makeTheGPUISA, Transform("CFG ISA", 0)))
445 ########################################################################
447 # Prevent any SimObjects from being added after this point, they
448 # should all have been added in the SConscripts above
450 SimObject.fixed = True
452 class DictImporter(object):
453 '''This importer takes a dictionary of arbitrary module names that
454 map to arbitrary filenames.'''
455 def __init__(self, modules):
456 self.modules = modules
457 self.installed = set()
464 for module in self.installed:
465 del sys.modules[module]
466 self.installed = set()
468 def find_module(self, fullname, path):
469 if fullname == 'm5.defines':
472 if fullname == 'm5.objects':
475 if fullname.startswith('_m5'):
478 source = self.modules.get(fullname, None)
479 if source is not None and fullname.startswith('m5.objects'):
484 def load_module(self, fullname):
485 mod = imp.new_module(fullname)
486 sys.modules[fullname] = mod
487 self.installed.add(fullname)
489 mod.__loader__ = self
490 if fullname == 'm5.objects':
491 mod.__path__ = fullname.split('.')
494 if fullname == 'm5.defines':
495 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
498 source = self.modules[fullname]
499 if source.modname == '__init__':
500 mod.__path__ = source.modpath
501 mod.__file__ = source.abspath
503 exec file(source.abspath, 'r') in mod.__dict__
509 from m5.util import code_formatter
514 # install the python importer so we can grab stuff from the source
515 # tree itself. We can't have SimObjects added after this point or
516 # else we won't know about them for the rest of the stuff.
517 importer = DictImporter(PySource.modules)
518 sys.meta_path[0:0] = [ importer ]
520 # import all sim objects so we can populate the all_objects list
521 # make sure that we're working with a list, then let's sort it
522 for modname in SimObject.modnames:
523 exec('from m5.objects import %s' % modname)
525 # we need to unload all of the currently imported modules so that they
526 # will be re-imported the next time the sconscript is run
528 sys.meta_path.remove(importer)
530 sim_objects = m5.SimObject.allClasses
531 all_enums = m5.params.allEnums
533 for name,obj in sorted(sim_objects.iteritems()):
534 for param in obj._params.local.values():
535 # load the ptype attribute now because it depends on the
536 # current version of SimObject.allClasses, but when scons
537 # actually uses the value, all versions of
538 # SimObject.allClasses will have been loaded
541 ########################################################################
543 # calculate extra dependencies
545 module_depends = ["m5", "m5.SimObject", "m5.params"]
546 depends = [ PySource.modules[dep].snode for dep in module_depends ]
547 depends.sort(key = lambda x: x.name)
549 ########################################################################
551 # Commands for the basic automatically generated python files
554 # Generate Python file containing a dict specifying the current
556 def makeDefinesPyFile(target, source, env):
557 build_env = source[0].get_contents()
559 code = code_formatter()
564 buildEnv = m5.util.SmartDict($build_env)
566 compileDate = _m5.core.compileDate
568 for key,val in _m5.core.__dict__.iteritems():
569 if key.startswith('flag_'):
574 code.write(target[0].abspath)
576 defines_info = Value(build_env)
577 # Generate a file with all of the compile options in it
578 env.Command('python/m5/defines.py', defines_info,
579 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
580 PySource('m5', 'python/m5/defines.py')
582 # Generate python file containing info about the M5 source code
583 def makeInfoPyFile(target, source, env):
584 code = code_formatter()
586 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
587 code('$src = ${{repr(data)}}')
588 code.write(str(target[0]))
590 # Generate a file that wraps the basic top level files
591 env.Command('python/m5/info.py',
592 [ '#/COPYING', '#/LICENSE', '#/README', ],
593 MakeAction(makeInfoPyFile, Transform("INFO")))
594 PySource('m5', 'python/m5/info.py')
596 ########################################################################
598 # Create all of the SimObject param headers and enum headers
601 def createSimObjectParamStruct(target, source, env):
602 assert len(target) == 1 and len(source) == 1
604 name = source[0].get_text_contents()
605 obj = sim_objects[name]
607 code = code_formatter()
608 obj.cxx_param_decl(code)
609 code.write(target[0].abspath)
611 def createSimObjectCxxConfig(is_header):
612 def body(target, source, env):
613 assert len(target) == 1 and len(source) == 1
615 name = str(source[0].get_contents())
616 obj = sim_objects[name]
618 code = code_formatter()
619 obj.cxx_config_param_file(code, is_header)
620 code.write(target[0].abspath)
623 def createEnumStrings(target, source, env):
624 assert len(target) == 1 and len(source) == 2
626 name = source[0].get_text_contents()
627 use_python = source[1].read()
628 obj = all_enums[name]
630 code = code_formatter()
634 code.write(target[0].abspath)
636 def createEnumDecls(target, source, env):
637 assert len(target) == 1 and len(source) == 1
639 name = source[0].get_text_contents()
640 obj = all_enums[name]
642 code = code_formatter()
644 code.write(target[0].abspath)
646 def createSimObjectPyBindWrapper(target, source, env):
647 name = source[0].get_text_contents()
648 obj = sim_objects[name]
650 code = code_formatter()
651 obj.pybind_decl(code)
652 code.write(target[0].abspath)
654 # Generate all of the SimObject param C++ struct header files
656 for name,simobj in sorted(sim_objects.iteritems()):
657 py_source = PySource.modules[simobj.__module__]
658 extra_deps = [ py_source.tnode ]
660 hh_file = File('params/%s.hh' % name)
661 params_hh_files.append(hh_file)
662 env.Command(hh_file, Value(name),
663 MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
664 env.Depends(hh_file, depends + extra_deps)
666 # C++ parameter description files
667 if GetOption('with_cxx_config'):
668 for name,simobj in sorted(sim_objects.iteritems()):
669 py_source = PySource.modules[simobj.__module__]
670 extra_deps = [ py_source.tnode ]
672 cxx_config_hh_file = File('cxx_config/%s.hh' % name)
673 cxx_config_cc_file = File('cxx_config/%s.cc' % name)
674 env.Command(cxx_config_hh_file, Value(name),
675 MakeAction(createSimObjectCxxConfig(True),
676 Transform("CXXCPRHH")))
677 env.Command(cxx_config_cc_file, Value(name),
678 MakeAction(createSimObjectCxxConfig(False),
679 Transform("CXXCPRCC")))
680 env.Depends(cxx_config_hh_file, depends + extra_deps +
681 [File('params/%s.hh' % name), File('sim/cxx_config.hh')])
682 env.Depends(cxx_config_cc_file, depends + extra_deps +
683 [cxx_config_hh_file])
684 Source(cxx_config_cc_file)
686 cxx_config_init_cc_file = File('cxx_config/init.cc')
688 def createCxxConfigInitCC(target, source, env):
689 assert len(target) == 1 and len(source) == 1
691 code = code_formatter()
693 for name,simobj in sorted(sim_objects.iteritems()):
694 if not hasattr(simobj, 'abstract') or not simobj.abstract:
695 code('#include "cxx_config/${name}.hh"')
697 code('void cxxConfigInit()')
700 for name,simobj in sorted(sim_objects.iteritems()):
701 not_abstract = not hasattr(simobj, 'abstract') or \
703 if not_abstract and 'type' in simobj.__dict__:
704 code('cxx_config_directory["${name}"] = '
705 '${name}CxxConfigParams::makeDirectoryEntry();')
708 code.write(target[0].abspath)
710 py_source = PySource.modules[simobj.__module__]
711 extra_deps = [ py_source.tnode ]
712 env.Command(cxx_config_init_cc_file, Value(name),
713 MakeAction(createCxxConfigInitCC, Transform("CXXCINIT")))
714 cxx_param_hh_files = ["cxx_config/%s.hh" % simobj
715 for name,simobj in sorted(sim_objects.iteritems())
716 if not hasattr(simobj, 'abstract') or not simobj.abstract]
717 Depends(cxx_config_init_cc_file, cxx_param_hh_files +
718 [File('sim/cxx_config.hh')])
719 Source(cxx_config_init_cc_file)
721 # Generate all enum header files
722 for name,enum in sorted(all_enums.iteritems()):
723 py_source = PySource.modules[enum.__module__]
724 extra_deps = [ py_source.tnode ]
726 cc_file = File('enums/%s.cc' % name)
727 env.Command(cc_file, [Value(name), Value(env['USE_PYTHON'])],
728 MakeAction(createEnumStrings, Transform("ENUM STR")))
729 env.Depends(cc_file, depends + extra_deps)
732 hh_file = File('enums/%s.hh' % name)
733 env.Command(hh_file, Value(name),
734 MakeAction(createEnumDecls, Transform("ENUMDECL")))
735 env.Depends(hh_file, depends + extra_deps)
737 # Generate SimObject Python bindings wrapper files
738 if env['USE_PYTHON']:
739 for name,simobj in sorted(sim_objects.iteritems()):
740 py_source = PySource.modules[simobj.__module__]
741 extra_deps = [ py_source.tnode ]
742 cc_file = File('python/_m5/param_%s.cc' % name)
743 env.Command(cc_file, Value(name),
744 MakeAction(createSimObjectPyBindWrapper,
745 Transform("SO PyBind")))
746 env.Depends(cc_file, depends + extra_deps)
749 # Build all protocol buffers if we have got protoc and protobuf available
750 if env['HAVE_PROTOBUF']:
751 for proto in ProtoBuf.all:
752 # Use both the source and header as the target, and the .proto
753 # file as the source. When executing the protoc compiler, also
754 # specify the proto_path to avoid having the generated files
756 env.Command([proto.cc_file, proto.hh_file], proto.tnode,
757 MakeAction('$PROTOC --cpp_out ${TARGET.dir} '
758 '--proto_path ${SOURCE.dir} $SOURCE',
759 Transform("PROTOC")))
761 # Add the C++ source file
762 Source(proto.cc_file, tags=proto.tags)
764 print 'Got protobuf to build, but lacks support!'
770 def makeDebugFlagCC(target, source, env):
771 assert(len(target) == 1 and len(source) == 1)
773 code = code_formatter()
775 # delay definition of CompoundFlags until after all the definition
776 # of all constituent SimpleFlags
777 comp_code = code_formatter()
782 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
785 #include "base/debug.hh"
791 for name, flag in sorted(source[0].read().iteritems()):
792 n, compound, desc = flag
796 code('SimpleFlag $name("$name", "$desc");')
798 comp_code('CompoundFlag $name("$name", "$desc",')
800 last = len(compound) - 1
801 for i,flag in enumerate(compound):
805 comp_code('&$flag);')
808 code.append(comp_code)
810 code('} // namespace Debug')
812 code.write(str(target[0]))
814 def makeDebugFlagHH(target, source, env):
815 assert(len(target) == 1 and len(source) == 1)
817 val = eval(source[0].get_contents())
818 name, compound, desc = val
820 code = code_formatter()
822 # file header boilerplate
825 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
828 #ifndef __DEBUG_${name}_HH__
829 #define __DEBUG_${name}_HH__
835 code('class CompoundFlag;')
836 code('class SimpleFlag;')
839 code('extern CompoundFlag $name;')
840 for flag in compound:
841 code('extern SimpleFlag $flag;')
843 code('extern SimpleFlag $name;')
848 #endif // __DEBUG_${name}_HH__
851 code.write(str(target[0]))
853 for name,flag in sorted(debug_flags.iteritems()):
854 n, compound, desc = flag
857 hh_file = 'debug/%s.hh' % name
858 env.Command(hh_file, Value(flag),
859 MakeAction(makeDebugFlagHH, Transform("TRACING", 0)))
861 env.Command('debug/flags.cc', Value(debug_flags),
862 MakeAction(makeDebugFlagCC, Transform("TRACING", 0)))
863 Source('debug/flags.cc')
867 env.Command('sim/tags.cc', None,
868 MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET',
869 Transform("VER TAGS")))
870 env.AlwaysBuild(tags)
872 # Embed python files. All .py files that have been indicated by a
873 # PySource() call in a SConscript need to be embedded into the M5
874 # library. To do that, we compile the file to byte code, marshal the
875 # byte code, compress it, and then generate a c++ file that
876 # inserts the result into an array.
877 def embedPyFile(target, source, env):
881 return '"%s"' % string
883 '''Action function to compile a .py into a code object, marshal
884 it, compress it, and stick it into an asm file so the code appears
885 as just bytes with a label in the data section'''
887 src = file(str(source[0]), 'r').read()
889 pysource = PySource.tnodes[source[0]]
890 compiled = compile(src, pysource.abspath, 'exec')
891 marshalled = marshal.dumps(compiled)
892 compressed = zlib.compress(marshalled)
894 sym = pysource.symname
896 code = code_formatter()
898 #include "sim/init.hh"
902 const uint8_t data_${sym}[] = {
906 for i in xrange(0, len(data), step):
907 x = array.array('B', data[i:i+step])
908 code(''.join('%d,' % d for d in x))
913 EmbeddedPython embedded_${sym}(
914 ${{c_str(pysource.arcname)}},
915 ${{c_str(pysource.abspath)}},
916 ${{c_str(pysource.modpath)}},
919 ${{len(marshalled)}});
921 } // anonymous namespace
923 code.write(str(target[0]))
925 for source in PySource.all:
926 env.Command(source.cpp, source.tnode,
927 MakeAction(embedPyFile, Transform("EMBED PY")))
928 Source(source.cpp, tags=source.tags, add_tags='python')
930 ########################################################################
932 # Define binaries. Each different build type (debug, opt, etc.) gets
933 # a slightly different build environment.
936 # List of constructed environments to pass back to SConstruct
937 date_source = Source('base/date.cc', tags=[])
939 # Function to create a new build environment as clone of current
940 # environment 'env' with modified object suffix and optional stripped
941 # binary. Additional keyword arguments are appended to corresponding
942 # build environment vars.
943 def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs):
944 # SCons doesn't know to append a library suffix when there is a '.' in the
945 # name. Use '_' instead.
946 libname = 'gem5_' + label
947 exename = 'gem5.' + label
948 secondary_exename = 'm5.' + label
950 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
951 new_env.Label = label
952 new_env.Append(**kwargs)
954 make_static = lambda source: new_env.StaticObject(source.tnode)
955 make_shared = lambda source: new_env.SharedObject(source.tnode)
957 lib_sources = Source.all.with_tag('gem5 lib')
959 # Without Python, leave out all Python content from the library
960 # builds. The option doesn't affect gem5 built as a program
961 if GetOption('without_python'):
962 lib_sources = lib_sources.without_tag('python')
967 for s in lib_sources.with_tag(Source.ungrouped_tag):
968 static_objs.append(make_static(s))
969 shared_objs.append(make_shared(s))
971 for group in Source.source_groups:
972 srcs = lib_sources.with_tag(Source.link_group_tag(group))
976 group_static = [ make_static(s) for s in srcs ]
977 group_shared = [ make_shared(s) for s in srcs ]
979 # If partial linking is disabled, add these sources to the build
980 # directly, and short circuit this loop.
982 static_objs.extend(group_static)
983 shared_objs.extend(group_shared)
986 # Set up the static partially linked objects.
987 file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial")
988 target = File(joinpath(group, file_name))
989 partial = env.PartialStatic(target=target, source=group_static)
990 static_objs.extend(partial)
992 # Set up the shared partially linked objects.
993 file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial")
994 target = File(joinpath(group, file_name))
995 partial = env.PartialShared(target=target, source=group_shared)
996 shared_objs.extend(partial)
998 static_date = make_static(date_source)
999 new_env.Depends(static_date, static_objs)
1000 static_objs.extend(static_date)
1002 shared_date = make_shared(date_source)
1003 new_env.Depends(shared_date, shared_objs)
1004 shared_objs.extend(shared_date)
1006 # First make a library of everything but main() so other programs can
1008 static_lib = new_env.StaticLibrary(libname, static_objs)
1009 shared_lib = new_env.SharedLibrary(libname, shared_objs)
1011 # Now link a stub with main() and the static library.
1012 main_objs = [ make_static(s) for s in Source.all.with_tag('main') ]
1014 for test in UnitTest.all:
1015 test_sources = Source.all.with_tag(str(test.target))
1016 test_objs = [ make_static(s) for s in test_sources ]
1018 test_objs += main_objs
1019 path = 'unittest/%s.%s' % (test.target, label)
1020 new_env.Program(path, test_objs + static_objs)
1024 progname += '.unstripped'
1026 targets = new_env.Program(progname, main_objs + static_objs)
1029 if sys.platform == 'sunos5':
1030 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1032 cmd = 'strip $SOURCE -o $TARGET'
1033 targets = new_env.Command(exename, progname,
1034 MakeAction(cmd, Transform("STRIP")))
1036 new_env.Command(secondary_exename, exename,
1037 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK")))
1039 new_env.M5Binary = targets[0]
1041 # Set up regression tests.
1042 SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'),
1043 variant_dir=Dir('tests').Dir(new_env.Label),
1044 exports={ 'env' : new_env }, duplicate=False)
1046 # Start out with the compiler flags common to all compilers,
1047 # i.e. they all use -g for opt and -g -pg for prof
1048 ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'],
1051 # Start out with the linker flags common to all linkers, i.e. -pg for
1052 # prof, and -lprofiler for perf. The -lprofile flag is surrounded by
1053 # no-as-needed and as-needed as the binutils linker is too clever and
1054 # simply doesn't link to the library otherwise.
1055 ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'],
1056 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']}
1058 # For Link Time Optimization, the optimisation flags used to compile
1059 # individual files are decoupled from those used at link time
1060 # (i.e. you can compile with -O3 and perform LTO with -O0), so we need
1061 # to also update the linker flags based on the target.
1063 if sys.platform == 'sunos5':
1064 ccflags['debug'] += ['-gstabs+']
1066 ccflags['debug'] += ['-ggdb3']
1067 ldflags['debug'] += ['-O0']
1068 # opt, fast, prof and perf all share the same cc flags, also add
1069 # the optimization to the ldflags as LTO defers the optimization
1071 for target in ['opt', 'fast', 'prof', 'perf']:
1072 ccflags[target] += ['-O3']
1073 ldflags[target] += ['-O3']
1075 ccflags['fast'] += env['LTO_CCFLAGS']
1076 ldflags['fast'] += env['LTO_LDFLAGS']
1078 ccflags['debug'] += ['-g', '-O0']
1079 # opt, fast, prof and perf all share the same cc flags
1080 for target in ['opt', 'fast', 'prof', 'perf']:
1081 ccflags[target] += ['-O3']
1083 print 'Unknown compiler, please fix compiler options'
1087 # To speed things up, we only instantiate the build environments we
1088 # need. We try to identify the needed environment for each target; if
1089 # we can't, we fall back on instantiating all the environments just to
1091 target_types = ['debug', 'opt', 'fast', 'prof', 'perf']
1092 obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof',
1095 def identifyTarget(t):
1096 ext = t.split('.')[-1]
1097 if ext in target_types:
1099 if obj2target.has_key(ext):
1100 return obj2target[ext]
1101 match = re.search(r'/tests/([^/]+)/', t)
1102 if match and match.group(1) in target_types:
1103 return match.group(1)
1106 needed_envs = [identifyTarget(target) for target in BUILD_TARGETS]
1107 if 'all' in needed_envs:
1108 needed_envs += target_types
1111 if 'debug' in needed_envs:
1112 makeEnv(env, 'debug', '.do',
1113 CCFLAGS = Split(ccflags['debug']),
1114 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'],
1115 LINKFLAGS = Split(ldflags['debug']))
1118 if 'opt' in needed_envs:
1119 makeEnv(env, 'opt', '.o',
1120 CCFLAGS = Split(ccflags['opt']),
1121 CPPDEFINES = ['TRACING_ON=1'],
1122 LINKFLAGS = Split(ldflags['opt']))
1125 if 'fast' in needed_envs:
1127 env.get('BROKEN_INCREMENTAL_LTO', False) and \
1128 GetOption('force_lto')
1129 makeEnv(env, 'fast', '.fo', strip = True,
1130 CCFLAGS = Split(ccflags['fast']),
1131 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1132 LINKFLAGS = Split(ldflags['fast']),
1133 disable_partial=disable_partial)
1135 # Profiled binary using gprof
1136 if 'prof' in needed_envs:
1137 makeEnv(env, 'prof', '.po',
1138 CCFLAGS = Split(ccflags['prof']),
1139 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1140 LINKFLAGS = Split(ldflags['prof']))
1142 # Profiled binary using google-pprof
1143 if 'perf' in needed_envs:
1144 makeEnv(env, 'perf', '.gpo',
1145 CCFLAGS = Split(ccflags['perf']),
1146 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1147 LINKFLAGS = Split(ldflags['perf']))