SConscript revision 5068
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# 154srcdir = env['SRCDIR'] 155for 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 166extra_string = env['EXTRAS'] 167if 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 178for 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# 186sim_objects_fixed = True 187 188######################################################################## 189# 190# Manually turn python/generate.py into a python module and import it 191# 192generate_file = File('python/generate.py') 193generate_module = imp.new_module('generate') 194sys.modules['generate'] = generate_module 195exec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__ 196 197######################################################################## 198# 199# build a generate 200# 201from generate import Generate 202optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) 203generate = Generate(py_sources, sim_object_modfiles, optionDict) 204m5 = generate.m5 205 206######################################################################## 207# 208# calculate extra dependencies 209# 210module_depends = ["m5", "m5.SimObject", "m5.params"] 211module_depends = [ File(generate.py_modules[dep]) for dep in module_depends ] 212file_depends = [ generate_file ] 213depends = 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 221env.Command('python/m5/defines.py', Value(optionDict), 222 generate.makeDefinesPyFile) 223PySource('m5', 'python/m5/defines.py') 224 225# Generate a file that wraps the basic top level files 226env.Command('python/m5/info.py', 227 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], 228 generate.makeInfoPyFile) 229PySource('m5', 'python/m5/info.py') 230 231# Generate an __init__.py file for the objects package 232env.Command('python/m5/objects/__init__.py', 233 [ Value(o) for o in sort_list(sim_object_modfiles) ], 234 generate.makeObjectsInitFile) 235PySource('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 243params_hh_files = [] 244for 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 253for 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 264for 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) 278params_file = File('params/params.i') 279names = sort_list(generate.sim_objects.keys()) 280env.Command(params_file, [ Value(v) for v in names ], 281 generate.buildParams) 282env.Depends(params_file, params_hh_files + depends) 283SwigSource('m5.objects', params_file) 284 285# Build all swig modules 286swig_modules = [] 287for 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 307env.Command('swig/init.cc', swig_modules, generate.makeSwigInit) 308Source('swig/init.cc') 309 310# Build the zip file 311py_compiled = [] 312py_zip_depends = [] 313for 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. 322m5zip = File('m5py.zip') 323env.Command(m5zip, py_compiled, generate.buildPyZip) 324env.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 333envList = [] 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. 340def 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. 353def 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 373ccflags = {} 374if 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' 382elif env['SUNCC']: 383 ccflags['debug'] = '-g0' 384 ccflags['opt'] = '-g -O' 385 ccflags['fast'] = '-fast' 386 ccflags['prof'] = '-fast -g -pg' 387elif env['ICC']: 388 ccflags['debug'] = '-g -O0' 389 ccflags['opt'] = '-g -O' 390 ccflags['fast'] = '-fast' 391 ccflags['prof'] = '-fast -g -pg' 392else: 393 print 'Unknown compiler, please fix compiler options' 394 Exit(1) 395 396makeEnv('debug', '.do', 397 CCFLAGS = Split(ccflags['debug']), 398 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 399 400# Optimized binary 401makeEnv('opt', '.o', 402 CCFLAGS = Split(ccflags['opt']), 403 CPPDEFINES = ['TRACING_ON=1']) 404 405# "Fast" binary 406makeEnv('fast', '.fo', strip = True, 407 CCFLAGS = Split(ccflags['fast']), 408 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 409 410# Profiled binary 411makeEnv('prof', '.po', 412 CCFLAGS = Split(ccflags['prof']), 413 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 414 LINKFLAGS = '-pg') 415 416Return('envList') 417