arch-arm: AArch64 trap check, arbitrary ECs/Imms
[gem5.git] / src / SConscript
1 # -*- mode:python -*-
2
3 # Copyright (c) 2018 ARM Limited
4 #
5 # The license below extends only to copyright in the software and shall
6 # not be construed as granting a license to any other intellectual
7 # property including but not limited to intellectual property relating
8 # to a hardware implementation of the functionality of the software
9 # licensed hereunder. You may use the software subject to the license
10 # terms below provided that you ensure that this notice is replicated
11 # unmodified and in its entirety in all distributions of the software,
12 # modified or unmodified, in source code or in binary form.
13 #
14 # Copyright (c) 2004-2005 The Regents of The University of Michigan
15 # All rights reserved.
16 #
17 # Redistribution and use in source and binary forms, with or without
18 # modification, are permitted provided that the following conditions are
19 # met: redistributions of source code must retain the above copyright
20 # notice, this list of conditions and the following disclaimer;
21 # redistributions in binary form must reproduce the above copyright
22 # notice, this list of conditions and the following disclaimer in the
23 # documentation and/or other materials provided with the distribution;
24 # neither the name of the copyright holders nor the names of its
25 # contributors may be used to endorse or promote products derived from
26 # this software without specific prior written permission.
27 #
28 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #
40 # Authors: Nathan Binkert
41
42 from __future__ import print_function
43
44 import array
45 import bisect
46 import functools
47 import imp
48 import os
49 import re
50 import sys
51 import zlib
52
53 from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
54
55 import SCons
56
57 from gem5_scons import Transform, warning, error
58
59 # This file defines how to build a particular configuration of gem5
60 # based on variable settings in the 'env' build environment.
61
62 Import('*')
63
64 # Children need to see the environment
65 Export('env')
66
67 build_env = [(opt, env[opt]) for opt in export_vars]
68
69 from m5.util import code_formatter, compareVersions
70
71 ########################################################################
72 # Code for adding source files of various types
73 #
74 # When specifying a source file of some type, a set of tags can be
75 # specified for that file.
76
77 class SourceFilter(object):
78 def __init__(self, predicate):
79 self.predicate = predicate
80
81 def __or__(self, other):
82 return SourceFilter(lambda tags: self.predicate(tags) or
83 other.predicate(tags))
84
85 def __and__(self, other):
86 return SourceFilter(lambda tags: self.predicate(tags) and
87 other.predicate(tags))
88
89 def with_tags_that(predicate):
90 '''Return a list of sources with tags that satisfy a predicate.'''
91 return SourceFilter(predicate)
92
93 def with_any_tags(*tags):
94 '''Return a list of sources with any of the supplied tags.'''
95 return SourceFilter(lambda stags: len(set(tags) & stags) > 0)
96
97 def with_all_tags(*tags):
98 '''Return a list of sources with all of the supplied tags.'''
99 return SourceFilter(lambda stags: set(tags) <= stags)
100
101 def with_tag(tag):
102 '''Return a list of sources with the supplied tag.'''
103 return SourceFilter(lambda stags: tag in stags)
104
105 def without_tags(*tags):
106 '''Return a list of sources without any of the supplied tags.'''
107 return SourceFilter(lambda stags: len(set(tags) & stags) == 0)
108
109 def without_tag(tag):
110 '''Return a list of sources with the supplied tag.'''
111 return SourceFilter(lambda stags: tag not in stags)
112
113 source_filter_factories = {
114 'with_tags_that': with_tags_that,
115 'with_any_tags': with_any_tags,
116 'with_all_tags': with_all_tags,
117 'with_tag': with_tag,
118 'without_tags': without_tags,
119 'without_tag': without_tag,
120 }
121
122 Export(source_filter_factories)
123
124 class SourceList(list):
125 def apply_filter(self, f):
126 def match(source):
127 return f.predicate(source.tags)
128 return SourceList(filter(match, self))
129
130 def __getattr__(self, name):
131 func = source_filter_factories.get(name, None)
132 if not func:
133 raise AttributeError
134
135 @functools.wraps(func)
136 def wrapper(*args, **kwargs):
137 return self.apply_filter(func(*args, **kwargs))
138 return wrapper
139
140 class SourceMeta(type):
141 '''Meta class for source files that keeps track of all files of a
142 particular type.'''
143 def __init__(cls, name, bases, dict):
144 super(SourceMeta, cls).__init__(name, bases, dict)
145 cls.all = SourceList()
146
147 class SourceFile(object):
148 '''Base object that encapsulates the notion of a source file.
149 This includes, the source node, target node, various manipulations
150 of those. A source file also specifies a set of tags which
151 describing arbitrary properties of the source file.'''
152 __metaclass__ = SourceMeta
153
154 static_objs = {}
155 shared_objs = {}
156
157 def __init__(self, source, tags=None, add_tags=None):
158 if tags is None:
159 tags='gem5 lib'
160 if isinstance(tags, basestring):
161 tags = set([tags])
162 if not isinstance(tags, set):
163 tags = set(tags)
164 self.tags = tags
165
166 if add_tags:
167 if isinstance(add_tags, basestring):
168 add_tags = set([add_tags])
169 if not isinstance(add_tags, set):
170 add_tags = set(add_tags)
171 self.tags |= add_tags
172
173 tnode = source
174 if not isinstance(source, SCons.Node.FS.File):
175 tnode = File(source)
176
177 self.tnode = tnode
178 self.snode = tnode.srcnode()
179
180 for base in type(self).__mro__:
181 if issubclass(base, SourceFile):
182 base.all.append(self)
183
184 def static(self, env):
185 key = (self.tnode, env['OBJSUFFIX'])
186 if not key in self.static_objs:
187 self.static_objs[key] = env.StaticObject(self.tnode)
188 return self.static_objs[key]
189
190 def shared(self, env):
191 key = (self.tnode, env['OBJSUFFIX'])
192 if not key in self.shared_objs:
193 self.shared_objs[key] = env.SharedObject(self.tnode)
194 return self.shared_objs[key]
195
196 @property
197 def filename(self):
198 return str(self.tnode)
199
200 @property
201 def dirname(self):
202 return dirname(self.filename)
203
204 @property
205 def basename(self):
206 return basename(self.filename)
207
208 @property
209 def extname(self):
210 index = self.basename.rfind('.')
211 if index <= 0:
212 # dot files aren't extensions
213 return self.basename, None
214
215 return self.basename[:index], self.basename[index+1:]
216
217 def __lt__(self, other): return self.filename < other.filename
218 def __le__(self, other): return self.filename <= other.filename
219 def __gt__(self, other): return self.filename > other.filename
220 def __ge__(self, other): return self.filename >= other.filename
221 def __eq__(self, other): return self.filename == other.filename
222 def __ne__(self, other): return self.filename != other.filename
223
224 def blobToCpp(data, symbol, cpp_code, hpp_code=None, namespace=None):
225 '''
226 Convert bytes data into C++ .cpp and .hh uint8_t byte array
227 code containing that binary data.
228
229 :param data: binary data to be converted to C++
230 :param symbol: name of the symbol
231 :param cpp_code: append the generated cpp_code to this object
232 :param hpp_code: append the generated hpp_code to this object
233 If None, ignore it. Otherwise, also include it
234 in the .cpp file.
235 :param namespace: namespace to put the symbol into. If None,
236 don't put the symbols into any namespace.
237 '''
238 symbol_len_declaration = 'const std::size_t {}_len'.format(symbol)
239 symbol_declaration = 'const std::uint8_t {}[]'.format(symbol)
240 if hpp_code is not None:
241 cpp_code('''\
242 #include "blobs/{}.hh"
243 '''.format(symbol))
244 hpp_code('''\
245 #include <cstddef>
246 #include <cstdint>
247 ''')
248 if namespace is not None:
249 hpp_code('namespace {} {{'.format(namespace))
250 hpp_code('extern ' + symbol_len_declaration + ';')
251 hpp_code('extern ' + symbol_declaration + ';')
252 if namespace is not None:
253 hpp_code('}')
254 if namespace is not None:
255 cpp_code('namespace {} {{'.format(namespace))
256 if hpp_code is not None:
257 cpp_code(symbol_len_declaration + ' = {};'.format(len(data)))
258 cpp_code(symbol_declaration + ' = {')
259 cpp_code.indent()
260 step = 16
261 for i in xrange(0, len(data), step):
262 x = array.array('B', data[i:i+step])
263 cpp_code(''.join('%d,' % d for d in x))
264 cpp_code.dedent()
265 cpp_code('};')
266 if namespace is not None:
267 cpp_code('}')
268
269 def Blob(blob_path, symbol):
270 '''
271 Embed an arbitrary blob into the gem5 executable,
272 and make it accessible to C++ as a byte array.
273 '''
274 blob_path = os.path.abspath(blob_path)
275 blob_out_dir = os.path.join(env['BUILDDIR'], 'blobs')
276 path_noext = joinpath(blob_out_dir, symbol)
277 cpp_path = path_noext + '.cc'
278 hpp_path = path_noext + '.hh'
279 def embedBlob(target, source, env):
280 data = file(str(source[0]), 'r').read()
281 cpp_code = code_formatter()
282 hpp_code = code_formatter()
283 blobToCpp(data, symbol, cpp_code, hpp_code, namespace='Blobs')
284 cpp_path = str(target[0])
285 hpp_path = str(target[1])
286 cpp_dir = os.path.split(cpp_path)[0]
287 if not os.path.exists(cpp_dir):
288 os.makedirs(cpp_dir)
289 cpp_code.write(cpp_path)
290 hpp_code.write(hpp_path)
291 env.Command([cpp_path, hpp_path], blob_path,
292 MakeAction(embedBlob, Transform("EMBED BLOB")))
293 Source(cpp_path)
294
295 def GdbXml(xml_id, symbol):
296 Blob(joinpath(gdb_xml_dir, xml_id), symbol)
297
298 class Source(SourceFile):
299 ungrouped_tag = 'No link group'
300 source_groups = set()
301
302 _current_group_tag = ungrouped_tag
303
304 @staticmethod
305 def link_group_tag(group):
306 return 'link group: %s' % group
307
308 @classmethod
309 def set_group(cls, group):
310 new_tag = Source.link_group_tag(group)
311 Source._current_group_tag = new_tag
312 Source.source_groups.add(group)
313
314 def _add_link_group_tag(self):
315 self.tags.add(Source._current_group_tag)
316
317 '''Add a c/c++ source file to the build'''
318 def __init__(self, source, tags=None, add_tags=None):
319 '''specify the source file, and any tags'''
320 super(Source, self).__init__(source, tags, add_tags)
321 self._add_link_group_tag()
322
323 class PySource(SourceFile):
324 '''Add a python source file to the named package'''
325 invalid_sym_char = re.compile('[^A-z0-9_]')
326 modules = {}
327 tnodes = {}
328 symnames = {}
329
330 def __init__(self, package, source, tags=None, add_tags=None):
331 '''specify the python package, the source file, and any tags'''
332 super(PySource, self).__init__(source, tags, add_tags)
333
334 modname,ext = self.extname
335 assert ext == 'py'
336
337 if package:
338 path = package.split('.')
339 else:
340 path = []
341
342 modpath = path[:]
343 if modname != '__init__':
344 modpath += [ modname ]
345 modpath = '.'.join(modpath)
346
347 arcpath = path + [ self.basename ]
348 abspath = self.snode.abspath
349 if not exists(abspath):
350 abspath = self.tnode.abspath
351
352 self.package = package
353 self.modname = modname
354 self.modpath = modpath
355 self.arcname = joinpath(*arcpath)
356 self.abspath = abspath
357 self.compiled = File(self.filename + 'c')
358 self.cpp = File(self.filename + '.cc')
359 self.symname = PySource.invalid_sym_char.sub('_', modpath)
360
361 PySource.modules[modpath] = self
362 PySource.tnodes[self.tnode] = self
363 PySource.symnames[self.symname] = self
364
365 class SimObject(PySource):
366 '''Add a SimObject python file as a python source object and add
367 it to a list of sim object modules'''
368
369 fixed = False
370 modnames = []
371
372 def __init__(self, source, tags=None, add_tags=None):
373 '''Specify the source file and any tags (automatically in
374 the m5.objects package)'''
375 super(SimObject, self).__init__('m5.objects', source, tags, add_tags)
376 if self.fixed:
377 raise AttributeError, "Too late to call SimObject now."
378
379 bisect.insort_right(SimObject.modnames, self.modname)
380
381 class ProtoBuf(SourceFile):
382 '''Add a Protocol Buffer to build'''
383
384 def __init__(self, source, tags=None, add_tags=None):
385 '''Specify the source file, and any tags'''
386 super(ProtoBuf, self).__init__(source, tags, add_tags)
387
388 # Get the file name and the extension
389 modname,ext = self.extname
390 assert ext == 'proto'
391
392 # Currently, we stick to generating the C++ headers, so we
393 # only need to track the source and header.
394 self.cc_file = File(modname + '.pb.cc')
395 self.hh_file = File(modname + '.pb.h')
396
397
398 exectuable_classes = []
399 class ExecutableMeta(type):
400 '''Meta class for Executables.'''
401 all = []
402
403 def __init__(cls, name, bases, d):
404 if not d.pop('abstract', False):
405 ExecutableMeta.all.append(cls)
406 super(ExecutableMeta, cls).__init__(name, bases, d)
407
408 cls.all = []
409
410 class Executable(object):
411 '''Base class for creating an executable from sources.'''
412 __metaclass__ = ExecutableMeta
413
414 abstract = True
415
416 def __init__(self, target, *srcs_and_filts):
417 '''Specify the target name and any sources. Sources that are
418 not SourceFiles are evalued with Source().'''
419 super(Executable, self).__init__()
420 self.all.append(self)
421 self.target = target
422
423 isFilter = lambda arg: isinstance(arg, SourceFilter)
424 self.filters = filter(isFilter, srcs_and_filts)
425 sources = filter(lambda a: not isFilter(a), srcs_and_filts)
426
427 srcs = SourceList()
428 for src in sources:
429 if not isinstance(src, SourceFile):
430 src = Source(src, tags=[])
431 srcs.append(src)
432
433 self.sources = srcs
434 self.dir = Dir('.')
435
436 def path(self, env):
437 return self.dir.File(self.target + '.' + env['EXE_SUFFIX'])
438
439 def srcs_to_objs(self, env, sources):
440 return list([ s.static(env) for s in sources ])
441
442 @classmethod
443 def declare_all(cls, env):
444 return list([ instance.declare(env) for instance in cls.all ])
445
446 def declare(self, env, objs=None):
447 if objs is None:
448 objs = self.srcs_to_objs(env, self.sources)
449
450 env = env.Clone()
451 env['BIN_RPATH_PREFIX'] = os.path.relpath(
452 env['BUILDDIR'], self.path(env).dir.abspath)
453
454 if env['STRIP_EXES']:
455 stripped = self.path(env)
456 unstripped = env.File(str(stripped) + '.unstripped')
457 if sys.platform == 'sunos5':
458 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
459 else:
460 cmd = 'strip $SOURCE -o $TARGET'
461 env.Program(unstripped, objs)
462 return env.Command(stripped, unstripped,
463 MakeAction(cmd, Transform("STRIP")))
464 else:
465 return env.Program(self.path(env), objs)
466
467 class UnitTest(Executable):
468 '''Create a UnitTest'''
469 def __init__(self, target, *srcs_and_filts, **kwargs):
470 super(UnitTest, self).__init__(target, *srcs_and_filts)
471
472 self.main = kwargs.get('main', False)
473
474 def declare(self, env):
475 sources = list(self.sources)
476 for f in self.filters:
477 sources += Source.all.apply_filter(f)
478 objs = self.srcs_to_objs(env, sources) + env['STATIC_OBJS']
479 if self.main:
480 objs += env['MAIN_OBJS']
481 return super(UnitTest, self).declare(env, objs)
482
483 class GTest(Executable):
484 '''Create a unit test based on the google test framework.'''
485 all = []
486 def __init__(self, *srcs_and_filts, **kwargs):
487 super(GTest, self).__init__(*srcs_and_filts)
488
489 self.skip_lib = kwargs.pop('skip_lib', False)
490
491 @classmethod
492 def declare_all(cls, env):
493 env = env.Clone()
494 env.Append(LIBS=env['GTEST_LIBS'])
495 env.Append(CPPFLAGS=env['GTEST_CPPFLAGS'])
496 env['GTEST_LIB_SOURCES'] = Source.all.with_tag('gtest lib')
497 env['GTEST_OUT_DIR'] = \
498 Dir(env['BUILDDIR']).Dir('unittests.' + env['EXE_SUFFIX'])
499 return super(GTest, cls).declare_all(env)
500
501 def declare(self, env):
502 sources = list(self.sources)
503 if not self.skip_lib:
504 sources += env['GTEST_LIB_SOURCES']
505 for f in self.filters:
506 sources += Source.all.apply_filter(f)
507 objs = self.srcs_to_objs(env, sources)
508
509 binary = super(GTest, self).declare(env, objs)
510
511 out_dir = env['GTEST_OUT_DIR']
512 xml_file = out_dir.Dir(str(self.dir)).File(self.target + '.xml')
513 AlwaysBuild(env.Command(xml_file, binary,
514 "${SOURCES[0]} --gtest_output=xml:${TARGETS[0]}"))
515
516 return binary
517
518 class Gem5(Executable):
519 '''Create a gem5 executable.'''
520
521 def __init__(self, target):
522 super(Gem5, self).__init__(target)
523
524 def declare(self, env):
525 objs = env['MAIN_OBJS'] + env['STATIC_OBJS']
526 return super(Gem5, self).declare(env, objs)
527
528
529 # Children should have access
530 Export('Blob')
531 Export('GdbXml')
532 Export('Source')
533 Export('PySource')
534 Export('SimObject')
535 Export('ProtoBuf')
536 Export('Executable')
537 Export('UnitTest')
538 Export('GTest')
539
540 ########################################################################
541 #
542 # Debug Flags
543 #
544 debug_flags = {}
545 def DebugFlag(name, desc=None):
546 if name in debug_flags:
547 raise AttributeError, "Flag %s already specified" % name
548 debug_flags[name] = (name, (), desc)
549
550 def CompoundFlag(name, flags, desc=None):
551 if name in debug_flags:
552 raise AttributeError, "Flag %s already specified" % name
553
554 compound = tuple(flags)
555 debug_flags[name] = (name, compound, desc)
556
557 Export('DebugFlag')
558 Export('CompoundFlag')
559
560 ########################################################################
561 #
562 # Set some compiler variables
563 #
564
565 # Include file paths are rooted in this directory. SCons will
566 # automatically expand '.' to refer to both the source directory and
567 # the corresponding build directory to pick up generated include
568 # files.
569 env.Append(CPPPATH=Dir('.'))
570
571 for extra_dir in extras_dir_list:
572 env.Append(CPPPATH=Dir(extra_dir))
573
574 # Workaround for bug in SCons version > 0.97d20071212
575 # Scons bug id: 2006 gem5 Bug id: 308
576 for root, dirs, files in os.walk(base_dir, topdown=True):
577 Dir(root[len(base_dir) + 1:])
578
579 ########################################################################
580 #
581 # Walk the tree and execute all SConscripts in subdirectories
582 #
583
584 here = Dir('.').srcnode().abspath
585 for root, dirs, files in os.walk(base_dir, topdown=True):
586 if root == here:
587 # we don't want to recurse back into this SConscript
588 continue
589
590 if 'SConscript' in files:
591 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
592 Source.set_group(build_dir)
593 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
594
595 for extra_dir in extras_dir_list:
596 prefix_len = len(dirname(extra_dir)) + 1
597
598 # Also add the corresponding build directory to pick up generated
599 # include files.
600 env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:])))
601
602 for root, dirs, files in os.walk(extra_dir, topdown=True):
603 # if build lives in the extras directory, don't walk down it
604 if 'build' in dirs:
605 dirs.remove('build')
606
607 if 'SConscript' in files:
608 build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
609 Source.set_group(build_dir)
610 SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir)
611
612 for opt in export_vars:
613 env.ConfigFile(opt)
614
615 def makeTheISA(source, target, env):
616 isas = [ src.get_contents() for src in source ]
617 target_isa = env['TARGET_ISA']
618 def define(isa):
619 return isa.upper() + '_ISA'
620
621 def namespace(isa):
622 return isa[0].upper() + isa[1:].lower() + 'ISA'
623
624
625 code = code_formatter()
626 code('''\
627 #ifndef __CONFIG_THE_ISA_HH__
628 #define __CONFIG_THE_ISA_HH__
629
630 ''')
631
632 # create defines for the preprocessing and compile-time determination
633 for i,isa in enumerate(isas):
634 code('#define $0 $1', define(isa), i + 1)
635 code()
636
637 # create an enum for any run-time determination of the ISA, we
638 # reuse the same name as the namespaces
639 code('enum class Arch {')
640 for i,isa in enumerate(isas):
641 if i + 1 == len(isas):
642 code(' $0 = $1', namespace(isa), define(isa))
643 else:
644 code(' $0 = $1,', namespace(isa), define(isa))
645 code('};')
646
647 code('''
648
649 #define THE_ISA ${{define(target_isa)}}
650 #define TheISA ${{namespace(target_isa)}}
651 #define THE_ISA_STR "${{target_isa}}"
652
653 #endif // __CONFIG_THE_ISA_HH__''')
654
655 code.write(str(target[0]))
656
657 env.Command('config/the_isa.hh', map(Value, all_isa_list),
658 MakeAction(makeTheISA, Transform("CFG ISA", 0)))
659
660 def makeTheGPUISA(source, target, env):
661 isas = [ src.get_contents() for src in source ]
662 target_gpu_isa = env['TARGET_GPU_ISA']
663 def define(isa):
664 return isa.upper() + '_ISA'
665
666 def namespace(isa):
667 return isa[0].upper() + isa[1:].lower() + 'ISA'
668
669
670 code = code_formatter()
671 code('''\
672 #ifndef __CONFIG_THE_GPU_ISA_HH__
673 #define __CONFIG_THE_GPU_ISA_HH__
674
675 ''')
676
677 # create defines for the preprocessing and compile-time determination
678 for i,isa in enumerate(isas):
679 code('#define $0 $1', define(isa), i + 1)
680 code()
681
682 # create an enum for any run-time determination of the ISA, we
683 # reuse the same name as the namespaces
684 code('enum class GPUArch {')
685 for i,isa in enumerate(isas):
686 if i + 1 == len(isas):
687 code(' $0 = $1', namespace(isa), define(isa))
688 else:
689 code(' $0 = $1,', namespace(isa), define(isa))
690 code('};')
691
692 code('''
693
694 #define THE_GPU_ISA ${{define(target_gpu_isa)}}
695 #define TheGpuISA ${{namespace(target_gpu_isa)}}
696 #define THE_GPU_ISA_STR "${{target_gpu_isa}}"
697
698 #endif // __CONFIG_THE_GPU_ISA_HH__''')
699
700 code.write(str(target[0]))
701
702 env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list),
703 MakeAction(makeTheGPUISA, Transform("CFG ISA", 0)))
704
705 ########################################################################
706 #
707 # Prevent any SimObjects from being added after this point, they
708 # should all have been added in the SConscripts above
709 #
710 SimObject.fixed = True
711
712 class DictImporter(object):
713 '''This importer takes a dictionary of arbitrary module names that
714 map to arbitrary filenames.'''
715 def __init__(self, modules):
716 self.modules = modules
717 self.installed = set()
718
719 def __del__(self):
720 self.unload()
721
722 def unload(self):
723 import sys
724 for module in self.installed:
725 del sys.modules[module]
726 self.installed = set()
727
728 def find_module(self, fullname, path):
729 if fullname == 'm5.defines':
730 return self
731
732 if fullname == 'm5.objects':
733 return self
734
735 if fullname.startswith('_m5'):
736 return None
737
738 source = self.modules.get(fullname, None)
739 if source is not None and fullname.startswith('m5.objects'):
740 return self
741
742 return None
743
744 def load_module(self, fullname):
745 mod = imp.new_module(fullname)
746 sys.modules[fullname] = mod
747 self.installed.add(fullname)
748
749 mod.__loader__ = self
750 if fullname == 'm5.objects':
751 mod.__path__ = fullname.split('.')
752 return mod
753
754 if fullname == 'm5.defines':
755 mod.__dict__['buildEnv'] = m5.util.SmartDict(build_env)
756 return mod
757
758 source = self.modules[fullname]
759 if source.modname == '__init__':
760 mod.__path__ = source.modpath
761 mod.__file__ = source.abspath
762
763 exec file(source.abspath, 'r') in mod.__dict__
764
765 return mod
766
767 import m5.SimObject
768 import m5.params
769 from m5.util import code_formatter
770
771 m5.SimObject.clear()
772 m5.params.clear()
773
774 # install the python importer so we can grab stuff from the source
775 # tree itself. We can't have SimObjects added after this point or
776 # else we won't know about them for the rest of the stuff.
777 importer = DictImporter(PySource.modules)
778 sys.meta_path[0:0] = [ importer ]
779
780 # import all sim objects so we can populate the all_objects list
781 # make sure that we're working with a list, then let's sort it
782 for modname in SimObject.modnames:
783 exec('from m5.objects import %s' % modname)
784
785 # we need to unload all of the currently imported modules so that they
786 # will be re-imported the next time the sconscript is run
787 importer.unload()
788 sys.meta_path.remove(importer)
789
790 sim_objects = m5.SimObject.allClasses
791 all_enums = m5.params.allEnums
792
793 for name,obj in sorted(sim_objects.iteritems()):
794 for param in obj._params.local.values():
795 # load the ptype attribute now because it depends on the
796 # current version of SimObject.allClasses, but when scons
797 # actually uses the value, all versions of
798 # SimObject.allClasses will have been loaded
799 param.ptype
800
801 ########################################################################
802 #
803 # calculate extra dependencies
804 #
805 module_depends = ["m5", "m5.SimObject", "m5.params"]
806 depends = [ PySource.modules[dep].snode for dep in module_depends ]
807 depends.sort(key = lambda x: x.name)
808
809 ########################################################################
810 #
811 # Commands for the basic automatically generated python files
812 #
813
814 # Generate Python file containing a dict specifying the current
815 # buildEnv flags.
816 def makeDefinesPyFile(target, source, env):
817 build_env = source[0].get_contents()
818
819 code = code_formatter()
820 code("""
821 import _m5.core
822 import m5.util
823
824 buildEnv = m5.util.SmartDict($build_env)
825
826 compileDate = _m5.core.compileDate
827 _globals = globals()
828 for key,val in _m5.core.__dict__.items():
829 if key.startswith('flag_'):
830 flag = key[5:]
831 _globals[flag] = val
832 del _globals
833 """)
834 code.write(target[0].abspath)
835
836 defines_info = Value(build_env)
837 # Generate a file with all of the compile options in it
838 env.Command('python/m5/defines.py', defines_info,
839 MakeAction(makeDefinesPyFile, Transform("DEFINES", 0)))
840 PySource('m5', 'python/m5/defines.py')
841
842 # Generate python file containing info about the M5 source code
843 def makeInfoPyFile(target, source, env):
844 code = code_formatter()
845 for src in source:
846 data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
847 code('$src = ${{repr(data)}}')
848 code.write(str(target[0]))
849
850 # Generate a file that wraps the basic top level files
851 env.Command('python/m5/info.py',
852 [ '#/COPYING', '#/LICENSE', '#/README', ],
853 MakeAction(makeInfoPyFile, Transform("INFO")))
854 PySource('m5', 'python/m5/info.py')
855
856 ########################################################################
857 #
858 # Create all of the SimObject param headers and enum headers
859 #
860
861 def createSimObjectParamStruct(target, source, env):
862 assert len(target) == 1 and len(source) == 1
863
864 name = source[0].get_text_contents()
865 obj = sim_objects[name]
866
867 code = code_formatter()
868 obj.cxx_param_decl(code)
869 code.write(target[0].abspath)
870
871 def createSimObjectCxxConfig(is_header):
872 def body(target, source, env):
873 assert len(target) == 1 and len(source) == 1
874
875 name = str(source[0].get_contents())
876 obj = sim_objects[name]
877
878 code = code_formatter()
879 obj.cxx_config_param_file(code, is_header)
880 code.write(target[0].abspath)
881 return body
882
883 def createEnumStrings(target, source, env):
884 assert len(target) == 1 and len(source) == 2
885
886 name = source[0].get_text_contents()
887 use_python = source[1].read()
888 obj = all_enums[name]
889
890 code = code_formatter()
891 obj.cxx_def(code)
892 if use_python:
893 obj.pybind_def(code)
894 code.write(target[0].abspath)
895
896 def createEnumDecls(target, source, env):
897 assert len(target) == 1 and len(source) == 1
898
899 name = source[0].get_text_contents()
900 obj = all_enums[name]
901
902 code = code_formatter()
903 obj.cxx_decl(code)
904 code.write(target[0].abspath)
905
906 def createSimObjectPyBindWrapper(target, source, env):
907 name = source[0].get_text_contents()
908 obj = sim_objects[name]
909
910 code = code_formatter()
911 obj.pybind_decl(code)
912 code.write(target[0].abspath)
913
914 # Generate all of the SimObject param C++ struct header files
915 params_hh_files = []
916 for name,simobj in sorted(sim_objects.iteritems()):
917 py_source = PySource.modules[simobj.__module__]
918 extra_deps = [ py_source.tnode ]
919
920 hh_file = File('params/%s.hh' % name)
921 params_hh_files.append(hh_file)
922 env.Command(hh_file, Value(name),
923 MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
924 env.Depends(hh_file, depends + extra_deps)
925
926 # C++ parameter description files
927 if GetOption('with_cxx_config'):
928 for name,simobj in sorted(sim_objects.iteritems()):
929 py_source = PySource.modules[simobj.__module__]
930 extra_deps = [ py_source.tnode ]
931
932 cxx_config_hh_file = File('cxx_config/%s.hh' % name)
933 cxx_config_cc_file = File('cxx_config/%s.cc' % name)
934 env.Command(cxx_config_hh_file, Value(name),
935 MakeAction(createSimObjectCxxConfig(True),
936 Transform("CXXCPRHH")))
937 env.Command(cxx_config_cc_file, Value(name),
938 MakeAction(createSimObjectCxxConfig(False),
939 Transform("CXXCPRCC")))
940 env.Depends(cxx_config_hh_file, depends + extra_deps +
941 [File('params/%s.hh' % name), File('sim/cxx_config.hh')])
942 env.Depends(cxx_config_cc_file, depends + extra_deps +
943 [cxx_config_hh_file])
944 Source(cxx_config_cc_file)
945
946 cxx_config_init_cc_file = File('cxx_config/init.cc')
947
948 def createCxxConfigInitCC(target, source, env):
949 assert len(target) == 1 and len(source) == 1
950
951 code = code_formatter()
952
953 for name,simobj in sorted(sim_objects.iteritems()):
954 if not hasattr(simobj, 'abstract') or not simobj.abstract:
955 code('#include "cxx_config/${name}.hh"')
956 code()
957 code('void cxxConfigInit()')
958 code('{')
959 code.indent()
960 for name,simobj in sorted(sim_objects.iteritems()):
961 not_abstract = not hasattr(simobj, 'abstract') or \
962 not simobj.abstract
963 if not_abstract and 'type' in simobj.__dict__:
964 code('cxx_config_directory["${name}"] = '
965 '${name}CxxConfigParams::makeDirectoryEntry();')
966 code.dedent()
967 code('}')
968 code.write(target[0].abspath)
969
970 py_source = PySource.modules[simobj.__module__]
971 extra_deps = [ py_source.tnode ]
972 env.Command(cxx_config_init_cc_file, Value(name),
973 MakeAction(createCxxConfigInitCC, Transform("CXXCINIT")))
974 cxx_param_hh_files = ["cxx_config/%s.hh" % simobj
975 for name,simobj in sorted(sim_objects.iteritems())
976 if not hasattr(simobj, 'abstract') or not simobj.abstract]
977 Depends(cxx_config_init_cc_file, cxx_param_hh_files +
978 [File('sim/cxx_config.hh')])
979 Source(cxx_config_init_cc_file)
980
981 # Generate all enum header files
982 for name,enum in sorted(all_enums.iteritems()):
983 py_source = PySource.modules[enum.__module__]
984 extra_deps = [ py_source.tnode ]
985
986 cc_file = File('enums/%s.cc' % name)
987 env.Command(cc_file, [Value(name), Value(env['USE_PYTHON'])],
988 MakeAction(createEnumStrings, Transform("ENUM STR")))
989 env.Depends(cc_file, depends + extra_deps)
990 Source(cc_file)
991
992 hh_file = File('enums/%s.hh' % name)
993 env.Command(hh_file, Value(name),
994 MakeAction(createEnumDecls, Transform("ENUMDECL")))
995 env.Depends(hh_file, depends + extra_deps)
996
997 # Generate SimObject Python bindings wrapper files
998 if env['USE_PYTHON']:
999 for name,simobj in sorted(sim_objects.iteritems()):
1000 py_source = PySource.modules[simobj.__module__]
1001 extra_deps = [ py_source.tnode ]
1002 cc_file = File('python/_m5/param_%s.cc' % name)
1003 env.Command(cc_file, Value(name),
1004 MakeAction(createSimObjectPyBindWrapper,
1005 Transform("SO PyBind")))
1006 env.Depends(cc_file, depends + extra_deps)
1007 Source(cc_file)
1008
1009 # Build all protocol buffers if we have got protoc and protobuf available
1010 if env['HAVE_PROTOC'] and env['HAVE_PROTOBUF']:
1011 for proto in ProtoBuf.all:
1012 # Use both the source and header as the target, and the .proto
1013 # file as the source. When executing the protoc compiler, also
1014 # specify the proto_path to avoid having the generated files
1015 # include the path.
1016 env.Command([proto.cc_file, proto.hh_file], proto.tnode,
1017 MakeAction('${PROTOC} --cpp_out ${TARGET.dir} '
1018 '--proto_path ${SOURCE.dir} $SOURCE',
1019 Transform("PROTOC")))
1020
1021 # Add the C++ source file
1022 Source(proto.cc_file, tags=proto.tags)
1023 elif ProtoBuf.all:
1024 error('Got protobuf to build, but lacks support!')
1025
1026 #
1027 # Handle debug flags
1028 #
1029 def makeDebugFlagCC(target, source, env):
1030 assert(len(target) == 1 and len(source) == 1)
1031
1032 code = code_formatter()
1033
1034 # delay definition of CompoundFlags until after all the definition
1035 # of all constituent SimpleFlags
1036 comp_code = code_formatter()
1037
1038 # file header
1039 code('''
1040 /*
1041 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
1042 */
1043
1044 #include "base/debug.hh"
1045
1046 namespace Debug {
1047
1048 ''')
1049
1050 for name, flag in sorted(source[0].read().iteritems()):
1051 n, compound, desc = flag
1052 assert n == name
1053
1054 if not compound:
1055 code('SimpleFlag $name("$name", "$desc");')
1056 else:
1057 comp_code('CompoundFlag $name("$name", "$desc",')
1058 comp_code.indent()
1059 last = len(compound) - 1
1060 for i,flag in enumerate(compound):
1061 if i != last:
1062 comp_code('&$flag,')
1063 else:
1064 comp_code('&$flag);')
1065 comp_code.dedent()
1066
1067 code.append(comp_code)
1068 code()
1069 code('} // namespace Debug')
1070
1071 code.write(str(target[0]))
1072
1073 def makeDebugFlagHH(target, source, env):
1074 assert(len(target) == 1 and len(source) == 1)
1075
1076 val = eval(source[0].get_contents())
1077 name, compound, desc = val
1078
1079 code = code_formatter()
1080
1081 # file header boilerplate
1082 code('''\
1083 /*
1084 * DO NOT EDIT THIS FILE! Automatically generated by SCons.
1085 */
1086
1087 #ifndef __DEBUG_${name}_HH__
1088 #define __DEBUG_${name}_HH__
1089
1090 namespace Debug {
1091 ''')
1092
1093 if compound:
1094 code('class CompoundFlag;')
1095 code('class SimpleFlag;')
1096
1097 if compound:
1098 code('extern CompoundFlag $name;')
1099 for flag in compound:
1100 code('extern SimpleFlag $flag;')
1101 else:
1102 code('extern SimpleFlag $name;')
1103
1104 code('''
1105 }
1106
1107 #endif // __DEBUG_${name}_HH__
1108 ''')
1109
1110 code.write(str(target[0]))
1111
1112 for name,flag in sorted(debug_flags.iteritems()):
1113 n, compound, desc = flag
1114 assert n == name
1115
1116 hh_file = 'debug/%s.hh' % name
1117 env.Command(hh_file, Value(flag),
1118 MakeAction(makeDebugFlagHH, Transform("TRACING", 0)))
1119
1120 env.Command('debug/flags.cc', Value(debug_flags),
1121 MakeAction(makeDebugFlagCC, Transform("TRACING", 0)))
1122 Source('debug/flags.cc')
1123
1124 # version tags
1125 tags = \
1126 env.Command('sim/tags.cc', None,
1127 MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET',
1128 Transform("VER TAGS")))
1129 env.AlwaysBuild(tags)
1130
1131 # Build a small helper that marshals the Python code using the same
1132 # version of Python as gem5. This is in an unorthodox location to
1133 # avoid building it for every variant.
1134 py_marshal = env.Program('marshal', 'python/marshal.cc')[0]
1135
1136 # Embed python files. All .py files that have been indicated by a
1137 # PySource() call in a SConscript need to be embedded into the M5
1138 # library. To do that, we compile the file to byte code, marshal the
1139 # byte code, compress it, and then generate a c++ file that
1140 # inserts the result into an array.
1141 def embedPyFile(target, source, env):
1142 def c_str(string):
1143 if string is None:
1144 return "0"
1145 return '"%s"' % string
1146
1147 '''Action function to compile a .py into a code object, marshal it,
1148 compress it, and stick it into an asm file so the code appears as
1149 just bytes with a label in the data section. The action takes two
1150 sources:
1151
1152 source[0]: Binary used to marshal Python sources
1153 source[1]: Python script to marshal
1154 '''
1155
1156 import subprocess
1157
1158 marshalled = subprocess.check_output([source[0].abspath, str(source[1])])
1159
1160 compressed = zlib.compress(marshalled)
1161 data = compressed
1162 pysource = PySource.tnodes[source[1]]
1163 sym = pysource.symname
1164
1165 code = code_formatter()
1166 code('''\
1167 #include "sim/init.hh"
1168
1169 namespace {
1170
1171 ''')
1172 blobToCpp(data, 'data_' + sym, code)
1173 code('''\
1174
1175
1176 EmbeddedPython embedded_${sym}(
1177 ${{c_str(pysource.arcname)}},
1178 ${{c_str(pysource.abspath)}},
1179 ${{c_str(pysource.modpath)}},
1180 data_${sym},
1181 ${{len(data)}},
1182 ${{len(marshalled)}});
1183
1184 } // anonymous namespace
1185 ''')
1186 code.write(str(target[0]))
1187
1188 for source in PySource.all:
1189 env.Command(source.cpp, [ py_marshal, source.tnode ],
1190 MakeAction(embedPyFile, Transform("EMBED PY")))
1191 Source(source.cpp, tags=source.tags, add_tags='python')
1192
1193 ########################################################################
1194 #
1195 # Define binaries. Each different build type (debug, opt, etc.) gets
1196 # a slightly different build environment.
1197 #
1198
1199 # List of constructed environments to pass back to SConstruct
1200 date_source = Source('base/date.cc', tags=[])
1201
1202 gem5_binary = Gem5('gem5')
1203
1204 # Function to create a new build environment as clone of current
1205 # environment 'env' with modified object suffix and optional stripped
1206 # binary. Additional keyword arguments are appended to corresponding
1207 # build environment vars.
1208 def makeEnv(env, label, objsfx, strip=False, disable_partial=False, **kwargs):
1209 # SCons doesn't know to append a library suffix when there is a '.' in the
1210 # name. Use '_' instead.
1211 libname = 'gem5_' + label
1212 secondary_exename = 'm5.' + label
1213
1214 new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
1215 new_env.Label = label
1216 new_env.Append(**kwargs)
1217
1218 lib_sources = Source.all.with_tag('gem5 lib')
1219
1220 # Without Python, leave out all Python content from the library
1221 # builds. The option doesn't affect gem5 built as a program
1222 if GetOption('without_python'):
1223 lib_sources = lib_sources.without_tag('python')
1224
1225 static_objs = []
1226 shared_objs = []
1227
1228 for s in lib_sources.with_tag(Source.ungrouped_tag):
1229 static_objs.append(s.static(new_env))
1230 shared_objs.append(s.shared(new_env))
1231
1232 for group in Source.source_groups:
1233 srcs = lib_sources.with_tag(Source.link_group_tag(group))
1234 if not srcs:
1235 continue
1236
1237 group_static = [ s.static(new_env) for s in srcs ]
1238 group_shared = [ s.shared(new_env) for s in srcs ]
1239
1240 # If partial linking is disabled, add these sources to the build
1241 # directly, and short circuit this loop.
1242 if disable_partial:
1243 static_objs.extend(group_static)
1244 shared_objs.extend(group_shared)
1245 continue
1246
1247 # Set up the static partially linked objects.
1248 file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial")
1249 target = File(joinpath(group, file_name))
1250 partial = env.PartialStatic(target=target, source=group_static)
1251 static_objs.extend(partial)
1252
1253 # Set up the shared partially linked objects.
1254 file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial")
1255 target = File(joinpath(group, file_name))
1256 partial = env.PartialShared(target=target, source=group_shared)
1257 shared_objs.extend(partial)
1258
1259 static_date = date_source.static(new_env)
1260 new_env.Depends(static_date, static_objs)
1261 static_objs.extend(static_date)
1262
1263 shared_date = date_source.shared(new_env)
1264 new_env.Depends(shared_date, shared_objs)
1265 shared_objs.extend(shared_date)
1266
1267 main_objs = [ s.static(new_env) for s in Source.all.with_tag('main') ]
1268
1269 # First make a library of everything but main() so other programs can
1270 # link against m5.
1271 static_lib = new_env.StaticLibrary(libname, static_objs)
1272 shared_lib = new_env.SharedLibrary(libname, shared_objs)
1273
1274 # Keep track of the object files generated so far so Executables can
1275 # include them.
1276 new_env['STATIC_OBJS'] = static_objs
1277 new_env['SHARED_OBJS'] = shared_objs
1278 new_env['MAIN_OBJS'] = main_objs
1279
1280 new_env['STATIC_LIB'] = static_lib
1281 new_env['SHARED_LIB'] = shared_lib
1282
1283 # Record some settings for building Executables.
1284 new_env['EXE_SUFFIX'] = label
1285 new_env['STRIP_EXES'] = strip
1286
1287 for cls in ExecutableMeta.all:
1288 cls.declare_all(new_env)
1289
1290 new_env.M5Binary = File(gem5_binary.path(new_env))
1291
1292 new_env.Command(secondary_exename, new_env.M5Binary,
1293 MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK")))
1294
1295 # Set up regression tests.
1296 SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'),
1297 variant_dir=Dir('tests').Dir(new_env.Label),
1298 exports={ 'env' : new_env }, duplicate=False)
1299
1300 # Start out with the compiler flags common to all compilers,
1301 # i.e. they all use -g for opt and -g -pg for prof
1302 ccflags = {'debug' : [], 'opt' : ['-g'], 'fast' : [], 'prof' : ['-g', '-pg'],
1303 'perf' : ['-g']}
1304
1305 # Start out with the linker flags common to all linkers, i.e. -pg for
1306 # prof, and -lprofiler for perf. The -lprofile flag is surrounded by
1307 # no-as-needed and as-needed as the binutils linker is too clever and
1308 # simply doesn't link to the library otherwise.
1309 ldflags = {'debug' : [], 'opt' : [], 'fast' : [], 'prof' : ['-pg'],
1310 'perf' : ['-Wl,--no-as-needed', '-lprofiler', '-Wl,--as-needed']}
1311
1312 # For Link Time Optimization, the optimisation flags used to compile
1313 # individual files are decoupled from those used at link time
1314 # (i.e. you can compile with -O3 and perform LTO with -O0), so we need
1315 # to also update the linker flags based on the target.
1316 if env['GCC']:
1317 if sys.platform == 'sunos5':
1318 ccflags['debug'] += ['-gstabs+']
1319 else:
1320 ccflags['debug'] += ['-ggdb3']
1321 ldflags['debug'] += ['-O0']
1322 # opt, fast, prof and perf all share the same cc flags, also add
1323 # the optimization to the ldflags as LTO defers the optimization
1324 # to link time
1325 for target in ['opt', 'fast', 'prof', 'perf']:
1326 ccflags[target] += ['-O3']
1327 ldflags[target] += ['-O3']
1328
1329 ccflags['fast'] += env['LTO_CCFLAGS']
1330 ldflags['fast'] += env['LTO_LDFLAGS']
1331 elif env['CLANG']:
1332 ccflags['debug'] += ['-g', '-O0']
1333 # opt, fast, prof and perf all share the same cc flags
1334 for target in ['opt', 'fast', 'prof', 'perf']:
1335 ccflags[target] += ['-O3']
1336 else:
1337 error('Unknown compiler, please fix compiler options')
1338
1339
1340 # To speed things up, we only instantiate the build environments we
1341 # need. We try to identify the needed environment for each target; if
1342 # we can't, we fall back on instantiating all the environments just to
1343 # be safe.
1344 target_types = ['debug', 'opt', 'fast', 'prof', 'perf']
1345 obj2target = {'do': 'debug', 'o': 'opt', 'fo': 'fast', 'po': 'prof',
1346 'gpo' : 'perf'}
1347
1348 def identifyTarget(t):
1349 ext = t.split('.')[-1]
1350 if ext in target_types:
1351 return ext
1352 if ext in obj2target:
1353 return obj2target[ext]
1354 match = re.search(r'/tests/([^/]+)/', t)
1355 if match and match.group(1) in target_types:
1356 return match.group(1)
1357 return 'all'
1358
1359 needed_envs = [identifyTarget(target) for target in BUILD_TARGETS]
1360 if 'all' in needed_envs:
1361 needed_envs += target_types
1362
1363 disable_partial = False
1364 if env['PLATFORM'] == 'darwin':
1365 # Up until Apple LLVM version 10.0.0 (clang-1000.11.45.5), partial
1366 # linked objects do not expose symbols that are marked with the
1367 # hidden visibility and consequently building gem5 on Mac OS
1368 # fails. As a workaround, we disable partial linking, however, we
1369 # may want to revisit in the future.
1370 disable_partial = True
1371
1372 # Debug binary
1373 if 'debug' in needed_envs:
1374 makeEnv(env, 'debug', '.do',
1375 CCFLAGS = Split(ccflags['debug']),
1376 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'],
1377 LINKFLAGS = Split(ldflags['debug']),
1378 disable_partial=disable_partial)
1379
1380 # Optimized binary
1381 if 'opt' in needed_envs:
1382 makeEnv(env, 'opt', '.o',
1383 CCFLAGS = Split(ccflags['opt']),
1384 CPPDEFINES = ['TRACING_ON=1'],
1385 LINKFLAGS = Split(ldflags['opt']),
1386 disable_partial=disable_partial)
1387
1388 # "Fast" binary
1389 if 'fast' in needed_envs:
1390 disable_partial = disable_partial or \
1391 (env.get('BROKEN_INCREMENTAL_LTO', False) and \
1392 GetOption('force_lto'))
1393 makeEnv(env, 'fast', '.fo', strip = True,
1394 CCFLAGS = Split(ccflags['fast']),
1395 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1396 LINKFLAGS = Split(ldflags['fast']),
1397 disable_partial=disable_partial)
1398
1399 # Profiled binary using gprof
1400 if 'prof' in needed_envs:
1401 makeEnv(env, 'prof', '.po',
1402 CCFLAGS = Split(ccflags['prof']),
1403 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1404 LINKFLAGS = Split(ldflags['prof']),
1405 disable_partial=disable_partial)
1406
1407 # Profiled binary using google-pprof
1408 if 'perf' in needed_envs:
1409 makeEnv(env, 'perf', '.gpo',
1410 CCFLAGS = Split(ccflags['perf']),
1411 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
1412 LINKFLAGS = Split(ldflags['perf']),
1413 disable_partial=disable_partial)