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