3 # Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
29 # Authors: Nathan Binkert
35 from os.path import basename, exists, isdir, isfile, join as joinpath
39 # This file defines how to build a particular configuration of M5
40 # based on variable settings in the 'env' build environment.
44 # Children need to see the environment
48 """return a sorted copy of '_list'"""
49 if isinstance(_list, list):
56 class PySourceFile(object):
57 def __init__(self, package, source):
58 filename = str(source)
59 pyname = basename(filename)
60 assert pyname.endswith('.py')
62 path = package.split('.')
64 if name != '__init__':
66 modpath = '.'.join(modpath)
68 arcpath = package.split('.') + [ pyname + 'c' ]
69 arcname = joinpath(*arcpath)
73 self.srcpath = source.srcnode().abspath
74 self.package = package
75 self.modpath = modpath
76 self.arcname = arcname
77 self.filename = filename
78 self.compiled = File(filename + 'c')
80 ########################################################################
81 # Code for adding source files of various types
85 '''Add a C/C++ source file to the build'''
86 if not isinstance(source, SCons.Node.FS.File):
89 cc_sources.append(source)
92 def PySource(package, source):
93 '''Add a python source file to the named package'''
94 if not isinstance(source, SCons.Node.FS.File):
97 source = PySourceFile(package, source)
98 py_sources.append(source)
100 sim_objects_fixed = False
101 sim_object_modfiles = set()
102 def SimObject(source):
103 '''Add a SimObject python file as a python source object and add
104 it to a list of sim object modules'''
106 if sim_objects_fixed:
107 raise AttributeError, "Too late to call SimObject now."
109 if not isinstance(source, SCons.Node.FS.File):
110 source = File(source)
112 PySource('m5.objects', source)
113 modfile = basename(str(source))
114 assert modfile.endswith('.py')
115 modname = modfile[:-3]
116 sim_object_modfiles.add(modname)
119 def SwigSource(package, source):
120 '''Add a swig file to build'''
121 if not isinstance(source, SCons.Node.FS.File):
122 source = File(source)
124 swig_sources.append(val)
126 # Children should have access
132 ########################################################################
138 def TraceFlag(name, desc=''):
139 if name in all_flags:
140 raise AttributeError, "Flag %s already specified" % name
141 flag = (name, (), desc)
142 trace_flags.append(flag)
145 def CompoundFlag(name, flags, desc=''):
146 if name in all_flags:
147 raise AttributeError, "Flag %s already specified" % name
149 compound = tuple(flags)
150 for flag in compound:
151 if flag not in all_flags:
152 raise AttributeError, "Trace flag %s not found" % flag
154 raise AttributeError, \
155 "Compound flag can't point to another compound flag"
157 flag = (name, compound, desc)
158 trace_flags.append(flag)
159 all_flags[name] = compound
162 Export('CompoundFlag')
164 ########################################################################
166 # Set some compiler variables
169 # Include file paths are rooted in this directory. SCons will
170 # automatically expand '.' to refer to both the source directory and
171 # the corresponding build directory to pick up generated include
173 env.Append(CPPPATH=Dir('.'))
175 # Add a flag defining what THE_ISA should be for all compilation
176 env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
178 ########################################################################
180 # Walk the tree and execute all SConscripts in subdirectories
183 for base_dir in base_dir_list:
184 here = Dir('.').srcnode().abspath
185 for root, dirs, files in os.walk(base_dir, topdown=True):
187 # we don't want to recurse back into this SConscript
190 if 'SConscript' in files:
191 build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
192 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
194 for opt in env.ExportOptions:
197 ########################################################################
199 # Prevent any SimObjects from being added after this point, they
200 # should all have been added in the SConscripts above
202 sim_objects_fixed = True
204 ########################################################################
206 # Manually turn python/generate.py into a python module and import it
208 generate_file = File('python/generate.py')
209 generate_module = imp.new_module('generate')
210 sys.modules['generate'] = generate_module
211 exec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__
213 ########################################################################
217 from generate import Generate
218 optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
219 generate = Generate(py_sources, sim_object_modfiles, optionDict)
222 ########################################################################
224 # calculate extra dependencies
226 module_depends = ["m5", "m5.SimObject", "m5.params"]
227 module_depends = [ File(generate.py_modules[dep]) for dep in module_depends ]
228 file_depends = [ generate_file ]
229 depends = module_depends + file_depends
231 ########################################################################
233 # Commands for the basic automatically generated python files
236 # Generate a file with all of the compile options in it
237 env.Command('python/m5/defines.py', Value(optionDict),
238 generate.makeDefinesPyFile)
239 PySource('m5', 'python/m5/defines.py')
241 # Generate a file that wraps the basic top level files
242 env.Command('python/m5/info.py',
243 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
244 generate.makeInfoPyFile)
245 PySource('m5', 'python/m5/info.py')
247 # Generate an __init__.py file for the objects package
248 env.Command('python/m5/objects/__init__.py',
249 [ Value(o) for o in sort_list(sim_object_modfiles) ],
250 generate.makeObjectsInitFile)
251 PySource('m5.objects', 'python/m5/objects/__init__.py')
253 ########################################################################
255 # Create all of the SimObject param headers and enum headers
258 # Generate all of the SimObject param struct header files
260 for name,simobj in generate.sim_objects.iteritems():
261 extra_deps = [ File(generate.py_modules[simobj.__module__]) ]
263 hh_file = File('params/%s.hh' % name)
264 params_hh_files.append(hh_file)
265 env.Command(hh_file, Value(name), generate.createSimObjectParam)
266 env.Depends(hh_file, depends + extra_deps)
268 # Generate any parameter header files needed
269 for name,param in generate.params.iteritems():
270 if isinstance(param, m5.params.VectorParamDesc):
275 i_file = File('params/%s_%s.i' % (name, ext))
276 env.Command(i_file, Value(name), generate.createSwigParam)
277 env.Depends(i_file, depends)
279 # Generate all enum header files
280 for name,enum in generate.enums.iteritems():
281 extra_deps = [ File(generate.py_modules[enum.__module__]) ]
283 cc_file = File('enums/%s.cc' % name)
284 env.Command(cc_file, Value(name), generate.createEnumStrings)
285 env.Depends(cc_file, depends + extra_deps)
288 hh_file = File('enums/%s.hh' % name)
289 env.Command(hh_file, Value(name), generate.createEnumParam)
290 env.Depends(hh_file, depends + extra_deps)
292 # Build the big monolithic swigged params module (wraps all SimObject
293 # param structs and enum structs)
294 params_file = File('params/params.i')
295 names = sort_list(generate.sim_objects.keys())
296 env.Command(params_file, [ Value(v) for v in names ],
297 generate.buildParams)
298 env.Depends(params_file, params_hh_files + depends)
299 SwigSource('m5.objects', params_file)
301 # Build all swig modules
303 for source,package in swig_sources:
304 filename = str(source)
305 assert filename.endswith('.i')
307 base = '.'.join(filename.split('.')[:-1])
308 module = basename(base)
309 cc_file = base + '_wrap.cc'
310 py_file = base + '.py'
312 env.Command([cc_file, py_file], source,
313 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
314 '-o ${TARGETS[0]} $SOURCES')
315 env.Depends(py_file, source)
316 env.Depends(cc_file, source)
318 swig_modules.append(Value(module))
320 PySource(package, py_file)
322 # Generate the main swig init file
323 env.Command('swig/init.cc', swig_modules, generate.makeSwigInit)
324 Source('swig/init.cc')
326 # Generate traceflags.py
327 flags = [ Value(f) for f in trace_flags ]
328 env.Command('base/traceflags.py', flags, generate.traceFlagsPy)
329 PySource('m5', 'base/traceflags.py')
331 env.Command('base/traceflags.hh', flags, generate.traceFlagsHH)
332 env.Command('base/traceflags.cc', flags, generate.traceFlagsCC)
333 Source('base/traceflags.cc')
335 # Generate program_info.cc
336 env.Command('base/program_info.cc',
337 Value(str(SCons.Node.FS.default_fs.SConstruct_dir)), generate.programInfo)
342 for source in py_sources:
343 env.Command(source.compiled, source.source, generate.compilePyFile)
344 py_compiled.append(source.compiled)
346 # make the zipfile depend on the archive name so that the archive
347 # is rebuilt if the name changes
348 py_zip_depends.append(Value(source.arcname))
350 # Add the zip file target to the environment.
351 m5zip = File('m5py.zip')
352 env.Command(m5zip, py_compiled, generate.buildPyZip)
353 env.Depends(m5zip, py_zip_depends)
355 ########################################################################
357 # Define binaries. Each different build type (debug, opt, etc.) gets
358 # a slightly different build environment.
361 # List of constructed environments to pass back to SConstruct
364 # This function adds the specified sources to the given build
365 # environment, and returns a list of all the corresponding SCons
366 # Object nodes (including an extra one for date.cc). We explicitly
367 # add the Object nodes so we can set up special dependencies for
369 def make_objs(sources, env):
370 objs = [env.Object(s) for s in sources]
372 # make date.cc depend on all other objects so it always gets
373 # recompiled whenever anything else does
374 date_obj = env.Object('base/date.cc')
376 # Make the generation of program_info.cc dependend on all
377 # the other cc files and the compiling of program_info.cc
378 # dependent on all the objects but program_info.o
379 pinfo_obj = env.Object('base/program_info.cc')
380 env.Depends('base/program_info.cc', sources)
381 env.Depends(date_obj, objs)
382 env.Depends(pinfo_obj, objs)
383 objs.extend([date_obj,pinfo_obj])
386 # Function to create a new build environment as clone of current
387 # environment 'env' with modified object suffix and optional stripped
388 # binary. Additional keyword arguments are appended to corresponding
389 # build environment vars.
390 def makeEnv(label, objsfx, strip = False, **kwargs):
391 newEnv = env.Copy(OBJSUFFIX=objsfx)
393 newEnv.Append(**kwargs)
394 exe = 'm5.' + label # final executable
395 bin = exe + '.bin' # executable w/o appended Python zip archive
396 newEnv.Program(bin, make_objs(cc_sources, newEnv))
398 stripped_bin = bin + '.stripped'
399 if sys.platform == 'sunos5':
400 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
402 cmd = 'strip $SOURCE -o $TARGET'
403 newEnv.Command(stripped_bin, bin, cmd)
405 targets = newEnv.Concat(exe, [bin, 'm5py.zip'])
406 newEnv.M5Binary = targets[0]
407 envList.append(newEnv)
412 if sys.platform == 'sunos5':
413 ccflags['debug'] = '-gstabs+'
415 ccflags['debug'] = '-ggdb3'
416 ccflags['opt'] = '-g -O3'
417 ccflags['fast'] = '-O3'
418 ccflags['prof'] = '-O3 -g -pg'
420 ccflags['debug'] = '-g0'
421 ccflags['opt'] = '-g -O'
422 ccflags['fast'] = '-fast'
423 ccflags['prof'] = '-fast -g -pg'
425 ccflags['debug'] = '-g -O0'
426 ccflags['opt'] = '-g -O'
427 ccflags['fast'] = '-fast'
428 ccflags['prof'] = '-fast -g -pg'
430 print 'Unknown compiler, please fix compiler options'
433 makeEnv('debug', '.do',
434 CCFLAGS = Split(ccflags['debug']),
435 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
439 CCFLAGS = Split(ccflags['opt']),
440 CPPDEFINES = ['TRACING_ON=1'])
443 makeEnv('fast', '.fo', strip = True,
444 CCFLAGS = Split(ccflags['fast']),
445 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
448 makeEnv('prof', '.po',
449 CCFLAGS = Split(ccflags['prof']),
450 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],