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