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