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