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