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