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