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