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