Add a new SCons option called EXTRAS that allows you to include stuff in
[gem5.git] / src / SConscript
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
31 import imp
32 import os
33 import sys
34
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
40
41 import SCons
42
43 # This file defines how to build a particular configuration of M5
44 # based on variable settings in the 'env' build environment.
45
46 Import('*')
47
48 # Children need to see the environment
49 Export('env')
50
51 def sort_list(_list):
52 """return a sorted copy of '_list'"""
53 if isinstance(_list, list):
54 _list = _list[:]
55 else:
56 _list = list(_list)
57 _list.sort()
58 return _list
59
60 class PySourceFile(object):
61 def __init__(self, package, source):
62 filename = str(source)
63 pyname = basename(filename)
64 assert pyname.endswith('.py')
65 name = pyname[:-3]
66 path = package.split('.')
67 modpath = path
68 if name != '__init__':
69 modpath += [name]
70 modpath = '.'.join(modpath)
71
72 arcpath = package.split('.') + [ pyname + 'c' ]
73 arcname = joinpath(*arcpath)
74
75 self.source = source
76 self.pyname = pyname
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')
83
84 ########################################################################
85 # Code for adding source files of various types
86 #
87 cc_sources = []
88 def Source(source):
89 '''Add a C/C++ source file to the build'''
90 if not isinstance(source, SCons.Node.FS.File):
91 source = File(source)
92
93 cc_sources.append(source)
94
95 py_sources = []
96 def PySource(package, source):
97 '''Add a python source file to the named package'''
98 if not isinstance(source, SCons.Node.FS.File):
99 source = File(source)
100
101 source = PySourceFile(package, source)
102 py_sources.append(source)
103
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'''
109
110 if sim_objects_fixed:
111 raise AttributeError, "Too late to call SimObject now."
112
113 if not isinstance(source, SCons.Node.FS.File):
114 source = File(source)
115
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)
121
122 swig_sources = []
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)
127 val = source,package
128 swig_sources.append(val)
129
130 # Children should have access
131 Export('Source')
132 Export('PySource')
133 Export('SimObject')
134 Export('SwigSource')
135
136 ########################################################################
137 #
138 # Set some compiler variables
139 #
140
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
144 # files.
145 env.Append(CPPPATH=Dir('.'))
146
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())])
149
150 ########################################################################
151 #
152 # Walk the tree and execute all SConscripts
153 #
154 srcdir = env['SRCDIR']
155 for root, dirs, files in os.walk(srcdir, topdown=True):
156 if root == srcdir:
157 # we don't want to recurse back into this SConscript
158 continue
159
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'))
165
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)
174
175 for opt in env.ExportOptions:
176 env.ConfigFile(opt)
177
178 ########################################################################
179 #
180 # Prevent any SimObjects from being added after this point, they
181 # should all have been added in the SConscripts above
182 #
183 sim_objects_fixed = True
184
185 ########################################################################
186 #
187 # Manually turn python/generate.py into a python module and import it
188 #
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__
193
194 ########################################################################
195 #
196 # build a generate
197 #
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)
201 m5 = generate.m5
202
203 ########################################################################
204 #
205 # calculate extra dependencies
206 #
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
211
212 ########################################################################
213 #
214 # Commands for the basic automatically generated python files
215 #
216
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')
221
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')
227
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')
233
234 ########################################################################
235 #
236 # Create all of the SimObject param headers and enum headers
237 #
238
239 # Generate all of the SimObject param struct header files
240 params_hh_files = []
241 for name,simobj in generate.sim_objects.iteritems():
242 extra_deps = [ File(generate.py_modules[simobj.__module__]) ]
243
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)
248
249 # Generate any parameter header files needed
250 for name,param in generate.params.iteritems():
251 if isinstance(param, m5.params.VectorParamDesc):
252 ext = 'vptype'
253 else:
254 ext = 'ptype'
255
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)
259
260 # Generate all enum header files
261 for name,enum in generate.enums.iteritems():
262 extra_deps = [ File(generate.py_modules[enum.__module__]) ]
263
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)
267 Source(cc_file)
268
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)
272
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)
281
282 # Build all swig modules
283 swig_modules = []
284 for source,package in swig_sources:
285 filename = str(source)
286 assert filename.endswith('.i')
287
288 base = '.'.join(filename.split('.')[:-1])
289 module = basename(base)
290 cc_file = base + '_wrap.cc'
291 py_file = base + '.py'
292
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)
298
299 swig_modules.append(Value(module))
300 Source(cc_file)
301 PySource(package, py_file)
302
303 # Generate the main swig init file
304 env.Command('swig/init.cc', swig_modules, generate.makeSwigInit)
305 Source('swig/init.cc')
306
307 # Build the zip file
308 py_compiled = []
309 py_zip_depends = []
310 for source in py_sources:
311 env.Command(source.compiled, source.source, generate.compilePyFile)
312 py_compiled.append(source.compiled)
313
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))
317
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)
322
323 ########################################################################
324 #
325 # Define binaries. Each different build type (debug, opt, etc.) gets
326 # a slightly different build environment.
327 #
328
329 # List of constructed environments to pass back to SConstruct
330 envList = []
331
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
336 # date.cc.
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)
344 return objs
345
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)
352 newEnv.Label = label
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))
357 if strip:
358 stripped_bin = bin + '.stripped'
359 if sys.platform == 'sunos5':
360 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
361 else:
362 cmd = 'strip $SOURCE -o $TARGET'
363 newEnv.Command(stripped_bin, bin, cmd)
364 bin = stripped_bin
365 targets = newEnv.Concat(exe, [bin, 'm5py.zip'])
366 newEnv.M5Binary = targets[0]
367 envList.append(newEnv)
368
369 # Debug binary
370 ccflags = {}
371 if env['GCC']:
372 if sys.platform == 'sunos5':
373 ccflags['debug'] = '-gstabs+'
374 else:
375 ccflags['debug'] = '-ggdb3'
376 ccflags['opt'] = '-g -O3'
377 ccflags['fast'] = '-O3'
378 ccflags['prof'] = '-O3 -g -pg'
379 elif env['SUNCC']:
380 ccflags['debug'] = '-g0'
381 ccflags['opt'] = '-g -O'
382 ccflags['fast'] = '-fast'
383 ccflags['prof'] = '-fast -g -pg'
384 elif env['ICC']:
385 ccflags['debug'] = '-g -O0'
386 ccflags['opt'] = '-g -O'
387 ccflags['fast'] = '-fast'
388 ccflags['prof'] = '-fast -g -pg'
389 else:
390 print 'Unknown compiler, please fix compiler options'
391 Exit(1)
392
393 makeEnv('debug', '.do',
394 CCFLAGS = Split(ccflags['debug']),
395 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
396
397 # Optimized binary
398 makeEnv('opt', '.o',
399 CCFLAGS = Split(ccflags['opt']),
400 CPPDEFINES = ['TRACING_ON=1'])
401
402 # "Fast" binary
403 makeEnv('fast', '.fo', strip = True,
404 CCFLAGS = Split(ccflags['fast']),
405 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
406
407 # Profiled binary
408 makeEnv('prof', '.po',
409 CCFLAGS = Split(ccflags['prof']),
410 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
411 LINKFLAGS = '-pg')
412
413 Return('envList')