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