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