Merge with head
[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 extra_string = env['EXTRAS']
167 if extra_string and extra_string != '' and not extra_string.isspace():
168 for extra in extra_string.split(':'):
169 extra = os.path.expanduser(extra)
170 extra = os.path.normpath(extra)
171 env.Append(CPPPATH=[Dir(extra)])
172 for root, dirs, files in os.walk(extra, topdown=True):
173 if 'SConscript' in files:
174 subdir = root[len(os.path.dirname(extra))+1:]
175 build_dir = joinpath(env['BUILDDIR'], subdir)
176 SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
177
178 for opt in env.ExportOptions:
179 env.ConfigFile(opt)
180
181 ########################################################################
182 #
183 # Prevent any SimObjects from being added after this point, they
184 # should all have been added in the SConscripts above
185 #
186 sim_objects_fixed = True
187
188 ########################################################################
189 #
190 # Manually turn python/generate.py into a python module and import it
191 #
192 generate_file = File('python/generate.py')
193 generate_module = imp.new_module('generate')
194 sys.modules['generate'] = generate_module
195 exec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__
196
197 ########################################################################
198 #
199 # build a generate
200 #
201 from generate import Generate
202 optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
203 generate = Generate(py_sources, sim_object_modfiles, optionDict)
204 m5 = generate.m5
205
206 ########################################################################
207 #
208 # calculate extra dependencies
209 #
210 module_depends = ["m5", "m5.SimObject", "m5.params"]
211 module_depends = [ File(generate.py_modules[dep]) for dep in module_depends ]
212 file_depends = [ generate_file ]
213 depends = module_depends + file_depends
214
215 ########################################################################
216 #
217 # Commands for the basic automatically generated python files
218 #
219
220 # Generate a file with all of the compile options in it
221 env.Command('python/m5/defines.py', Value(optionDict),
222 generate.makeDefinesPyFile)
223 PySource('m5', 'python/m5/defines.py')
224
225 # Generate a file that wraps the basic top level files
226 env.Command('python/m5/info.py',
227 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
228 generate.makeInfoPyFile)
229 PySource('m5', 'python/m5/info.py')
230
231 # Generate an __init__.py file for the objects package
232 env.Command('python/m5/objects/__init__.py',
233 [ Value(o) for o in sort_list(sim_object_modfiles) ],
234 generate.makeObjectsInitFile)
235 PySource('m5.objects', 'python/m5/objects/__init__.py')
236
237 ########################################################################
238 #
239 # Create all of the SimObject param headers and enum headers
240 #
241
242 # Generate all of the SimObject param struct header files
243 params_hh_files = []
244 for name,simobj in generate.sim_objects.iteritems():
245 extra_deps = [ File(generate.py_modules[simobj.__module__]) ]
246
247 hh_file = File('params/%s.hh' % name)
248 params_hh_files.append(hh_file)
249 env.Command(hh_file, Value(name), generate.createSimObjectParam)
250 env.Depends(hh_file, depends + extra_deps)
251
252 # Generate any parameter header files needed
253 for name,param in generate.params.iteritems():
254 if isinstance(param, m5.params.VectorParamDesc):
255 ext = 'vptype'
256 else:
257 ext = 'ptype'
258
259 i_file = File('params/%s_%s.i' % (name, ext))
260 env.Command(i_file, Value(name), generate.createSwigParam)
261 env.Depends(i_file, depends)
262
263 # Generate all enum header files
264 for name,enum in generate.enums.iteritems():
265 extra_deps = [ File(generate.py_modules[enum.__module__]) ]
266
267 cc_file = File('enums/%s.cc' % name)
268 env.Command(cc_file, Value(name), generate.createEnumStrings)
269 env.Depends(cc_file, depends + extra_deps)
270 Source(cc_file)
271
272 hh_file = File('enums/%s.hh' % name)
273 env.Command(hh_file, Value(name), generate.createEnumParam)
274 env.Depends(hh_file, depends + extra_deps)
275
276 # Build the big monolithic swigged params module (wraps all SimObject
277 # param structs and enum structs)
278 params_file = File('params/params.i')
279 names = sort_list(generate.sim_objects.keys())
280 env.Command(params_file, [ Value(v) for v in names ],
281 generate.buildParams)
282 env.Depends(params_file, params_hh_files + depends)
283 SwigSource('m5.objects', params_file)
284
285 # Build all swig modules
286 swig_modules = []
287 for source,package in swig_sources:
288 filename = str(source)
289 assert filename.endswith('.i')
290
291 base = '.'.join(filename.split('.')[:-1])
292 module = basename(base)
293 cc_file = base + '_wrap.cc'
294 py_file = base + '.py'
295
296 env.Command([cc_file, py_file], source,
297 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
298 '-o ${TARGETS[0]} $SOURCES')
299 env.Depends(py_file, source)
300 env.Depends(cc_file, source)
301
302 swig_modules.append(Value(module))
303 Source(cc_file)
304 PySource(package, py_file)
305
306 # Generate the main swig init file
307 env.Command('swig/init.cc', swig_modules, generate.makeSwigInit)
308 Source('swig/init.cc')
309
310 # Build the zip file
311 py_compiled = []
312 py_zip_depends = []
313 for source in py_sources:
314 env.Command(source.compiled, source.source, generate.compilePyFile)
315 py_compiled.append(source.compiled)
316
317 # make the zipfile depend on the archive name so that the archive
318 # is rebuilt if the name changes
319 py_zip_depends.append(Value(source.arcname))
320
321 # Add the zip file target to the environment.
322 m5zip = File('m5py.zip')
323 env.Command(m5zip, py_compiled, generate.buildPyZip)
324 env.Depends(m5zip, py_zip_depends)
325
326 ########################################################################
327 #
328 # Define binaries. Each different build type (debug, opt, etc.) gets
329 # a slightly different build environment.
330 #
331
332 # List of constructed environments to pass back to SConstruct
333 envList = []
334
335 # This function adds the specified sources to the given build
336 # environment, and returns a list of all the corresponding SCons
337 # Object nodes (including an extra one for date.cc). We explicitly
338 # add the Object nodes so we can set up special dependencies for
339 # date.cc.
340 def make_objs(sources, env):
341 objs = [env.Object(s) for s in sources]
342 # make date.cc depend on all other objects so it always gets
343 # recompiled whenever anything else does
344 date_obj = env.Object('base/date.cc')
345 env.Depends(date_obj, objs)
346 objs.append(date_obj)
347 return objs
348
349 # Function to create a new build environment as clone of current
350 # environment 'env' with modified object suffix and optional stripped
351 # binary. Additional keyword arguments are appended to corresponding
352 # build environment vars.
353 def makeEnv(label, objsfx, strip = False, **kwargs):
354 newEnv = env.Copy(OBJSUFFIX=objsfx)
355 newEnv.Label = label
356 newEnv.Append(**kwargs)
357 exe = 'm5.' + label # final executable
358 bin = exe + '.bin' # executable w/o appended Python zip archive
359 newEnv.Program(bin, make_objs(cc_sources, newEnv))
360 if strip:
361 stripped_bin = bin + '.stripped'
362 if sys.platform == 'sunos5':
363 cmd = 'cp $SOURCE $TARGET; strip $TARGET'
364 else:
365 cmd = 'strip $SOURCE -o $TARGET'
366 newEnv.Command(stripped_bin, bin, cmd)
367 bin = stripped_bin
368 targets = newEnv.Concat(exe, [bin, 'm5py.zip'])
369 newEnv.M5Binary = targets[0]
370 envList.append(newEnv)
371
372 # Debug binary
373 ccflags = {}
374 if env['GCC']:
375 if sys.platform == 'sunos5':
376 ccflags['debug'] = '-gstabs+'
377 else:
378 ccflags['debug'] = '-ggdb3'
379 ccflags['opt'] = '-g -O3'
380 ccflags['fast'] = '-O3'
381 ccflags['prof'] = '-O3 -g -pg'
382 elif env['SUNCC']:
383 ccflags['debug'] = '-g0'
384 ccflags['opt'] = '-g -O'
385 ccflags['fast'] = '-fast'
386 ccflags['prof'] = '-fast -g -pg'
387 elif env['ICC']:
388 ccflags['debug'] = '-g -O0'
389 ccflags['opt'] = '-g -O'
390 ccflags['fast'] = '-fast'
391 ccflags['prof'] = '-fast -g -pg'
392 else:
393 print 'Unknown compiler, please fix compiler options'
394 Exit(1)
395
396 makeEnv('debug', '.do',
397 CCFLAGS = Split(ccflags['debug']),
398 CPPDEFINES = ['DEBUG', 'TRACING_ON=1'])
399
400 # Optimized binary
401 makeEnv('opt', '.o',
402 CCFLAGS = Split(ccflags['opt']),
403 CPPDEFINES = ['TRACING_ON=1'])
404
405 # "Fast" binary
406 makeEnv('fast', '.fo', strip = True,
407 CCFLAGS = Split(ccflags['fast']),
408 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'])
409
410 # Profiled binary
411 makeEnv('prof', '.po',
412 CCFLAGS = Split(ccflags['prof']),
413 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'],
414 LINKFLAGS = '-pg')
415
416 Return('envList')