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