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