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