params: small cleanup to param description internals
[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 i_file = File('params/%s_%s.i' % (name, param.file_ext))
493 params_i_files.append(i_file)
494 env.Command(i_file, Value(name), createSwigParam)
495 env.Depends(i_file, depends)
496
497 # Generate all enum header files
498 for name,enum in sorted(all_enums.iteritems()):
499 py_source = PySource.modules[enum.__module__]
500 extra_deps = [ py_source.tnode ]
501
502 cc_file = File('enums/%s.cc' % name)
503 env.Command(cc_file, Value(name), createEnumStrings)
504 env.Depends(cc_file, depends + extra_deps)
505 Source(cc_file)
506
507 hh_file = File('enums/%s.hh' % name)
508 env.Command(hh_file, Value(name), createEnumParam)
509 env.Depends(hh_file, depends + extra_deps)
510
511 # Build the big monolithic swigged params module (wraps all SimObject
512 # param structs and enum structs)
513 def buildParams(target, source, env):
514 names = [ s.get_contents() for s in source ]
515 objs = [ sim_objects[name] for name in names ]
516 out = file(target[0].abspath, 'w')
517
518 ordered_objs = []
519 obj_seen = set()
520 def order_obj(obj):
521 name = str(obj)
522 if name in obj_seen:
523 return
524
525 obj_seen.add(name)
526 if str(obj) != 'SimObject':
527 order_obj(obj.__bases__[0])
528
529 ordered_objs.append(obj)
530
531 for obj in objs:
532 order_obj(obj)
533
534 enums = set()
535 predecls = []
536 pd_seen = set()
537
538 def add_pds(*pds):
539 for pd in pds:
540 if pd not in pd_seen:
541 predecls.append(pd)
542 pd_seen.add(pd)
543
544 for obj in ordered_objs:
545 params = obj._params.local.values()
546 for param in params:
547 ptype = param.ptype
548 if issubclass(ptype, m5.params.Enum):
549 if ptype not in enums:
550 enums.add(ptype)
551 pds = param.swig_predecls()
552 if isinstance(pds, (list, tuple)):
553 add_pds(*pds)
554 else:
555 add_pds(pds)
556
557 print >>out, '%module params'
558
559 print >>out, '%{'
560 for obj in ordered_objs:
561 print >>out, '#include "params/%s.hh"' % obj
562 print >>out, '%}'
563
564 for pd in predecls:
565 print >>out, pd
566
567 enums = list(enums)
568 enums.sort()
569 for enum in enums:
570 print >>out, '%%include "enums/%s.hh"' % enum.__name__
571 print >>out
572
573 for obj in ordered_objs:
574 if obj.swig_objdecls:
575 for decl in obj.swig_objdecls:
576 print >>out, decl
577 continue
578
579 class_path = obj.cxx_class.split('::')
580 classname = class_path[-1]
581 namespaces = class_path[:-1]
582 namespaces.reverse()
583
584 code = ''
585
586 if namespaces:
587 code += '// avoid name conflicts\n'
588 sep_string = '_COLONS_'
589 flat_name = sep_string.join(class_path)
590 code += '%%rename(%s) %s;\n' % (flat_name, classname)
591
592 code += '// stop swig from creating/wrapping default ctor/dtor\n'
593 code += '%%nodefault %s;\n' % classname
594 code += 'class %s ' % classname
595 if obj._base:
596 code += ': public %s' % obj._base.cxx_class
597 code += ' {};\n'
598
599 for ns in namespaces:
600 new_code = 'namespace %s {\n' % ns
601 new_code += code
602 new_code += '}\n'
603 code = new_code
604
605 print >>out, code
606
607 print >>out, '%%include "src/sim/sim_object_params.hh"' % obj
608 for obj in ordered_objs:
609 print >>out, '%%include "params/%s.hh"' % obj
610
611 params_file = File('params/params.i')
612 names = sorted(sim_objects.keys())
613 env.Command(params_file, map(Value, names), buildParams)
614 env.Depends(params_file, params_hh_files + params_i_files + depends)
615 SwigSource('m5.objects', params_file)
616
617 # Build all swig modules
618 for swig in SwigSource.all:
619 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
620 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
621 '-o ${TARGETS[0]} $SOURCES')
622 env.Depends(swig.py_source.tnode, swig.tnode)
623 env.Depends(swig.cc_source.tnode, swig.tnode)
624
625 # Generate the main swig init file
626 def makeSwigInit(target, source, env):
627 f = file(str(target[0]), 'w')
628 print >>f, 'extern "C" {'
629 for module in source:
630 print >>f, ' void init_%s();' % module.get_contents()
631 print >>f, '}'
632 print >>f, 'void initSwig() {'
633 for module in source:
634 print >>f, ' init_%s();' % module.get_contents()
635 print >>f, '}'
636 f.close()
637
638 env.Command('python/swig/init.cc',
639 map(Value, sorted(s.module for s in SwigSource.all)),
640 makeSwigInit)
641 Source('python/swig/init.cc')
642
643 def getFlags(source_flags):
644 flagsMap = {}
645 flagsList = []
646 for s in source_flags:
647 val = eval(s.get_contents())
648 name, compound, desc = val
649 flagsList.append(val)
650 flagsMap[name] = bool(compound)
651
652 for name, compound, desc in flagsList:
653 for flag in compound:
654 if flag not in flagsMap:
655 raise AttributeError, "Trace flag %s not found" % flag
656 if flagsMap[flag]:
657 raise AttributeError, \
658 "Compound flag can't point to another compound flag"
659
660 flagsList.sort()
661 return flagsList
662
663
664 # Generate traceflags.py
665 def traceFlagsPy(target, source, env):
666 assert(len(target) == 1)
667
668 f = file(str(target[0]), 'w')
669
670 allFlags = getFlags(source)
671
672 print >>f, 'basic = ['
673 for flag, compound, desc in allFlags:
674 if not compound:
675 print >>f, " '%s'," % flag
676 print >>f, " ]"
677 print >>f
678
679 print >>f, 'compound = ['
680 print >>f, " 'All',"
681 for flag, compound, desc in allFlags:
682 if compound:
683 print >>f, " '%s'," % flag
684 print >>f, " ]"
685 print >>f
686
687 print >>f, "all = frozenset(basic + compound)"
688 print >>f
689
690 print >>f, 'compoundMap = {'
691 all = tuple([flag for flag,compound,desc in allFlags if not compound])
692 print >>f, " 'All' : %s," % (all, )
693 for flag, compound, desc in allFlags:
694 if compound:
695 print >>f, " '%s' : %s," % (flag, compound)
696 print >>f, " }"
697 print >>f
698
699 print >>f, 'descriptions = {'
700 print >>f, " 'All' : 'All flags',"
701 for flag, compound, desc in allFlags:
702 print >>f, " '%s' : '%s'," % (flag, desc)
703 print >>f, " }"
704
705 f.close()
706
707 def traceFlagsCC(target, source, env):
708 assert(len(target) == 1)
709
710 f = file(str(target[0]), 'w')
711
712 allFlags = getFlags(source)
713
714 # file header
715 print >>f, '''
716 /*
717 * DO NOT EDIT THIS FILE! Automatically generated
718 */
719
720 #include "base/traceflags.hh"
721
722 using namespace Trace;
723
724 const char *Trace::flagStrings[] =
725 {'''
726
727 # The string array is used by SimpleEnumParam to map the strings
728 # provided by the user to enum values.
729 for flag, compound, desc in allFlags:
730 if not compound:
731 print >>f, ' "%s",' % flag
732
733 print >>f, ' "All",'
734 for flag, compound, desc in allFlags:
735 if compound:
736 print >>f, ' "%s",' % flag
737
738 print >>f, '};'
739 print >>f
740 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
741 print >>f
742
743 #
744 # Now define the individual compound flag arrays. There is an array
745 # for each compound flag listing the component base flags.
746 #
747 all = tuple([flag for flag,compound,desc in allFlags if not compound])
748 print >>f, 'static const Flags AllMap[] = {'
749 for flag, compound, desc in allFlags:
750 if not compound:
751 print >>f, " %s," % flag
752 print >>f, '};'
753 print >>f
754
755 for flag, compound, desc in allFlags:
756 if not compound:
757 continue
758 print >>f, 'static const Flags %sMap[] = {' % flag
759 for flag in compound:
760 print >>f, " %s," % flag
761 print >>f, " (Flags)-1"
762 print >>f, '};'
763 print >>f
764
765 #
766 # Finally the compoundFlags[] array maps the compound flags
767 # to their individual arrays/
768 #
769 print >>f, 'const Flags *Trace::compoundFlags[] ='
770 print >>f, '{'
771 print >>f, ' AllMap,'
772 for flag, compound, desc in allFlags:
773 if compound:
774 print >>f, ' %sMap,' % flag
775 # file trailer
776 print >>f, '};'
777
778 f.close()
779
780 def traceFlagsHH(target, source, env):
781 assert(len(target) == 1)
782
783 f = file(str(target[0]), 'w')
784
785 allFlags = getFlags(source)
786
787 # file header boilerplate
788 print >>f, '''
789 /*
790 * DO NOT EDIT THIS FILE!
791 *
792 * Automatically generated from traceflags.py
793 */
794
795 #ifndef __BASE_TRACE_FLAGS_HH__
796 #define __BASE_TRACE_FLAGS_HH__
797
798 namespace Trace {
799
800 enum Flags {'''
801
802 # Generate the enum. Base flags come first, then compound flags.
803 idx = 0
804 for flag, compound, desc in allFlags:
805 if not compound:
806 print >>f, ' %s = %d,' % (flag, idx)
807 idx += 1
808
809 numBaseFlags = idx
810 print >>f, ' NumFlags = %d,' % idx
811
812 # put a comment in here to separate base from compound flags
813 print >>f, '''
814 // The remaining enum values are *not* valid indices for Trace::flags.
815 // They are "compound" flags, which correspond to sets of base
816 // flags, and are used by changeFlag.'''
817
818 print >>f, ' All = %d,' % idx
819 idx += 1
820 for flag, compound, desc in allFlags:
821 if compound:
822 print >>f, ' %s = %d,' % (flag, idx)
823 idx += 1
824
825 numCompoundFlags = idx - numBaseFlags
826 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags
827
828 # trailer boilerplate
829 print >>f, '''\
830 }; // enum Flags
831
832 // Array of strings for SimpleEnumParam
833 extern const char *flagStrings[];
834 extern const int numFlagStrings;
835
836 // Array of arraay pointers: for each compound flag, gives the list of
837 // base flags to set. Inidividual flag arrays are terminated by -1.
838 extern const Flags *compoundFlags[];
839
840 /* namespace Trace */ }
841
842 #endif // __BASE_TRACE_FLAGS_HH__
843 '''
844
845 f.close()
846
847 flags = map(Value, trace_flags.values())
848 env.Command('base/traceflags.py', flags, traceFlagsPy)
849 PySource('m5', 'base/traceflags.py')
850
851 env.Command('base/traceflags.hh', flags, traceFlagsHH)
852 env.Command('base/traceflags.cc', flags, traceFlagsCC)
853 Source('base/traceflags.cc')
854
855 # embed python files. All .py files that have been indicated by a
856 # PySource() call in a SConscript need to be embedded into the M5
857 # library. To do that, we compile the file to byte code, marshal the
858 # byte code, compress it, and then generate an assembly file that
859 # inserts the result into the data section with symbols indicating the
860 # beginning, and end (and with the size at the end)
861 def objectifyPyFile(target, source, env):
862 '''Action function to compile a .py into a code object, marshal
863 it, compress it, and stick it into an asm file so the code appears
864 as just bytes with a label in the data section'''
865
866 src = file(str(source[0]), 'r').read()
867 dst = file(str(target[0]), 'w')
868
869 pysource = PySource.tnodes[source[0]]
870 compiled = compile(src, pysource.debugname, 'exec')
871 marshalled = marshal.dumps(compiled)
872 compressed = zlib.compress(marshalled)
873 data = compressed
874
875 # Some C/C++ compilers prepend an underscore to global symbol
876 # names, so if they're going to do that, we need to prepend that
877 # leading underscore to globals in the assembly file.
878 if env['LEADING_UNDERSCORE']:
879 sym = '_' + pysource.symname
880 else:
881 sym = pysource.symname
882
883 step = 16
884 print >>dst, ".data"
885 print >>dst, ".globl %s_beg" % sym
886 print >>dst, ".globl %s_end" % sym
887 print >>dst, "%s_beg:" % sym
888 for i in xrange(0, len(data), step):
889 x = array.array('B', data[i:i+step])
890 print >>dst, ".byte", ','.join([str(d) for d in x])
891 print >>dst, "%s_end:" % sym
892 print >>dst, ".long %d" % len(marshalled)
893
894 for source in PySource.all:
895 env.Command(source.assembly, source.tnode, objectifyPyFile)
896 Source(source.assembly)
897
898 # Generate init_python.cc which creates a bunch of EmbeddedPyModule
899 # structs that describe the embedded python code. One such struct
900 # contains information about the importer that python uses to get at
901 # the embedded files, and then there's a list of all of the rest that
902 # the importer uses to load the rest on demand.
903 def pythonInit(target, source, env):
904 dst = file(str(target[0]), 'w')
905
906 def dump_mod(sym, endchar=','):
907 pysource = PySource.symnames[sym]
908 print >>dst, ' { "%s",' % pysource.arcname
909 print >>dst, ' "%s",' % pysource.modpath
910 print >>dst, ' %s_beg, %s_end,' % (sym, sym)
911 print >>dst, ' %s_end - %s_beg,' % (sym, sym)
912 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar)
913
914 print >>dst, '#include "sim/init.hh"'
915
916 for sym in source:
917 sym = sym.get_contents()
918 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym)
919
920 print >>dst, "const EmbeddedPyModule embeddedPyImporter = "
921 dump_mod("PyEMB_importer", endchar=';');
922 print >>dst
923
924 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {"
925 for i,sym in enumerate(source):
926 sym = sym.get_contents()
927 if sym == "PyEMB_importer":
928 # Skip the importer since we've already exported it
929 continue
930 dump_mod(sym)
931 print >>dst, " { 0, 0, 0, 0, 0, 0 }"
932 print >>dst, "};"
933
934
935 env.Command('sim/init_python.cc',
936 map(Value, (s.symname for s in PySource.all)),
937 pythonInit)
938 Source('sim/init_python.cc')
939
940 ########################################################################
941 #
942 # Define binaries. Each different build type (debug, opt, etc.) gets
943 # a slightly different build environment.
944 #
945
946 # List of constructed environments to pass back to SConstruct
947 envList = []
948
949 date_source = Source('base/date.cc', skip_lib=True)
950
951 # Function to create a new build environment as clone of current
952 # environment 'env' with modified object suffix and optional stripped
953 # binary. Additional keyword arguments are appended to corresponding
954 # build environment vars.
955 def makeEnv(label, objsfx, strip = False, **kwargs):
956 # SCons doesn't know to append a library suffix when there is a '.' in the
957 # name. Use '_' instead.
958 libname = 'm5_' + label
959 exename = 'm5.' + label
960
961 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
962 new_env.Label = label
963 new_env.Append(**kwargs)
964
965 swig_env = new_env.Clone()
966 swig_env.Append(CCFLAGS='-Werror')
967 if env['GCC']:
968 swig_env.Append(CCFLAGS='-Wno-uninitialized')
969 swig_env.Append(CCFLAGS='-Wno-sign-compare')
970 swig_env.Append(CCFLAGS='-Wno-parentheses')
971
972 werror_env = new_env.Clone()
973 werror_env.Append(CCFLAGS='-Werror')
974
975 def make_obj(source, static, extra_deps = None):
976 '''This function adds the specified source to the correct
977 build environment, and returns the corresponding SCons Object
978 nodes'''
979
980 if source.swig:
981 env = swig_env
982 elif source.Werror:
983 env = werror_env
984 else:
985 env = new_env
986
987 if static:
988 obj = env.StaticObject(source.tnode)
989 else:
990 obj = env.SharedObject(source.tnode)
991
992 if extra_deps:
993 env.Depends(obj, extra_deps)
994
995 return obj
996
997 static_objs = [ make_obj(s, True) for s in Source.get(skip_lib=False)]
998 shared_objs = [ make_obj(s, False) for s in Source.get(skip_lib=False)]
999
1000 static_date = make_obj(date_source, static=True, extra_deps=static_objs)
1001 static_objs.append(static_date)
1002
1003 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
1004 shared_objs.append(shared_date)
1005
1006 # First make a library of everything but main() so other programs can
1007 # link against m5.
1008 static_lib = new_env.StaticLibrary(libname, static_objs)
1009 shared_lib = new_env.SharedLibrary(libname, shared_objs)
1010
1011 for target, sources in unit_tests:
1012 objs = [ make_obj(s, static=True) for s in sources ]
1013 new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs)
1014
1015 # Now link a stub with main() and the static library.
1016 bin_objs = [make_obj(s, True) for s in Source.get(bin_only=True) ]
1017 progname = exename
1018 if strip:
1019 progname += '.unstripped'
1020
1021 targets = new_env.Program(progname, bin_objs + static_objs)
1022
1023 if strip:
1024 if sys.platform == 'sunos5':
1025 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1026 else:
1027 cmd = 'strip $SOURCE -o $TARGET'
1028 targets = new_env.Command(exename, progname, cmd)
1029
1030 new_env.M5Binary = targets[0]
1031 envList.append(new_env)
1032
1033 # Debug binary
1034 ccflags = {}
1035 if env['GCC']:
1036 if sys.platform == 'sunos5':
1037 ccflags['debug'] = '-gstabs+'
1038 else:
1039 ccflags['debug'] = '-ggdb3'
1040 ccflags['opt'] = '-g -O3'
1041 ccflags['fast'] = '-O3'
1042 ccflags['prof'] = '-O3 -g -pg'
1043 elif env['SUNCC']:
1044 ccflags['debug'] = '-g0'
1045 ccflags['opt'] = '-g -O'
1046 ccflags['fast'] = '-fast'
1047 ccflags['prof'] = '-fast -g -pg'
1048 elif env['ICC']:
1049 ccflags['debug'] = '-g -O0'
1050 ccflags['opt'] = '-g -O'
1051 ccflags['fast'] = '-fast'
1052 ccflags['prof'] = '-fast -g -pg'
1053 else:
1054 print 'Unknown compiler, please fix compiler options'
1055 Exit(1)
1056
1057 makeEnv('debug', '.do',
1058 CCFLAGS = Split(ccflags['debug']),
1059 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
1060
1061 # Optimized binary
1062 makeEnv('opt', '.o',
1063 CCFLAGS = Split(ccflags['opt']),
1064 CPPDEFINES = ['TRACING_ON=1'])
1065
1066 # "Fast" binary
1067 makeEnv('fast', '.fo', strip = True,
1068 CCFLAGS = Split(ccflags['fast']),
1069 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1070
1071 # Profiled binary
1072 makeEnv('prof', '.po',
1073 CCFLAGS = Split(ccflags['prof']),
1074 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1075 LINKFLAGS = '-pg')
1076
1077 Return('envList')