Deleted Added
sdiff udiff text old ( 5518:70caf53d9d7c ) new ( 5522:e56c3d89be79 )
full compact
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 = []
546for source,package in swig_sources:
547 filename = str(source)
548 assert filename.endswith('.i')
549
550 base = '.'.join(filename.split('.')[:-1])
551 module = basename(base)
552 cc_file = base + '_wrap.cc'
553 py_file = base + '.py'
554
555 env.Command([cc_file, py_file], source,
556 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
557 '-o ${TARGETS[0]} $SOURCES')
558 env.Depends(py_file, source)
559 env.Depends(cc_file, source)
560
561 swig_modules.append(Value(module))
562 Source(cc_file)
563 PySource(package, py_file)
564
565# Generate the main swig init file
566def makeSwigInit(target, source, env):
567 f = file(str(target[0]), 'w')
568 print >>f, 'extern "C" {'
569 for module in source:
570 print >>f, ' void init_%s();' % module.get_contents()
571 print >>f, '}'
572 print >>f, 'void initSwig() {'
573 for module in source:
574 print >>f, ' init_%s();' % module.get_contents()
575 print >>f, '}'
576 f.close()
577
578env.Command('python/swig/init.cc', swig_modules, makeSwigInit)
579Source('python/swig/init.cc')
580
581# Generate traceflags.py
582def traceFlagsPy(target, source, env):
583 assert(len(target) == 1)
584
585 f = file(str(target[0]), 'w')
586
587 allFlags = []
588 for s in source:
589 val = eval(s.get_contents())
590 allFlags.append(val)
591
592 print >>f, 'baseFlags = ['
593 for flag, compound, desc in allFlags:
594 if not compound:
595 print >>f, " '%s'," % flag
596 print >>f, " ]"
597 print >>f
598
599 print >>f, 'compoundFlags = ['
600 print >>f, " 'All',"
601 for flag, compound, desc in allFlags:
602 if compound:
603 print >>f, " '%s'," % flag
604 print >>f, " ]"
605 print >>f
606
607 print >>f, "allFlags = frozenset(baseFlags + compoundFlags)"
608 print >>f
609
610 print >>f, 'compoundFlagMap = {'
611 all = tuple([flag for flag,compound,desc in allFlags if not compound])
612 print >>f, " 'All' : %s," % (all, )
613 for flag, compound, desc in allFlags:
614 if compound:
615 print >>f, " '%s' : %s," % (flag, compound)
616 print >>f, " }"
617 print >>f
618
619 print >>f, 'flagDescriptions = {'
620 print >>f, " 'All' : 'All flags',"
621 for flag, compound, desc in allFlags:
622 print >>f, " '%s' : '%s'," % (flag, desc)
623 print >>f, " }"
624
625 f.close()
626
627def traceFlagsCC(target, source, env):
628 assert(len(target) == 1)
629
630 f = file(str(target[0]), 'w')
631
632 allFlags = []
633 for s in source:
634 val = eval(s.get_contents())
635 allFlags.append(val)
636
637 # file header
638 print >>f, '''
639/*
640 * DO NOT EDIT THIS FILE! Automatically generated
641 */
642
643#include "base/traceflags.hh"
644
645using namespace Trace;
646
647const char *Trace::flagStrings[] =
648{'''
649
650 # The string array is used by SimpleEnumParam to map the strings
651 # provided by the user to enum values.
652 for flag, compound, desc in allFlags:
653 if not compound:
654 print >>f, ' "%s",' % flag
655
656 print >>f, ' "All",'
657 for flag, compound, desc in allFlags:
658 if compound:
659 print >>f, ' "%s",' % flag
660
661 print >>f, '};'
662 print >>f
663 print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
664 print >>f
665
666 #
667 # Now define the individual compound flag arrays. There is an array
668 # for each compound flag listing the component base flags.
669 #
670 all = tuple([flag for flag,compound,desc in allFlags if not compound])
671 print >>f, 'static const Flags AllMap[] = {'
672 for flag, compound, desc in allFlags:
673 if not compound:
674 print >>f, " %s," % flag
675 print >>f, '};'
676 print >>f
677
678 for flag, compound, desc in allFlags:
679 if not compound:
680 continue
681 print >>f, 'static const Flags %sMap[] = {' % flag
682 for flag in compound:
683 print >>f, " %s," % flag
684 print >>f, " (Flags)-1"
685 print >>f, '};'
686 print >>f
687
688 #
689 # Finally the compoundFlags[] array maps the compound flags
690 # to their individual arrays/
691 #
692 print >>f, 'const Flags *Trace::compoundFlags[] ='
693 print >>f, '{'
694 print >>f, ' AllMap,'
695 for flag, compound, desc in allFlags:
696 if compound:
697 print >>f, ' %sMap,' % flag
698 # file trailer
699 print >>f, '};'
700
701 f.close()
702
703def traceFlagsHH(target, source, env):
704 assert(len(target) == 1)
705
706 f = file(str(target[0]), 'w')
707
708 allFlags = []
709 for s in source:
710 val = eval(s.get_contents())
711 allFlags.append(val)
712
713 # file header boilerplate
714 print >>f, '''
715/*
716 * DO NOT EDIT THIS FILE!
717 *
718 * Automatically generated from traceflags.py
719 */
720
721#ifndef __BASE_TRACE_FLAGS_HH__
722#define __BASE_TRACE_FLAGS_HH__
723
724namespace Trace {
725
726enum Flags {'''
727
728 # Generate the enum. Base flags come first, then compound flags.
729 idx = 0
730 for flag, compound, desc in allFlags:
731 if not compound:
732 print >>f, ' %s = %d,' % (flag, idx)
733 idx += 1
734
735 numBaseFlags = idx
736 print >>f, ' NumFlags = %d,' % idx
737
738 # put a comment in here to separate base from compound flags
739 print >>f, '''
740// The remaining enum values are *not* valid indices for Trace::flags.
741// They are "compound" flags, which correspond to sets of base
742// flags, and are used by changeFlag.'''
743
744 print >>f, ' All = %d,' % idx
745 idx += 1
746 for flag, compound, desc in allFlags:
747 if compound:
748 print >>f, ' %s = %d,' % (flag, idx)
749 idx += 1
750
751 numCompoundFlags = idx - numBaseFlags
752 print >>f, ' NumCompoundFlags = %d' % numCompoundFlags
753
754 # trailer boilerplate
755 print >>f, '''\
756}; // enum Flags
757
758// Array of strings for SimpleEnumParam
759extern const char *flagStrings[];
760extern const int numFlagStrings;
761
762// Array of arraay pointers: for each compound flag, gives the list of
763// base flags to set. Inidividual flag arrays are terminated by -1.
764extern const Flags *compoundFlags[];
765
766/* namespace Trace */ }
767
768#endif // __BASE_TRACE_FLAGS_HH__
769'''
770
771 f.close()
772
773flags = [ Value(f) for f in trace_flags ]
774env.Command('base/traceflags.py', flags, traceFlagsPy)
775PySource('m5', 'base/traceflags.py')
776
777env.Command('base/traceflags.hh', flags, traceFlagsHH)
778env.Command('base/traceflags.cc', flags, traceFlagsCC)
779Source('base/traceflags.cc')
780
781# Generate program_info.cc
782def programInfo(target, source, env):
783 def gen_file(target, rev, node, date):
784 pi_stats = file(target, 'w')
785 print >>pi_stats, 'const char *hgRev = "%s:%s";' % (rev, node)
786 print >>pi_stats, 'const char *hgDate = "%s";' % date
787 pi_stats.close()
788
789 target = str(target[0])
790 scons_dir = str(source[0].get_contents())
791 try:
792 import mercurial.demandimport, mercurial.hg, mercurial.ui
793 import mercurial.util, mercurial.node
794 if not exists(scons_dir) or not isdir(scons_dir) or \
795 not exists(joinpath(scons_dir, ".hg")):
796 raise ValueError
797 repo = mercurial.hg.repository(mercurial.ui.ui(), scons_dir)
798 rev = mercurial.node.nullrev + repo.changelog.count()
799 changenode = repo.changelog.node(rev)
800 changes = repo.changelog.read(changenode)
801 date = mercurial.util.datestr(changes[2])
802
803 gen_file(target, rev, mercurial.node.hex(changenode), date)
804
805 mercurial.demandimport.disable()
806 except ImportError:
807 gen_file(target, "Unknown", "Unknown", "Unknown")
808
809 except:
810 print "in except"
811 gen_file(target, "Unknown", "Unknown", "Unknown")
812 mercurial.demandimport.disable()
813
814env.Command('base/program_info.cc',
815 Value(str(SCons.Node.FS.default_fs.SConstruct_dir)),
816 programInfo)
817
818# embed python files. All .py files that have been indicated by a
819# PySource() call in a SConscript need to be embedded into the M5
820# library. To do that, we compile the file to byte code, marshal the
821# byte code, compress it, and then generate an assembly file that
822# inserts the result into the data section with symbols indicating the
823# beginning, and end (and with the size at the end)
824py_sources_tnodes = {}
825for pysource in py_sources:
826 py_sources_tnodes[pysource.tnode] = pysource
827
828def objectifyPyFile(target, source, env):
829 '''Action function to compile a .py into a code object, marshal
830 it, compress it, and stick it into an asm file so the code appears
831 as just bytes with a label in the data section'''
832
833 src = file(str(source[0]), 'r').read()
834 dst = file(str(target[0]), 'w')
835
836 pysource = py_sources_tnodes[source[0]]
837 compiled = compile(src, pysource.snode.path, 'exec')
838 marshalled = marshal.dumps(compiled)
839 compressed = zlib.compress(marshalled)
840 data = compressed
841
842 # Some C/C++ compilers prepend an underscore to global symbol
843 # names, so if they're going to do that, we need to prepend that
844 # leading underscore to globals in the assembly file.
845 if env['LEADING_UNDERSCORE']:
846 sym = '_' + pysource.symname
847 else:
848 sym = pysource.symname
849
850 step = 16
851 print >>dst, ".data"
852 print >>dst, ".globl %s_beg" % sym
853 print >>dst, ".globl %s_end" % sym
854 print >>dst, "%s_beg:" % sym
855 for i in xrange(0, len(data), step):
856 x = array.array('B', data[i:i+step])
857 print >>dst, ".byte", ','.join([str(d) for d in x])
858 print >>dst, "%s_end:" % sym
859 print >>dst, ".long %d" % len(marshalled)
860
861for source in py_sources:
862 env.Command(source.assembly, source.tnode, objectifyPyFile)
863 Source(source.assembly)
864
865# Generate init_python.cc which creates a bunch of EmbeddedPyModule
866# structs that describe the embedded python code. One such struct
867# contains information about the importer that python uses to get at
868# the embedded files, and then there's a list of all of the rest that
869# the importer uses to load the rest on demand.
870py_sources_symbols = {}
871for pysource in py_sources:
872 py_sources_symbols[pysource.symname] = pysource
873def pythonInit(target, source, env):
874 dst = file(str(target[0]), 'w')
875
876 def dump_mod(sym, endchar=','):
877 pysource = py_sources_symbols[sym]
878 print >>dst, ' { "%s",' % pysource.arcname
879 print >>dst, ' "%s",' % pysource.modpath
880 print >>dst, ' %s_beg, %s_end,' % (sym, sym)
881 print >>dst, ' %s_end - %s_beg,' % (sym, sym)
882 print >>dst, ' *(int *)%s_end }%s' % (sym, endchar)
883
884 print >>dst, '#include "sim/init.hh"'
885
886 for sym in source:
887 sym = sym.get_contents()
888 print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym)
889
890 print >>dst, "const EmbeddedPyModule embeddedPyImporter = "
891 dump_mod("PyEMB_importer", endchar=';');
892 print >>dst
893
894 print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {"
895 for i,sym in enumerate(source):
896 sym = sym.get_contents()
897 if sym == "PyEMB_importer":
898 # Skip the importer since we've already exported it
899 continue
900 dump_mod(sym)
901 print >>dst, " { 0, 0, 0, 0, 0, 0 }"
902 print >>dst, "};"
903
904symbols = [Value(s.symname) for s in py_sources]
905env.Command('sim/init_python.cc', symbols, pythonInit)
906Source('sim/init_python.cc')
907
908########################################################################
909#
910# Define binaries. Each different build type (debug, opt, etc.) gets
911# a slightly different build environment.
912#
913
914# List of constructed environments to pass back to SConstruct
915envList = []
916
917# This function adds the specified sources to the given build
918# environment, and returns a list of all the corresponding SCons
919# Object nodes (including an extra one for date.cc). We explicitly
920# add the Object nodes so we can set up special dependencies for
921# date.cc.
922def make_objs(sources, env):
923 objs = [env.Object(s) for s in sources]
924
925 # make date.cc depend on all other objects so it always gets
926 # recompiled whenever anything else does
927 date_obj = env.Object('base/date.cc')
928
929 # Make the generation of program_info.cc dependend on all
930 # the other cc files and the compiling of program_info.cc
931 # dependent on all the objects but program_info.o
932 pinfo_obj = env.Object('base/program_info.cc')
933 env.Depends('base/program_info.cc', sources)
934 env.Depends(date_obj, objs)
935 env.Depends(pinfo_obj, objs)
936 objs.extend([date_obj,pinfo_obj])
937 return objs
938
939# Function to create a new build environment as clone of current
940# environment 'env' with modified object suffix and optional stripped
941# binary. Additional keyword arguments are appended to corresponding
942# build environment vars.
943def makeEnv(label, objsfx, strip = False, **kwargs):
944 newEnv = env.Copy(OBJSUFFIX=objsfx)
945 newEnv.Label = label
946 newEnv.Append(**kwargs)
947
948 # First make a library of everything but main() so other programs can
949 # link against m5.
950 #
951 # SCons doesn't know to append a library suffix when there is a '.' in the
952 # name. Use '_' instead.
953 m5lib = newEnv.Library('m5_' + label, make_objs(cc_lib_sources, newEnv))
954
955 # Now link a stub with main() and the library.
956 exe = 'm5.' + label # final executable
957 objects = [newEnv.Object(s) for s in cc_bin_sources] + m5lib
958 if strip:
959 unstripped_exe = exe + '.unstripped'
960 newEnv.Program(unstripped_exe, objects)
961 if sys.platform == 'sunos5':
962 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
963 else:
964 cmd = 'strip $SOURCE -o $TARGET'
965 targets = newEnv.Command(exe, unstripped_exe, cmd)
966 else:
967 targets = newEnv.Program(exe, objects)
968
969 newEnv.M5Binary = targets[0]
970 envList.append(newEnv)
971
972# Debug binary
973ccflags = {}
974if env['GCC']:
975 if sys.platform == 'sunos5':
976 ccflags['debug'] = '-gstabs+'
977 else:
978 ccflags['debug'] = '-ggdb3'
979 ccflags['opt'] = '-g -O3'
980 ccflags['fast'] = '-O3'
981 ccflags['prof'] = '-O3 -g -pg'
982elif env['SUNCC']:
983 ccflags['debug'] = '-g0'
984 ccflags['opt'] = '-g -O'
985 ccflags['fast'] = '-fast'
986 ccflags['prof'] = '-fast -g -pg'
987elif env['ICC']:
988 ccflags['debug'] = '-g -O0'
989 ccflags['opt'] = '-g -O'
990 ccflags['fast'] = '-fast'
991 ccflags['prof'] = '-fast -g -pg'
992else:
993 print 'Unknown compiler, please fix compiler options'
994 Exit(1)
995
996makeEnv('debug', '.do',
997 CCFLAGS = Split(ccflags['debug']),
998 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
999
1000# Optimized binary
1001makeEnv('opt', '.o',
1002 CCFLAGS = Split(ccflags['opt']),
1003 CPPDEFINES = ['TRACING_ON=1'])
1004
1005# "Fast" binary
1006makeEnv('fast', '.fo', strip = True,
1007 CCFLAGS = Split(ccflags['fast']),
1008 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
1009
1010# Profiled binary
1011makeEnv('prof', '.po',
1012 CCFLAGS = Split(ccflags['prof']),
1013 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1014 LINKFLAGS = '-pg')
1015
1016Return('envList')