99f986a2460443f2f9dc286d9cccce63804a3b4b
[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 bisect
33 import imp
34 import marshal
35 import os
36 import re
37 import subprocess
38 import sys
39 import zlib
40
41 from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
42
43 import SCons
44
45 # This file defines how to build a particular configuration of gem5
46 # based on variable settings in the 'env' build environment.
47
48 Import('*')
49
50 # Children need to see the environment
51 Export('env')
52
53 build_env = [(opt, env[opt]) for opt in export_vars]
54
55 from m5.util import code_formatter, compareVersions
56
57 ########################################################################
58 # Code for adding source files of various types
59 #
60 # When specifying a source file of some type, a set of guards can be
61 # specified for that file. When get() is used to find the files, if
62 # get specifies a set of filters, only files that match those filters
63 # will be accepted (unspecified filters on files are assumed to be
64 # false). Current filters are:
65 # main -- specifies the gem5 main() function
66 # skip_lib -- do not put this file into the gem5 library
67 # skip_no_python -- do not put this file into a no_python library
68 # as it embeds compiled Python
69 # <unittest> -- unit tests use filters based on the unit test name
70 #
71 # A parent can now be specified for a source file and default filter
72 # values will be retrieved recursively from parents (children override
73 # parents).
74 #
75 def guarded_source_iterator(sources, **guards):
76 '''Iterate over a set of sources, gated by a set of guards.'''
77 for src in sources:
78 for flag,value in guards.iteritems():
79 # if the flag is found and has a different value, skip
80 # this file
81 if src.all_guards.get(flag, False) != value:
82 break
83 else:
84 yield src
85
86 class SourceMeta(type):
87 '''Meta class for source files that keeps track of all files of a
88 particular type and has a get function for finding all functions
89 of a certain type that match a set of guards'''
90 def __init__(cls, name, bases, dict):
91 super(SourceMeta, cls).__init__(name, bases, dict)
92 cls.all = []
93
94 def get(cls, **guards):
95 '''Find all files that match the specified guards. If a source
96 file does not specify a flag, the default is False'''
97 for s in guarded_source_iterator(cls.all, **guards):
98 yield s
99
100 class SourceFile(object):
101 '''Base object that encapsulates the notion of a source file.
102 This includes, the source node, target node, various manipulations
103 of those. A source file also specifies a set of guards which
104 describing which builds the source file applies to. A parent can
105 also be specified to get default guards from'''
106 __metaclass__ = SourceMeta
107 def __init__(self, source, parent=None, **guards):
108 self.guards = guards
109 self.parent = parent
110
111 tnode = source
112 if not isinstance(source, SCons.Node.FS.File):
113 tnode = File(source)
114
115 self.tnode = tnode
116 self.snode = tnode.srcnode()
117
118 for base in type(self).__mro__:
119 if issubclass(base, SourceFile):
120 base.all.append(self)
121
122 @property
123 def filename(self):
124 return str(self.tnode)
125
126 @property
127 def dirname(self):
128 return dirname(self.filename)
129
130 @property
131 def basename(self):
132 return basename(self.filename)
133
134 @property
135 def extname(self):
136 index = self.basename.rfind('.')
137 if index <= 0:
138 # dot files aren't extensions
139 return self.basename, None
140
141 return self.basename[:index], self.basename[index+1:]
142
143 @property
144 def all_guards(self):
145 '''find all guards for this object getting default values
146 recursively from its parents'''
147 guards = {}
148 if self.parent:
149 guards.update(self.parent.guards)
150 guards.update(self.guards)
151 return guards
152
153 def __lt__(self, other): return self.filename < other.filename
154 def __le__(self, other): return self.filename <= other.filename
155 def __gt__(self, other): return self.filename > other.filename
156 def __ge__(self, other): return self.filename >= other.filename
157 def __eq__(self, other): return self.filename == other.filename
158 def __ne__(self, other): return self.filename != other.filename
159
160 @staticmethod
161 def done():
162 def disabled(cls, name, *ignored):
163 raise RuntimeError("Additional SourceFile '%s'" % name,\
164 "declared, but targets deps are already fixed.")
165 SourceFile.__init__ = disabled
166
167
168 class Source(SourceFile):
169 current_group = None
170 source_groups = { None : [] }
171
172 @classmethod
173 def set_group(cls, group):
174 if not group in Source.source_groups:
175 Source.source_groups[group] = []
176 Source.current_group = group
177
178 '''Add a c/c++ source file to the build'''
179 def __init__(self, source, Werror=True, swig=False, **guards):
180 '''specify the source file, and any guards'''
181 super(Source, self).__init__(source, **guards)
182
183 self.Werror = Werror
184 self.swig = swig
185
186 Source.source_groups[Source.current_group].append(self)
187
188 class PySource(SourceFile):
189 '''Add a python source file to the named package'''
190 invalid_sym_char = re.compile('[^A-z0-9_]')
191 modules = {}
192 tnodes = {}
193 symnames = {}
194
195 def __init__(self, package, source, **guards):
196 '''specify the python package, the source file, and any guards'''
197 super(PySource, self).__init__(source, **guards)
198
199 modname,ext = self.extname
200 assert ext == 'py'
201
202 if package:
203 path = package.split('.')
204 else:
205 path = []
206
207 modpath = path[:]
208 if modname != '__init__':
209 modpath += [ modname ]
210 modpath = '.'.join(modpath)
211
212 arcpath = path + [ self.basename ]
213 abspath = self.snode.abspath
214 if not exists(abspath):
215 abspath = self.tnode.abspath
216
217 self.package = package
218 self.modname = modname
219 self.modpath = modpath
220 self.arcname = joinpath(*arcpath)
221 self.abspath = abspath
222 self.compiled = File(self.filename + 'c')
223 self.cpp = File(self.filename + '.cc')
224 self.symname = PySource.invalid_sym_char.sub('_', modpath)
225
226 PySource.modules[modpath] = self
227 PySource.tnodes[self.tnode] = self
228 PySource.symnames[self.symname] = self
229
230 class SimObject(PySource):
231 '''Add a SimObject python file as a python source object and add
232 it to a list of sim object modules'''
233
234 fixed = False
235 modnames = []
236
237 def __init__(self, source, **guards):
238 '''Specify the source file and any guards (automatically in
239 the m5.objects package)'''
240 super(SimObject, self).__init__('m5.objects', source, **guards)
241 if self.fixed:
242 raise AttributeError, "Too late to call SimObject now."
243
244 bisect.insort_right(SimObject.modnames, self.modname)
245
246 class SwigSource(SourceFile):
247 '''Add a swig file to build'''
248
249 def __init__(self, package, source, **guards):
250 '''Specify the python package, the source file, and any guards'''
251 super(SwigSource, self).__init__(source, skip_no_python=True, **guards)
252
253 modname,ext = self.extname
254 assert ext == 'i'
255
256 self.package = package
257 self.module = modname
258 cc_file = joinpath(self.dirname, modname + '_wrap.cc')
259 py_file = joinpath(self.dirname, modname + '.py')
260
261 self.cc_source = Source(cc_file, swig=True, parent=self, **guards)
262 self.py_source = PySource(package, py_file, parent=self, **guards)
263
264 class ProtoBuf(SourceFile):
265 '''Add a Protocol Buffer to build'''
266
267 def __init__(self, source, **guards):
268 '''Specify the source file, and any guards'''
269 super(ProtoBuf, self).__init__(source, **guards)
270
271 # Get the file name and the extension
272 modname,ext = self.extname
273 assert ext == 'proto'
274
275 # Currently, we stick to generating the C++ headers, so we
276 # only need to track the source and header.
277 self.cc_file = File(modname + '.pb.cc')
278 self.hh_file = File(modname + '.pb.h')
279
280 class UnitTest(object):
281 '''Create a UnitTest'''
282
283 all = []
284 def __init__(self, target, *sources, **kwargs):
285 '''Specify the target name and any sources. Sources that are
286 not SourceFiles are evalued with Source(). All files are
287 guarded with a guard of the same name as the UnitTest
288 target.'''
289
290 srcs = []
291 for src in sources:
292 if not isinstance(src, SourceFile):
293 src = Source(src, skip_lib=True)
294 src.guards[target] = True
295 srcs.append(src)
296
297 self.sources = srcs
298 self.target = target
299 self.main = kwargs.get('main', False)
300 UnitTest.all.append(self)
301
302 # Children should have access
303 Export('Source')
304 Export('PySource')
305 Export('SimObject')
306 Export('SwigSource')
307 Export('ProtoBuf')
308 Export('UnitTest')
309
310 ########################################################################
311 #
312 # Debug Flags
313 #
314 debug_flags = {}
315 def DebugFlag(name, desc=None):
316 if name in debug_flags:
317 raise AttributeError, "Flag %s already specified" % name
318 debug_flags[name] = (name, (), desc)
319
320 def CompoundFlag(name, flags, desc=None):
321 if name in debug_flags:
322 raise AttributeError, "Flag %s already specified" % name
323
324 compound = tuple(flags)
325 debug_flags[name] = (name, compound, desc)
326
327 Export('DebugFlag')
328 Export('CompoundFlag')
329
330 ########################################################################
331 #
332 # Set some compiler variables
333 #
334
335 # Include file paths are rooted in this directory. SCons will
336 # automatically expand '.' to refer to both the source directory and
337 # the corresponding build directory to pick up generated include
338 # files.
339 env.Append(CPPPATH=Dir('.'))
340
341 for extra_dir in extras_dir_list:
342 env.Append(CPPPATH=Dir(extra_dir))
343
344 # Workaround for bug in SCons version > 0.97d20071212
345 # Scons bug id: 2006 gem5 Bug id: 308
346 for root, dirs, files in os.walk(base_dir, topdown=True):
347 Dir(root[len(base_dir) + 1:])
348
349 ########################################################################
350 #
351 # Walk the tree and execute all SConscripts in subdirectories
352 #
353
354 here = Dir('.').srcnode().abspath
355 for root, dirs, files in os.walk(base_dir, topdown=True):
356 if root == here:
357 # we don't want to recurse back into this SConscript
358 continue
359
360 if 'SConscript' in files:
361 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
362 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
363
364 for extra_dir in extras_dir_list:
365 prefix_len = len(dirname(extra_dir)) + 1
366
367 # Also add the corresponding build directory to pick up generated
368 # include files.
369 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:])))
370
371 for root, dirs, files in os.walk(extra_dir, topdown=True):
372 # if build lives in the extras directory, don't walk down it
373 if 'build' in dirs:
374 dirs.remove('build')
375
376 if 'SConscript' in files:
377 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
378 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
379
380 for opt in export_vars:
381 env.ConfigFile(opt)
382
383 def makeTheISA(source, target, env):
384 isas = [ src.get_contents() for src in source ]
385 target_isa = env['TARGET_ISA']
386 def define(isa):
387 return isa.upper() + '_ISA'
388
389 def namespace(isa):
390 return isa[0].upper() + isa[1:].lower() + 'ISA'
391
392
393 code = code_formatter()
394 code('''\
395 #ifndef __CONFIG_THE_ISA_HH__
396 #define __CONFIG_THE_ISA_HH__
397
398 ''')
399
400 # create defines for the preprocessing and compile-time determination
401 for i,isa in enumerate(isas):
402 code('#define $0 $1', define(isa), i + 1)
403 code()
404
405 # create an enum for any run-time determination of the ISA, we
406 # reuse the same name as the namespaces
407 code('enum class Arch {')
408 for i,isa in enumerate(isas):
409 if i + 1 == len(isas):
410 code(' $0 = $1', namespace(isa), define(isa))
411 else:
412 code(' $0 = $1,', namespace(isa), define(isa))
413 code('};')
414
415 code('''
416
417 #define THE_ISA ${{define(target_isa)}}
418 #define TheISA ${{namespace(target_isa)}}
419 #define THE_ISA_STR "${{target_isa}}"
420
421 #endif // __CONFIG_THE_ISA_HH__''')
422
423 code.write(str(target[0]))
424
425 env.Command('config/the_isa.hh', map(Value, all_isa_list),
426 MakeAction(makeTheISA, Transform("CFG ISA", 0)))
427
428 def makeTheGPUISA(source, target, env):
429 isas = [ src.get_contents() for src in source ]
430 target_gpu_isa = env['TARGET_GPU_ISA']
431 def define(isa):
432 return isa.upper() + '_ISA'
433
434 def namespace(isa):
435 return isa[0].upper() + isa[1:].lower() + 'ISA'
436
437
438 code = code_formatter()
439 code('''\
440 #ifndef __CONFIG_THE_GPU_ISA_HH__
441 #define __CONFIG_THE_GPU_ISA_HH__
442
443 ''')
444
445 # create defines for the preprocessing and compile-time determination
446 for i,isa in enumerate(isas):
447 code('#define $0 $1', define(isa), i + 1)
448 code()
449
450 # create an enum for any run-time determination of the ISA, we
451 # reuse the same name as the namespaces
452 code('enum class GPUArch {')
453 for i,isa in enumerate(isas):
454 if i + 1 == len(isas):
455 code(' $0 = $1', namespace(isa), define(isa))
456 else:
457 code(' $0 = $1,', namespace(isa), define(isa))
458 code('};')
459
460 code('''
461
462 #define THE_GPU_ISA ${{define(target_gpu_isa)}}
463 #define TheGpuISA ${{namespace(target_gpu_isa)}}
464 #define THE_GPU_ISA_STR "${{target_gpu_isa}}"
465
466 #endif // __CONFIG_THE_GPU_ISA_HH__''')
467
468 code.write(str(target[0]))
469
470 env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list),
471 MakeAction(makeTheGPUISA, Transform("CFG ISA", 0)))
472
473 ########################################################################
474 #
475 # Prevent any SimObjects from being added after this point, they
476 # should all have been added in the SConscripts above
477 #
478 SimObject.fixed = True
479
480 class DictImporter(object):
481 '''This importer takes a dictionary of arbitrary module names that
482 map to arbitrary filenames.'''
483 def __init__(self, modules):
484 self.modules = modules
485 self.installed = set()
486
487 def __del__(self):
488 self.unload()
489
490 def unload(self):
491 import sys
492 for module in self.installed:
493 del sys.modules[module]
494 self.installed = set()
495
496 def find_module(self, fullname, path):
497 if fullname == 'm5.defines':
498 return self
499
500 if fullname == 'm5.objects':
501 return self
502
503 if fullname.startswith('_m5'):
504 return None
505
506 source = self.modules.get(fullname, None)
507 if source is not None and fullname.startswith('m5.objects'):
508 return self
509
510 return None
511
512 def load_module(self, fullname):
513 mod = imp.new_module(fullname)
514 sys.modules[fullname] = mod
515 self.installed.add(fullname)
516
517 mod.__loader__ = self
518 if fullname == 'm5.objects':
519 mod.__path__ = fullname.split('.')
520 return mod
521
522 if fullname == 'm5.defines':
523 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
524 return mod
525
526 source = self.modules[fullname]
527 if source.modname == '__init__':
528 mod.__path__ = source.modpath
529 mod.__file__ = source.abspath
530
531 exec file(source.abspath, 'r') in mod.__dict__
532
533 return mod
534
535 import m5.SimObject
536 import m5.params
537 from m5.util import code_formatter
538
539 m5.SimObject.clear()
540 m5.params.clear()
541
542 # install the python importer so we can grab stuff from the source
543 # tree itself. We can't have SimObjects added after this point or
544 # else we won't know about them for the rest of the stuff.
545 importer = DictImporter(PySource.modules)
546 sys.meta_path[0:0] = [ importer ]
547
548 # import all sim objects so we can populate the all_objects list
549 # make sure that we're working with a list, then let's sort it
550 for modname in SimObject.modnames:
551 exec('from m5.objects import %s' % modname)
552
553 # we need to unload all of the currently imported modules so that they
554 # will be re-imported the next time the sconscript is run
555 importer.unload()
556 sys.meta_path.remove(importer)
557
558 sim_objects = m5.SimObject.allClasses
559 all_enums = m5.params.allEnums
560
561 if m5.SimObject.noCxxHeader:
562 print >> sys.stderr, \
563 "warning: At least one SimObject lacks a header specification. " \
564 "This can cause unexpected results in the generated SWIG " \
565 "wrappers."
566
567 # Find param types that need to be explicitly wrapped with swig.
568 # These will be recognized because the ParamDesc will have a
569 # swig_decl() method. Most param types are based on types that don't
570 # need this, either because they're based on native types (like Int)
571 # or because they're SimObjects (which get swigged independently).
572 # For now the only things handled here are VectorParam types.
573 params_to_swig = {}
574 for name,obj in sorted(sim_objects.iteritems()):
575 for param in obj._params.local.values():
576 # load the ptype attribute now because it depends on the
577 # current version of SimObject.allClasses, but when scons
578 # actually uses the value, all versions of
579 # SimObject.allClasses will have been loaded
580 param.ptype
581
582 if not hasattr(param, 'swig_decl'):
583 continue
584 pname = param.ptype_str
585 if pname not in params_to_swig:
586 params_to_swig[pname] = param
587
588 ########################################################################
589 #
590 # calculate extra dependencies
591 #
592 module_depends = ["m5", "m5.SimObject", "m5.params"]
593 depends = [ PySource.modules[dep].snode for dep in module_depends ]
594 depends.sort(key = lambda x: x.name)
595
596 ########################################################################
597 #
598 # Commands for the basic automatically generated python files
599 #
600
601 # Generate Python file containing a dict specifying the current
602 # buildEnv flags.
603 def makeDefinesPyFile(target, source, env):
604 build_env = source[0].get_contents()
605
606 code = code_formatter()
607 code("""
608 import _m5.core
609 import m5.util
610
611 buildEnv = m5.util.SmartDict($build_env)
612
613 compileDate = _m5.core.compileDate
614 _globals = globals()
615 for key,val in _m5.core.__dict__.iteritems():
616 if key.startswith('flag_'):
617 flag = key[5:]
618 _globals[flag] = val
619 del _globals
620 """)
621 code.write(target[0].abspath)
622
623 defines_info = Value(build_env)
624 # Generate a file with all of the compile options in it
625 env.Command('python/m5/defines.py', defines_info,
626 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
627 PySource('m5', 'python/m5/defines.py')
628
629 # Generate python file containing info about the M5 source code
630 def makeInfoPyFile(target, source, env):
631 code = code_formatter()
632 for src in source:
633 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
634 code('$src = ${{repr(data)}}')
635 code.write(str(target[0]))
636
637 # Generate a file that wraps the basic top level files
638 env.Command('python/m5/info.py',
639 [ '#/COPYING', '#/LICENSE', '#/README', ],
640 MakeAction(makeInfoPyFile, Transform("INFO")))
641 PySource('m5', 'python/m5/info.py')
642
643 ########################################################################
644 #
645 # Create all of the SimObject param headers and enum headers
646 #
647
648 def createSimObjectParamStruct(target, source, env):
649 assert len(target) == 1 and len(source) == 1
650
651 name = str(source[0].get_contents())
652 obj = sim_objects[name]
653
654 code = code_formatter()
655 obj.cxx_param_decl(code)
656 code.write(target[0].abspath)
657
658 def createSimObjectCxxConfig(is_header):
659 def body(target, source, env):
660 assert len(target) == 1 and len(source) == 1
661
662 name = str(source[0].get_contents())
663 obj = sim_objects[name]
664
665 code = code_formatter()
666 obj.cxx_config_param_file(code, is_header)
667 code.write(target[0].abspath)
668 return body
669
670 def createParamSwigWrapper(target, source, env):
671 assert len(target) == 1 and len(source) == 1
672
673 name = str(source[0].get_contents())
674 param = params_to_swig[name]
675
676 code = code_formatter()
677 param.swig_decl(code)
678 code.write(target[0].abspath)
679
680 def createEnumStrings(target, source, env):
681 assert len(target) == 1 and len(source) == 1
682
683 name = str(source[0].get_contents())
684 obj = all_enums[name]
685
686 code = code_formatter()
687 obj.cxx_def(code)
688 code.write(target[0].abspath)
689
690 def createEnumDecls(target, source, env):
691 assert len(target) == 1 and len(source) == 1
692
693 name = str(source[0].get_contents())
694 obj = all_enums[name]
695
696 code = code_formatter()
697 obj.cxx_decl(code)
698 code.write(target[0].abspath)
699
700 def createEnumSwigWrapper(target, source, env):
701 assert len(target) == 1 and len(source) == 1
702
703 name = str(source[0].get_contents())
704 obj = all_enums[name]
705
706 code = code_formatter()
707 obj.swig_decl(code)
708 code.write(target[0].abspath)
709
710 def createSimObjectSwigWrapper(target, source, env):
711 name = source[0].get_contents()
712 obj = sim_objects[name]
713
714 code = code_formatter()
715 obj.swig_decl(code)
716 code.write(target[0].abspath)
717
718 # dummy target for generated code
719 # we start out with all the Source files so they get copied to build/*/ also.
720 SWIG = env.Dummy('swig', [s.tnode for s in Source.get()])
721
722 # Generate all of the SimObject param C++ struct header files
723 params_hh_files = []
724 for name,simobj in sorted(sim_objects.iteritems()):
725 py_source = PySource.modules[simobj.__module__]
726 extra_deps = [ py_source.tnode ]
727
728 hh_file = File('params/%s.hh' % name)
729 params_hh_files.append(hh_file)
730 env.Command(hh_file, Value(name),
731 MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
732 env.Depends(hh_file, depends + extra_deps)
733 env.Depends(SWIG, hh_file)
734
735 # C++ parameter description files
736 if GetOption('with_cxx_config'):
737 for name,simobj in sorted(sim_objects.iteritems()):
738 py_source = PySource.modules[simobj.__module__]
739 extra_deps = [ py_source.tnode ]
740
741 cxx_config_hh_file = File('cxx_config/%s.hh' % name)
742 cxx_config_cc_file = File('cxx_config/%s.cc' % name)
743 env.Command(cxx_config_hh_file, Value(name),
744 MakeAction(createSimObjectCxxConfig(True),
745 Transform("CXXCPRHH")))
746 env.Command(cxx_config_cc_file, Value(name),
747 MakeAction(createSimObjectCxxConfig(False),
748 Transform("CXXCPRCC")))
749 env.Depends(cxx_config_hh_file, depends + extra_deps +
750 [File('params/%s.hh' % name), File('sim/cxx_config.hh')])
751 env.Depends(cxx_config_cc_file, depends + extra_deps +
752 [cxx_config_hh_file])
753 Source(cxx_config_cc_file)
754
755 cxx_config_init_cc_file = File('cxx_config/init.cc')
756
757 def createCxxConfigInitCC(target, source, env):
758 assert len(target) == 1 and len(source) == 1
759
760 code = code_formatter()
761
762 for name,simobj in sorted(sim_objects.iteritems()):
763 if not hasattr(simobj, 'abstract') or not simobj.abstract:
764 code('#include "cxx_config/${name}.hh"')
765 code()
766 code('void cxxConfigInit()')
767 code('{')
768 code.indent()
769 for name,simobj in sorted(sim_objects.iteritems()):
770 not_abstract = not hasattr(simobj, 'abstract') or \
771 not simobj.abstract
772 if not_abstract and 'type' in simobj.__dict__:
773 code('cxx_config_directory["${name}"] = '
774 '${name}CxxConfigParams::makeDirectoryEntry();')
775 code.dedent()
776 code('}')
777 code.write(target[0].abspath)
778
779 py_source = PySource.modules[simobj.__module__]
780 extra_deps = [ py_source.tnode ]
781 env.Command(cxx_config_init_cc_file, Value(name),
782 MakeAction(createCxxConfigInitCC, Transform("CXXCINIT")))
783 cxx_param_hh_files = ["cxx_config/%s.hh" % simobj
784 for name,simobj in sorted(sim_objects.iteritems())
785 if not hasattr(simobj, 'abstract') or not simobj.abstract]
786 Depends(cxx_config_init_cc_file, cxx_param_hh_files +
787 [File('sim/cxx_config.hh')])
788 Source(cxx_config_init_cc_file)
789
790 # Generate any needed param SWIG wrapper files
791 params_i_files = []
792 for name,param in sorted(params_to_swig.iteritems()):
793 i_file = File('python/_m5/%s.i' % (param.swig_module_name()))
794 params_i_files.append(i_file)
795 env.Command(i_file, Value(name),
796 MakeAction(createParamSwigWrapper, Transform("SW PARAM")))
797 env.Depends(i_file, depends)
798 env.Depends(SWIG, i_file)
799 SwigSource('_m5', i_file)
800
801 # Generate all enum header files
802 for name,enum in sorted(all_enums.iteritems()):
803 py_source = PySource.modules[enum.__module__]
804 extra_deps = [ py_source.tnode ]
805
806 cc_file = File('enums/%s.cc' % name)
807 env.Command(cc_file, Value(name),
808 MakeAction(createEnumStrings, Transform("ENUM STR")))
809 env.Depends(cc_file, depends + extra_deps)
810 env.Depends(SWIG, cc_file)
811 Source(cc_file)
812
813 hh_file = File('enums/%s.hh' % name)
814 env.Command(hh_file, Value(name),
815 MakeAction(createEnumDecls, Transform("ENUMDECL")))
816 env.Depends(hh_file, depends + extra_deps)
817 env.Depends(SWIG, hh_file)
818
819 i_file = File('python/_m5/enum_%s.i' % name)
820 env.Command(i_file, Value(name),
821 MakeAction(createEnumSwigWrapper, Transform("ENUMSWIG")))
822 env.Depends(i_file, depends + extra_deps)
823 env.Depends(SWIG, i_file)
824 SwigSource('_m5', i_file)
825
826 # Generate SimObject SWIG wrapper files
827 for name,simobj in sorted(sim_objects.iteritems()):
828 py_source = PySource.modules[simobj.__module__]
829 extra_deps = [ py_source.tnode ]
830 i_file = File('python/_m5/param_%s.i' % name)
831 env.Command(i_file, Value(name),
832 MakeAction(createSimObjectSwigWrapper, Transform("SO SWIG")))
833 env.Depends(i_file, depends + extra_deps)
834 SwigSource('_m5', i_file)
835
836 # Generate the main swig init file
837 def makeEmbeddedSwigInit(package):
838 def body(target, source, env):
839 assert len(target) == 1 and len(source) == 1
840
841 code = code_formatter()
842 module = source[0].get_contents()
843 # Provide the full context so that the swig-generated call to
844 # Py_InitModule ends up placing the embedded module in the
845 # right package.
846 context = str(package) + "._" + str(module)
847 code('''\
848 #include "sim/init.hh"
849
850 extern "C" {
851 void init_${module}();
852 }
853
854 EmbeddedSwig embed_swig_${module}(init_${module}, "${context}");
855 ''')
856 code.write(str(target[0]))
857 return body
858
859 # Build all swig modules
860 for swig in SwigSource.all:
861 env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
862 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
863 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG")))
864 cc_file = str(swig.tnode)
865 init_file = '%s/%s_init.cc' % (dirname(cc_file), basename(cc_file))
866 env.Command(init_file, Value(swig.module),
867 MakeAction(makeEmbeddedSwigInit(swig.package),
868 Transform("EMBED SW")))
869 env.Depends(SWIG, init_file)
870 Source(init_file, **swig.guards)
871
872 # Build all protocol buffers if we have got protoc and protobuf available
873 if env['HAVE_PROTOBUF']:
874 for proto in ProtoBuf.all:
875 # Use both the source and header as the target, and the .proto
876 # file as the source. When executing the protoc compiler, also
877 # specify the proto_path to avoid having the generated files
878 # include the path.
879 env.Command([proto.cc_file, proto.hh_file], proto.tnode,
880 MakeAction('$PROTOC --cpp_out ${TARGET.dir} '
881 '--proto_path ${SOURCE.dir} $SOURCE',
882 Transform("PROTOC")))
883
884 env.Depends(SWIG, [proto.cc_file, proto.hh_file])
885 # Add the C++ source file
886 Source(proto.cc_file, **proto.guards)
887 elif ProtoBuf.all:
888 print 'Got protobuf to build, but lacks support!'
889 Exit(1)
890
891 #
892 # Handle debug flags
893 #
894 def makeDebugFlagCC(target, source, env):
895 assert(len(target) == 1 and len(source) == 1)
896
897 code = code_formatter()
898
899 # delay definition of CompoundFlags until after all the definition
900 # of all constituent SimpleFlags
901 comp_code = code_formatter()
902
903 # file header
904 code('''
905 /*
906 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
907 */
908
909 #include "base/debug.hh"
910
911 namespace Debug {
912
913 ''')
914
915 for name, flag in sorted(source[0].read().iteritems()):
916 n, compound, desc = flag
917 assert n == name
918
919 if not compound:
920 code('SimpleFlag $name("$name", "$desc");')
921 else:
922 comp_code('CompoundFlag $name("$name", "$desc",')
923 comp_code.indent()
924 last = len(compound) - 1
925 for i,flag in enumerate(compound):
926 if i != last:
927 comp_code('&$flag,')
928 else:
929 comp_code('&$flag);')
930 comp_code.dedent()
931
932 code.append(comp_code)
933 code()
934 code('} // namespace Debug')
935
936 code.write(str(target[0]))
937
938 def makeDebugFlagHH(target, source, env):
939 assert(len(target) == 1 and len(source) == 1)
940
941 val = eval(source[0].get_contents())
942 name, compound, desc = val
943
944 code = code_formatter()
945
946 # file header boilerplate
947 code('''\
948 /*
949 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
950 */
951
952 #ifndef __DEBUG_${name}_HH__
953 #define __DEBUG_${name}_HH__
954
955 namespace Debug {
956 ''')
957
958 if compound:
959 code('class CompoundFlag;')
960 code('class SimpleFlag;')
961
962 if compound:
963 code('extern CompoundFlag $name;')
964 for flag in compound:
965 code('extern SimpleFlag $flag;')
966 else:
967 code('extern SimpleFlag $name;')
968
969 code('''
970 }
971
972 #endif // __DEBUG_${name}_HH__
973 ''')
974
975 code.write(str(target[0]))
976
977 for name,flag in sorted(debug_flags.iteritems()):
978 n, compound, desc = flag
979 assert n == name
980
981 hh_file = 'debug/%s.hh' % name
982 env.Command(hh_file, Value(flag),
983 MakeAction(makeDebugFlagHH, Transform("TRACING", 0)))
984 env.Depends(SWIG, hh_file)
985
986 env.Command('debug/flags.cc', Value(debug_flags),
987 MakeAction(makeDebugFlagCC, Transform("TRACING", 0)))
988 env.Depends(SWIG, 'debug/flags.cc')
989 Source('debug/flags.cc')
990
991 # version tags
992 tags = \
993 env.Command('sim/tags.cc', None,
994 MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET',
995 Transform("VER TAGS")))
996 env.AlwaysBuild(tags)
997
998 # Embed python files. All .py files that have been indicated by a
999 # PySource() call in a SConscript need to be embedded into the M5
1000 # library. To do that, we compile the file to byte code, marshal the
1001 # byte code, compress it, and then generate a c++ file that
1002 # inserts the result into an array.
1003 def embedPyFile(target, source, env):
1004 def c_str(string):
1005 if string is None:
1006 return "0"
1007 return '"%s"' % string
1008
1009 '''Action function to compile a .py into a code object, marshal
1010 it, compress it, and stick it into an asm file so the code appears
1011 as just bytes with a label in the data section'''
1012
1013 src = file(str(source[0]), 'r').read()
1014
1015 pysource = PySource.tnodes[source[0]]
1016 compiled = compile(src, pysource.abspath, 'exec')
1017 marshalled = marshal.dumps(compiled)
1018 compressed = zlib.compress(marshalled)
1019 data = compressed
1020 sym = pysource.symname
1021
1022 code = code_formatter()
1023 code('''\
1024 #include "sim/init.hh"
1025
1026 namespace {
1027
1028 const uint8_t data_${sym}[] = {
1029 ''')
1030 code.indent()
1031 step = 16
1032 for i in xrange(0, len(data), step):
1033 x = array.array('B', data[i:i+step])
1034 code(''.join('%d,' % d for d in x))
1035 code.dedent()
1036
1037 code('''};
1038
1039 EmbeddedPython embedded_${sym}(
1040 ${{c_str(pysource.arcname)}},
1041 ${{c_str(pysource.abspath)}},
1042 ${{c_str(pysource.modpath)}},
1043 data_${sym},
1044 ${{len(data)}},
1045 ${{len(marshalled)}});
1046
1047 } // anonymous namespace
1048 ''')
1049 code.write(str(target[0]))
1050
1051 for source in PySource.all:
1052 env.Command(source.cpp, source.tnode,
1053 MakeAction(embedPyFile, Transform("EMBED PY")))
1054 env.Depends(SWIG, source.cpp)
1055 Source(source.cpp, skip_no_python=True)
1056
1057 ########################################################################
1058 #
1059 # Define binaries. Each different build type (debug, opt, etc.) gets
1060 # a slightly different build environment.
1061 #
1062
1063 # List of constructed environments to pass back to SConstruct
1064 date_source = Source('base/date.cc', skip_lib=True)
1065
1066 # Capture this directory for the closure makeEnv, otherwise when it is
1067 # called, it won't know what directory it should use.
1068 variant_dir = Dir('.').path
1069 def variant(*path):
1070 return os.path.join(variant_dir, *path)
1071 def variantd(*path):
1072 return variant(*path)+'/'
1073
1074 # Function to create a new build environment as clone of current
1075 # environment 'env' with modified object suffix and optional stripped
1076 # binary. Additional keyword arguments are appended to corresponding
1077 # build environment vars.
1078 def makeEnv(env, label, objsfx, strip = False, **kwargs):
1079 # SCons doesn't know to append a library suffix when there is a '.' in the
1080 # name. Use '_' instead.
1081 libname = variant('gem5_' + label)
1082 exename = variant('gem5.' + label)
1083 secondary_exename = variant('m5.' + label)
1084
1085 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
1086 new_env.Label = label
1087 new_env.Append(**kwargs)
1088
1089 swig_env = new_env.Clone()
1090
1091 # Both gcc and clang have issues with unused labels and values in
1092 # the SWIG generated code
1093 swig_env.Append(CCFLAGS=['-Wno-unused-label', '-Wno-unused-value'])
1094
1095 if env['GCC']:
1096 # Depending on the SWIG version, we also need to supress
1097 # warnings about uninitialized variables and missing field
1098 # initializers.
1099 swig_env.Append(CCFLAGS=['-Wno-uninitialized',
1100 '-Wno-missing-field-initializers',
1101 '-Wno-unused-but-set-variable',
1102 '-Wno-maybe-uninitialized',
1103 '-Wno-type-limits'])
1104
1105
1106 # The address sanitizer is available for gcc >= 4.8
1107 if GetOption('with_asan'):
1108 if GetOption('with_ubsan') and \
1109 compareVersions(env['GCC_VERSION'], '4.9') >= 0:
1110 new_env.Append(CCFLAGS=['-fsanitize=address,undefined',
1111 '-fno-omit-frame-pointer'])
1112 new_env.Append(LINKFLAGS='-fsanitize=address,undefined')
1113 else:
1114 new_env.Append(CCFLAGS=['-fsanitize=address',
1115 '-fno-omit-frame-pointer'])
1116 new_env.Append(LINKFLAGS='-fsanitize=address')
1117 # Only gcc >= 4.9 supports UBSan, so check both the version
1118 # and the command-line option before adding the compiler and
1119 # linker flags.
1120 elif GetOption('with_ubsan') and \
1121 compareVersions(env['GCC_VERSION'], '4.9') >= 0:
1122 new_env.Append(CCFLAGS='-fsanitize=undefined')
1123 new_env.Append(LINKFLAGS='-fsanitize=undefined')
1124
1125
1126 if env['CLANG']:
1127 swig_env.Append(CCFLAGS=['-Wno-sometimes-uninitialized',
1128 '-Wno-deprecated-register',
1129 '-Wno-tautological-compare'])
1130
1131 # We require clang >= 3.1, so there is no need to check any
1132 # versions here.
1133 if GetOption('with_ubsan'):
1134 if GetOption('with_asan'):
1135 new_env.Append(CCFLAGS=['-fsanitize=address,undefined',
1136 '-fno-omit-frame-pointer'])
1137 new_env.Append(LINKFLAGS='-fsanitize=address,undefined')
1138 else:
1139 new_env.Append(CCFLAGS='-fsanitize=undefined')
1140 new_env.Append(LINKFLAGS='-fsanitize=undefined')
1141
1142 elif GetOption('with_asan'):
1143 new_env.Append(CCFLAGS=['-fsanitize=address',
1144 '-fno-omit-frame-pointer'])
1145 new_env.Append(LINKFLAGS='-fsanitize=address')
1146
1147 werror_env = new_env.Clone()
1148 # Treat warnings as errors but white list some warnings that we
1149 # want to allow (e.g., deprecation warnings).
1150 werror_env.Append(CCFLAGS=['-Werror',
1151 '-Wno-error=deprecated-declarations',
1152 '-Wno-error=deprecated',
1153 ])
1154
1155 def make_obj(source, static, extra_deps = None):
1156 '''This function adds the specified source to the correct
1157 build environment, and returns the corresponding SCons Object
1158 nodes'''
1159
1160 if source.swig:
1161 env = swig_env
1162 elif source.Werror:
1163 env = werror_env
1164 else:
1165 env = new_env
1166
1167 if static:
1168 obj = env.StaticObject(source.tnode)
1169 else:
1170 obj = env.SharedObject(source.tnode)
1171
1172 if extra_deps:
1173 env.Depends(obj, extra_deps)
1174
1175 return obj
1176
1177 lib_guards = {'main': False, 'skip_lib': False}
1178
1179 # Without Python, leave out all SWIG and Python content from the
1180 # library builds. The option doesn't affect gem5 built as a program
1181 if GetOption('without_python'):
1182 lib_guards['skip_no_python'] = False
1183
1184 static_objs = []
1185 shared_objs = []
1186 for s in guarded_source_iterator(Source.source_groups[None], **lib_guards):
1187 static_objs.append(make_obj(s, True))
1188 shared_objs.append(make_obj(s, False))
1189
1190 partial_objs = []
1191 for group, all_srcs in Source.source_groups.iteritems():
1192 # If these are the ungrouped source files, skip them.
1193 if not group:
1194 continue
1195
1196 # Get a list of the source files compatible with the current guards.
1197 srcs = [ s for s in guarded_source_iterator(all_srcs, **lib_guards) ]
1198 # If there aren't any left, skip this group.
1199 if not srcs:
1200 continue
1201
1202 # Set up the static partially linked objects.
1203 source_objs = [ make_obj(s, True) for s in srcs ]
1204 file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial")
1205 target = File(joinpath(group, file_name))
1206 partial = env.PartialStatic(target=target, source=source_objs)
1207 static_objs.append(partial)
1208
1209 # Set up the shared partially linked objects.
1210 source_objs = [ make_obj(s, False) for s in srcs ]
1211 file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial")
1212 target = File(joinpath(group, file_name))
1213 partial = env.PartialShared(target=target, source=source_objs)
1214 shared_objs.append(partial)
1215
1216 static_date = make_obj(date_source, static=True, extra_deps=static_objs)
1217 static_objs.append(static_date)
1218
1219 shared_date = make_obj(date_source, static=False, extra_deps=shared_objs)
1220 shared_objs.append(shared_date)
1221
1222 # First make a library of everything but main() so other programs can
1223 # link against m5.
1224 static_lib = new_env.StaticLibrary(libname, static_objs)
1225 shared_lib = new_env.SharedLibrary(libname, shared_objs)
1226
1227 # Now link a stub with main() and the static library.
1228 main_objs = [ make_obj(s, True) for s in Source.get(main=True) ]
1229
1230 for test in UnitTest.all:
1231 flags = { test.target : True }
1232 test_sources = Source.get(**flags)
1233 test_objs = [ make_obj(s, static=True) for s in test_sources ]
1234 if test.main:
1235 test_objs += main_objs
1236 path = variant('unittest/%s.%s' % (test.target, label))
1237 new_env.Program(path, test_objs + static_objs)
1238
1239 progname = exename
1240 if strip:
1241 progname += '.unstripped'
1242
1243 # When linking the gem5 binary, the command line can be too big for the
1244 # shell to handle. Use "subprocess" to spawn processes without passing
1245 # through the shell to avoid this problem. That means we also can't use
1246 # shell syntax in any of the commands this will run, but that isn't
1247 # currently an issue.
1248 def spawn_with_subprocess(sh, escape, cmd, args, env):
1249 return subprocess.call(args, env=env)
1250
1251 # Since we're not running through a shell, no escaping is necessary either.
1252 targets = new_env.Program(progname, main_objs + static_objs,
1253 SPAWN=spawn_with_subprocess,
1254 ESCAPE=lambda x: x)
1255
1256 if strip:
1257 if sys.platform == 'sunos5':
1258 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
1259 else:
1260 cmd = 'strip $SOURCE -o $TARGET'
1261 targets = new_env.Command(exename, progname,
1262 MakeAction(cmd, Transform("STRIP")))
1263
1264 new_env.Command(secondary_exename, exename,
1265 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK")))
1266
1267 new_env.M5Binary = targets[0]
1268 return new_env
1269
1270 # Start out with the compiler flags common to all compilers,
1271 # i.e. they all use -g for opt and -g -pg for prof
1272 ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'],
1273 'perf' : ['-g']}
1274
1275 # Start out with the linker flags common to all linkers, i.e. -pg for
1276 # prof, and -lprofiler for perf. The -lprofile flag is surrounded by
1277 # no-as-needed and as-needed as the binutils linker is too clever and
1278 # simply doesn't link to the library otherwise.
1279 ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'],
1280 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']}
1281
1282 # For Link Time Optimization, the optimisation flags used to compile
1283 # individual files are decoupled from those used at link time
1284 # (i.e. you can compile with -O3 and perform LTO with -O0), so we need
1285 # to also update the linker flags based on the target.
1286 if env['GCC']:
1287 if sys.platform == 'sunos5':
1288 ccflags['debug'] += ['-gstabs+']
1289 else:
1290 ccflags['debug'] += ['-ggdb3']
1291 ldflags['debug'] += ['-O0']
1292 # opt, fast, prof and perf all share the same cc flags, also add
1293 # the optimization to the ldflags as LTO defers the optimization
1294 # to link time
1295 for target in ['opt', 'fast', 'prof', 'perf']:
1296 ccflags[target] += ['-O3']
1297 ldflags[target] += ['-O3']
1298
1299 ccflags['fast'] += env['LTO_CCFLAGS']
1300 ldflags['fast'] += env['LTO_LDFLAGS']
1301 elif env['CLANG']:
1302 ccflags['debug'] += ['-g', '-O0']
1303 # opt, fast, prof and perf all share the same cc flags
1304 for target in ['opt', 'fast', 'prof', 'perf']:
1305 ccflags[target] += ['-O3']
1306 else:
1307 print 'Unknown compiler, please fix compiler options'
1308 Exit(1)
1309
1310
1311 # To speed things up, we only instantiate the build environments we
1312 # need. We try to identify the needed environment for each target; if
1313 # we can't, we fall back on instantiating all the environments just to
1314 # be safe.
1315 target_types = ['debug', 'opt', 'fast', 'prof', 'perf']
1316 obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof',
1317 'gpo' : 'perf'}
1318
1319 def identifyTarget(t):
1320 ext = t.split('.')[-1]
1321 if ext in target_types:
1322 return ext
1323 if obj2target.has_key(ext):
1324 return obj2target[ext]
1325 match = re.search(r'/tests/([^/]+)/', t)
1326 if match and match.group(1) in target_types:
1327 return match.group(1)
1328 return 'all'
1329
1330 needed_envs = [identifyTarget(target) for target in BUILD_TARGETS]
1331 if 'all' in needed_envs:
1332 needed_envs += target_types
1333
1334 def makeEnvirons(target, source, env):
1335 # cause any later Source() calls to be fatal, as a diagnostic.
1336 Source.done()
1337
1338 envList = []
1339
1340 # Debug binary
1341 if 'debug' in needed_envs:
1342 envList.append(
1343 makeEnv(env, 'debug', '.do',
1344 CCFLAGS = Split(ccflags['debug']),
1345 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'],
1346 LINKFLAGS = Split(ldflags['debug'])))
1347
1348 # Optimized binary
1349 if 'opt' in needed_envs:
1350 envList.append(
1351 makeEnv(env, 'opt', '.o',
1352 CCFLAGS = Split(ccflags['opt']),
1353 CPPDEFINES = ['TRACING_ON=1'],
1354 LINKFLAGS = Split(ldflags['opt'])))
1355
1356 # "Fast" binary
1357 if 'fast' in needed_envs:
1358 envList.append(
1359 makeEnv(env, 'fast', '.fo', strip = True,
1360 CCFLAGS = Split(ccflags['fast']),
1361 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1362 LINKFLAGS = Split(ldflags['fast'])))
1363
1364 # Profiled binary using gprof
1365 if 'prof' in needed_envs:
1366 envList.append(
1367 makeEnv(env, 'prof', '.po',
1368 CCFLAGS = Split(ccflags['prof']),
1369 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1370 LINKFLAGS = Split(ldflags['prof'])))
1371
1372 # Profiled binary using google-pprof
1373 if 'perf' in needed_envs:
1374 envList.append(
1375 makeEnv(env, 'perf', '.gpo',
1376 CCFLAGS = Split(ccflags['perf']),
1377 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1378 LINKFLAGS = Split(ldflags['perf'])))
1379
1380 # Set up the regression tests for each build.
1381 for e in envList:
1382 SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'),
1383 variant_dir = variantd('tests', e.Label),
1384 exports = { 'env' : e }, duplicate = False)
1385
1386 # The MakeEnvirons Builder defers the full dependency collection until
1387 # after processing the ISA definition (due to dynamically generated
1388 # source files). Add this dependency to all targets so they will wait
1389 # until the environments are completely set up. Otherwise, a second
1390 # process (e.g. -j2 or higher) will try to compile the requested target,
1391 # not know how, and fail.
1392 env.Append(BUILDERS = {'MakeEnvirons' :
1393 Builder(action=MakeAction(makeEnvirons,
1394 Transform("ENVIRONS", 1)))})
1395
1396 isa_target = env['PHONY_BASE'] + '-deps'
1397 environs = env['PHONY_BASE'] + '-environs'
1398 env.Depends('#all-deps', isa_target)
1399 env.Depends('#all-environs', environs)
1400 env.ScanISA(isa_target, File('arch/%s/generated/inc.d' % env['TARGET_ISA']))
1401 envSetup = env.MakeEnvirons(environs, isa_target)
1402
1403 # make sure no -deps targets occur before all ISAs are complete
1404 env.Depends(isa_target, '#all-isas')
1405 # likewise for -environs targets and all the -deps targets
1406 env.Depends(environs, '#all-deps')