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
36 from os.path import join as joinpath
37 from os.path import exists
38 from os.path import isdir
39 from os.path import isfile
43 # This file defines how to build a particular configuration of M5
44 # based on variable settings in the 'env' build environment.
48 # Children need to see the environment
52 """return a sorted copy of '_list'"""
53 if isinstance(_list, list):
60 class PySourceFile(object):
61 def __init__(self, package, source):
62 filename = str(source)
63 pyname = basename(filename)
64 assert pyname.endswith('.py')
66 path = package.split('.')
68 if name != '__init__':
70 modpath = '.'.join(modpath)
72 arcpath = package.split('.') + [ pyname + 'c' ]
73 arcname = joinpath(*arcpath)
77 self.srcpath = source.srcnode().abspath
78 self.package = package
79 self.modpath = modpath
80 self.arcname = arcname
81 self.filename = filename
82 self.compiled = File(filename + 'c')
84 ########################################################################
85 # Code for adding source files of various types
89 '''Add a C/C++ source file to the build'''
90 if not isinstance(source, SCons.Node.FS.File):
93 cc_sources.append(source)
96 def PySource(package, source):
97 '''Add a python source file to the named package'''
98 if not isinstance(source, SCons.Node.FS.File):
101 source = PySourceFile(package, source)
102 py_sources.append(source)
104 sim_objects_fixed = False
105 sim_object_modfiles = set()
106 def SimObject(source):
107 '''Add a SimObject python file as a python source object and add
108 it to a list of sim object modules'''
110 if sim_objects_fixed:
111 raise AttributeError, "Too late to call SimObject now."
113 if not isinstance(source, SCons.Node.FS.File):
114 source = File(source)
116 PySource('m5.objects', source)
117 modfile = basename(str(source))
118 assert modfile.endswith('.py')
119 modname = modfile[:-3]
120 sim_object_modfiles.add(modname)
123 def SwigSource(package, source):
124 '''Add a swig file to build'''
125 if not isinstance(source, SCons.Node.FS.File):
126 source = File(source)
128 swig_sources.append(val)
130 # Children should have access
136 ########################################################################
138 # Set some compiler variables
141 # Include file paths are rooted in this directory. SCons will
142 # automatically expand '.' to refer to both the source directory and
143 # the corresponding build directory to pick up generated include
145 env.Append(CPPPATH=Dir('.'))
147 # Add a flag defining what THE_ISA should be for all compilation
148 env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
150 ########################################################################
152 # Walk the tree and execute all SConscripts
154 srcdir = env['SRCDIR']
155 for root, dirs, files in os.walk(srcdir, topdown=True):
157 # we don't want to recurse back into this SConscript
160 if 'SConscript' in files:
161 # strip off the srcdir part since scons will try to find the
162 # script in the build directory
163 base = root[len(srcdir) + 1:]
164 SConscript(joinpath(base, 'SConscript'))
166 for extra in env['EXTRAS'].split(':'):
167 extra = os.path.expanduser(extra)
168 env.Append(CPPPATH=[Dir(extra)])
169 for root, dirs, files in os.walk(extra, topdown=True):
170 if 'SConscript' in files:
171 subdir = root[len(os.path.dirname(extra))+1:]
172 build_dir = joinpath(env['BUILDDIR'], subdir)
173 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
175 for opt in env.ExportOptions:
178 ########################################################################
180 # Prevent any SimObjects from being added after this point, they
181 # should all have been added in the SConscripts above
183 sim_objects_fixed = True
185 ########################################################################
187 # Manually turn python/generate.py into a python module and import it
189 generate_file = File('python/generate.py')
190 generate_module = imp.new_module('generate')
191 sys.modules['generate'] = generate_module
192 exec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__
194 ########################################################################
198 from generate import Generate
199 optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
200 generate = Generate(py_sources, sim_object_modfiles, optionDict)
203 ########################################################################
205 # calculate extra dependencies
207 module_depends = ["m5", "m5.SimObject", "m5.params"]
208 module_depends = [ File(generate.py_modules[dep]) for dep in module_depends ]
209 file_depends = [ generate_file ]
210 depends = module_depends + file_depends
212 ########################################################################
214 # Commands for the basic automatically generated python files
217 # Generate a file with all of the compile options in it
218 env.Command('python/m5/defines.py', Value(optionDict),
219 generate.makeDefinesPyFile)
220 PySource('m5', 'python/m5/defines.py')
222 # Generate a file that wraps the basic top level files
223 env.Command('python/m5/info.py',
224 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
225 generate.makeInfoPyFile)
226 PySource('m5', 'python/m5/info.py')
228 # Generate an __init__.py file for the objects package
229 env.Command('python/m5/objects/__init__.py',
230 [ Value(o) for o in sort_list(sim_object_modfiles) ],
231 generate.makeObjectsInitFile)
232 PySource('m5.objects', 'python/m5/objects/__init__.py')
234 ########################################################################
236 # Create all of the SimObject param headers and enum headers
239 # Generate all of the SimObject param struct header files
241 for name,simobj in generate.sim_objects.iteritems():
242 extra_deps = [ File(generate.py_modules[simobj.__module__]) ]
244 hh_file = File('params/%s.hh' % name)
245 params_hh_files.append(hh_file)
246 env.Command(hh_file, Value(name), generate.createSimObjectParam)
247 env.Depends(hh_file, depends + extra_deps)
249 # Generate any parameter header files needed
250 for name,param in generate.params.iteritems():
251 if isinstance(param, m5.params.VectorParamDesc):
256 i_file = File('params/%s_%s.i' % (name, ext))
257 env.Command(i_file, Value(name), generate.createSwigParam)
258 env.Depends(i_file, depends)
260 # Generate all enum header files
261 for name,enum in generate.enums.iteritems():
262 extra_deps = [ File(generate.py_modules[enum.__module__]) ]
264 cc_file = File('enums/%s.cc' % name)
265 env.Command(cc_file, Value(name), generate.createEnumStrings)
266 env.Depends(cc_file, depends + extra_deps)
269 hh_file = File('enums/%s.hh' % name)
270 env.Command(hh_file, Value(name), generate.createEnumParam)
271 env.Depends(hh_file, depends + extra_deps)
273 # Build the big monolithic swigged params module (wraps all SimObject
274 # param structs and enum structs)
275 params_file = File('params/params.i')
276 names = sort_list(generate.sim_objects.keys())
277 env.Command(params_file, [ Value(v) for v in names ],
278 generate.buildParams)
279 env.Depends(params_file, params_hh_files + depends)
280 SwigSource('m5.objects', params_file)
282 # Build all swig modules
284 for source,package in swig_sources:
285 filename = str(source)
286 assert filename.endswith('.i')
288 base = '.'.join(filename.split('.')[:-1])
289 module = basename(base)
290 cc_file = base + '_wrap.cc'
291 py_file = base + '.py'
293 env.Command([cc_file, py_file], source,
294 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
295 '-o ${TARGETS[0]} $SOURCES')
296 env.Depends(py_file, source)
297 env.Depends(cc_file, source)
299 swig_modules.append(Value(module))
301 PySource(package, py_file)
303 # Generate the main swig init file
304 env.Command('swig/init.cc', swig_modules, generate.makeSwigInit)
305 Source('swig/init.cc')
310 for source in py_sources:
311 env.Command(source.compiled, source.source, generate.compilePyFile)
312 py_compiled.append(source.compiled)
314 # make the zipfile depend on the archive name so that the archive
315 # is rebuilt if the name changes
316 py_zip_depends.append(Value(source.arcname))
318 # Add the zip file target to the environment.
319 m5zip = File('m5py.zip')
320 env.Command(m5zip, py_compiled, generate.buildPyZip)
321 env.Depends(m5zip, py_zip_depends)
323 ########################################################################
325 # Define binaries. Each different build type (debug, opt, etc.) gets
326 # a slightly different build environment.
329 # List of constructed environments to pass back to SConstruct
332 # This function adds the specified sources to the given build
333 # environment, and returns a list of all the corresponding SCons
334 # Object nodes (including an extra one for date.cc). We explicitly
335 # add the Object nodes so we can set up special dependencies for
337 def make_objs(sources, env):
338 objs = [env.Object(s) for s in sources]
339 # make date.cc depend on all other objects so it always gets
340 # recompiled whenever anything else does
341 date_obj = env.Object('base/date.cc')
342 env.Depends(date_obj, objs)
343 objs.append(date_obj)
346 # Function to create a new build environment as clone of current
347 # environment 'env' with modified object suffix and optional stripped
348 # binary. Additional keyword arguments are appended to corresponding
349 # build environment vars.
350 def makeEnv(label, objsfx, strip = False, **kwargs):
351 newEnv = env.Copy(OBJSUFFIX=objsfx)
353 newEnv.Append(**kwargs)
354 exe = 'm5.' + label # final executable
355 bin = exe + '.bin' # executable w/o appended Python zip archive
356 newEnv.Program(bin, make_objs(cc_sources, newEnv))
358 stripped_bin = bin + '.stripped'
359 if sys.platform == 'sunos5':
360 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
362 cmd = 'strip $SOURCE -o $TARGET'
363 newEnv.Command(stripped_bin, bin, cmd)
365 targets = newEnv.Concat(exe, [bin, 'm5py.zip'])
366 newEnv.M5Binary = targets[0]
367 envList.append(newEnv)
372 if sys.platform == 'sunos5':
373 ccflags['debug'] = '-gstabs+'
375 ccflags['debug'] = '-ggdb3'
376 ccflags['opt'] = '-g -O3'
377 ccflags['fast'] = '-O3'
378 ccflags['prof'] = '-O3 -g -pg'
380 ccflags['debug'] = '-g0'
381 ccflags['opt'] = '-g -O'
382 ccflags['fast'] = '-fast'
383 ccflags['prof'] = '-fast -g -pg'
385 ccflags['debug'] = '-g -O0'
386 ccflags['opt'] = '-g -O'
387 ccflags['fast'] = '-fast'
388 ccflags['prof'] = '-fast -g -pg'
390 print 'Unknown compiler, please fix compiler options'
393 makeEnv('debug', '.do',
394 CCFLAGS = Split(ccflags['debug']),
395 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
399 CCFLAGS = Split(ccflags['opt']),
400 CPPDEFINES = ['TRACING_ON=1'])
403 makeEnv('fast', '.fo', strip = True,
404 CCFLAGS = Split(ccflags['fast']),
405 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
408 makeEnv('prof', '.po',
409 CCFLAGS = Split(ccflags['prof']),
410 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],