SConscript revision 4762:c94e103c83ad
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 31import imp 32import os 33import sys 34 35from os.path import basename 36from os.path import join as joinpath 37from os.path import exists 38from os.path import isdir 39from os.path import isfile 40 41import 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 46Import('*') 47 48# Children need to see the environment 49Export('env') 50 51def 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 60class 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# 87cc_sources = [] 88def 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 95py_sources = [] 96def 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 104sim_objects_fixed = False 105sim_object_modfiles = set() 106def 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 122swig_sources = [] 123def 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 131Export('Source') 132Export('PySource') 133Export('SimObject') 134Export('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. 145env.Append(CPPPATH=Dir('.')) 146 147# Add a flag defining what THE_ISA should be for all compilation 148env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) 149 150######################################################################## 151# 152# Walk the tree and execute all SConscripts 153# 154scripts = [] 155srcdir = env['SRCDIR'] 156for 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 167for 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# 175sim_objects_fixed = True 176 177######################################################################## 178# 179# Manually turn python/generate.py into a python module and import it 180# 181generate_file = File('python/generate.py') 182generate_module = imp.new_module('generate') 183sys.modules['generate'] = generate_module 184exec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__ 185 186######################################################################## 187# 188# build a generate 189# 190from generate import Generate 191optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) 192generate = Generate(py_sources, sim_object_modfiles, optionDict) 193m5 = generate.m5 194 195######################################################################## 196# 197# calculate extra dependencies 198# 199module_depends = ["m5", "m5.SimObject", "m5.params"] 200module_depends = [ File(generate.py_modules[dep]) for dep in module_depends ] 201file_depends = [ generate_file ] 202depends = 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 210env.Command('python/m5/defines.py', Value(optionDict), 211 generate.makeDefinesPyFile) 212PySource('m5', 'python/m5/defines.py') 213 214# Generate a file that wraps the basic top level files 215env.Command('python/m5/info.py', 216 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], 217 generate.makeInfoPyFile) 218PySource('m5', 'python/m5/info.py') 219 220# Generate an __init__.py file for the objects package 221env.Command('python/m5/objects/__init__.py', 222 [ Value(o) for o in sort_list(sim_object_modfiles) ], 223 generate.makeObjectsInitFile) 224PySource('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 232params_hh_files = [] 233for 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 242for 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 253for 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) 267params_file = File('params/params.i') 268names = sort_list(generate.sim_objects.keys()) 269env.Command(params_file, [ Value(v) for v in names ], 270 generate.buildParams) 271env.Depends(params_file, params_hh_files + depends) 272SwigSource('m5.objects', params_file) 273 274# Build all swig modules 275swig_modules = [] 276for 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 296env.Command('swig/init.cc', swig_modules, generate.makeSwigInit) 297Source('swig/init.cc') 298 299# Build the zip file 300py_compiled = [] 301py_zip_depends = [] 302for 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. 311m5zip = File('m5py.zip') 312env.Command(m5zip, py_compiled, generate.buildPyZip) 313env.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 322envList = [] 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. 329def 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. 342def 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 362ccflags = {} 363if 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' 371elif env['SUNCC']: 372 ccflags['debug'] = '-g0' 373 ccflags['opt'] = '-g -O' 374 ccflags['fast'] = '-fast' 375 ccflags['prof'] = '-fast -g -pg' 376elif env['ICC']: 377 ccflags['debug'] = '-g -O0' 378 ccflags['opt'] = '-g -O' 379 ccflags['fast'] = '-fast' 380 ccflags['prof'] = '-fast -g -pg' 381else: 382 print 'Unknown compiler, please fix compiler options' 383 Exit(1) 384 385makeEnv('debug', '.do', 386 CCFLAGS = Split(ccflags['debug']), 387 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 388 389# Optimized binary 390makeEnv('opt', '.o', 391 CCFLAGS = Split(ccflags['opt']), 392 CPPDEFINES = ['TRACING_ON=1']) 393 394# "Fast" binary 395makeEnv('fast', '.fo', strip = True, 396 CCFLAGS = Split(ccflags['fast']), 397 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 398 399# Profiled binary 400makeEnv('prof', '.po', 401 CCFLAGS = Split(ccflags['prof']), 402 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 403 LINKFLAGS = '-pg') 404 405Return('envList') 406