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