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