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