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