SConscript revision 5299
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# Trace Flags 139# 140all_flags = {} 141trace_flags = [] 142def 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 149def 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 165Export('TraceFlag') 166Export('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. 177env.Append(CPPPATH=Dir('.')) 178 179# Add a flag defining what THE_ISA should be for all compilation 180env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) 181 182######################################################################## 183# 184# Walk the tree and execute all SConscripts 185# 186srcdir = env['SRCDIR'] 187for 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 198extra_string = env['EXTRAS'] 199if 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 210for 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# 218sim_objects_fixed = True 219 220######################################################################## 221# 222# Manually turn python/generate.py into a python module and import it 223# 224generate_file = File('python/generate.py') 225generate_module = imp.new_module('generate') 226sys.modules['generate'] = generate_module 227exec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__ 228 229######################################################################## 230# 231# build a generate 232# 233from generate import Generate 234optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) 235generate = Generate(py_sources, sim_object_modfiles, optionDict) 236m5 = generate.m5 237 238######################################################################## 239# 240# calculate extra dependencies 241# 242module_depends = ["m5", "m5.SimObject", "m5.params"] 243module_depends = [ File(generate.py_modules[dep]) for dep in module_depends ] 244file_depends = [ generate_file ] 245depends = 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 253env.Command('python/m5/defines.py', Value(optionDict), 254 generate.makeDefinesPyFile) 255PySource('m5', 'python/m5/defines.py') 256 257# Generate a file that wraps the basic top level files 258env.Command('python/m5/info.py', 259 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], 260 generate.makeInfoPyFile) 261PySource('m5', 'python/m5/info.py') 262 263# Generate an __init__.py file for the objects package 264env.Command('python/m5/objects/__init__.py', 265 [ Value(o) for o in sort_list(sim_object_modfiles) ], 266 generate.makeObjectsInitFile) 267PySource('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 275params_hh_files = [] 276for 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 285for 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 296for 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) 310params_file = File('params/params.i') 311names = sort_list(generate.sim_objects.keys()) 312env.Command(params_file, [ Value(v) for v in names ], 313 generate.buildParams) 314env.Depends(params_file, params_hh_files + depends) 315SwigSource('m5.objects', params_file) 316 317# Build all swig modules 318swig_modules = [] 319for 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 339env.Command('swig/init.cc', swig_modules, generate.makeSwigInit) 340Source('swig/init.cc') 341 342# Generate traceflags.py 343flags = [ Value(f) for f in trace_flags ] 344env.Command('base/traceflags.py', flags, generate.traceFlagsPy) 345PySource('m5', 'base/traceflags.py') 346 347env.Command('base/traceflags.hh', flags, generate.traceFlagsHH) 348env.Command('base/traceflags.cc', flags, generate.traceFlagsCC) 349Source('base/traceflags.cc') 350 351# Build the zip file 352py_compiled = [] 353py_zip_depends = [] 354for 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. 363m5zip = File('m5py.zip') 364env.Command(m5zip, py_compiled, generate.buildPyZip) 365env.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 374envList = [] 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. 381def 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. 394def 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 414ccflags = {} 415if 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' 423elif env['SUNCC']: 424 ccflags['debug'] = '-g0' 425 ccflags['opt'] = '-g -O' 426 ccflags['fast'] = '-fast' 427 ccflags['prof'] = '-fast -g -pg' 428elif env['ICC']: 429 ccflags['debug'] = '-g -O0' 430 ccflags['opt'] = '-g -O' 431 ccflags['fast'] = '-fast' 432 ccflags['prof'] = '-fast -g -pg' 433else: 434 print 'Unknown compiler, please fix compiler options' 435 Exit(1) 436 437makeEnv('debug', '.do', 438 CCFLAGS = Split(ccflags['debug']), 439 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 440 441# Optimized binary 442makeEnv('opt', '.o', 443 CCFLAGS = Split(ccflags['opt']), 444 CPPDEFINES = ['TRACING_ON=1']) 445 446# "Fast" binary 447makeEnv('fast', '.fo', strip = True, 448 CCFLAGS = Split(ccflags['fast']), 449 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 450 451# Profiled binary 452makeEnv('prof', '.po', 453 CCFLAGS = Split(ccflags['prof']), 454 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 455 LINKFLAGS = '-pg') 456 457Return('envList') 458