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