SConscript revision 5456
19983Sstever@gmail.com# -*- mode:python -*- 29983Sstever@gmail.com 39983Sstever@gmail.com# Copyright (c) 2004-2005 The Regents of The University of Michigan 49983Sstever@gmail.com# All rights reserved. 59983Sstever@gmail.com# 69983Sstever@gmail.com# Redistribution and use in source and binary forms, with or without 79983Sstever@gmail.com# modification, are permitted provided that the following conditions are 89983Sstever@gmail.com# met: redistributions of source code must retain the above copyright 99983Sstever@gmail.com# notice, this list of conditions and the following disclaimer; 109983Sstever@gmail.com# redistributions in binary form must reproduce the above copyright 119983Sstever@gmail.com# notice, this list of conditions and the following disclaimer in the 129983Sstever@gmail.com# documentation and/or other materials provided with the distribution; 139983Sstever@gmail.com# neither the name of the copyright holders nor the names of its 149983Sstever@gmail.com# contributors may be used to endorse or promote products derived from 159983Sstever@gmail.com# this software without specific prior written permission. 169983Sstever@gmail.com# 179983Sstever@gmail.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 189983Sstever@gmail.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 199983Sstever@gmail.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 209983Sstever@gmail.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 219983Sstever@gmail.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 229983Sstever@gmail.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 239983Sstever@gmail.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 249983Sstever@gmail.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 259983Sstever@gmail.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 269983Sstever@gmail.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 279983Sstever@gmail.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 289983Sstever@gmail.com# 299983Sstever@gmail.com# Authors: Nathan Binkert 309983Sstever@gmail.com 319983Sstever@gmail.comimport imp 329983Sstever@gmail.comimport os 339983Sstever@gmail.comimport sys 349983Sstever@gmail.com 359983Sstever@gmail.comfrom os.path import basename, exists, isdir, isfile, join as joinpath 369983Sstever@gmail.com 379983Sstever@gmail.comimport SCons 389983Sstever@gmail.com 399983Sstever@gmail.com# This file defines how to build a particular configuration of M5 409983Sstever@gmail.com# based on variable settings in the 'env' build environment. 419983Sstever@gmail.com 429983Sstever@gmail.comImport('*') 439983Sstever@gmail.com 449983Sstever@gmail.com# Children need to see the environment 459983Sstever@gmail.comExport('env') 469983Sstever@gmail.com 479983Sstever@gmail.comdef sort_list(_list): 489983Sstever@gmail.com """return a sorted copy of '_list'""" 499983Sstever@gmail.com if isinstance(_list, list): 509983Sstever@gmail.com _list = _list[:] 519983Sstever@gmail.com else: 529983Sstever@gmail.com _list = list(_list) 539983Sstever@gmail.com _list.sort() 549983Sstever@gmail.com return _list 559983Sstever@gmail.com 569983Sstever@gmail.comclass PySourceFile(object): 579983Sstever@gmail.com def __init__(self, package, source): 589983Sstever@gmail.com filename = str(source) 599983Sstever@gmail.com pyname = basename(filename) 609983Sstever@gmail.com assert pyname.endswith('.py') 619983Sstever@gmail.com name = pyname[:-3] 629983Sstever@gmail.com path = package.split('.') 639983Sstever@gmail.com modpath = path 649983Sstever@gmail.com if name != '__init__': 659983Sstever@gmail.com modpath += [name] 669983Sstever@gmail.com modpath = '.'.join(modpath) 679983Sstever@gmail.com 689983Sstever@gmail.com arcpath = package.split('.') + [ pyname + 'c' ] 699983Sstever@gmail.com arcname = joinpath(*arcpath) 709983Sstever@gmail.com 719983Sstever@gmail.com self.source = source 729983Sstever@gmail.com self.pyname = pyname 739983Sstever@gmail.com self.srcpath = source.srcnode().abspath 749983Sstever@gmail.com self.package = package 759983Sstever@gmail.com self.modpath = modpath 769983Sstever@gmail.com self.arcname = arcname 779983Sstever@gmail.com self.filename = filename 789983Sstever@gmail.com self.compiled = File(filename + 'c') 799983Sstever@gmail.com 809983Sstever@gmail.com######################################################################## 819983Sstever@gmail.com# Code for adding source files of various types 829983Sstever@gmail.com# 839983Sstever@gmail.comcc_sources = [] 849983Sstever@gmail.comdef Source(source): 859983Sstever@gmail.com '''Add a C/C++ source file to the build''' 869983Sstever@gmail.com if not isinstance(source, SCons.Node.FS.File): 879983Sstever@gmail.com source = File(source) 889983Sstever@gmail.com 899983Sstever@gmail.com cc_sources.append(source) 909983Sstever@gmail.com 919983Sstever@gmail.compy_sources = [] 929983Sstever@gmail.comdef PySource(package, source): 939983Sstever@gmail.com '''Add a python source file to the named package''' 9410153Sandreas@sandberg.pp.se if not isinstance(source, SCons.Node.FS.File): 9510153Sandreas@sandberg.pp.se source = File(source) 9610153Sandreas@sandberg.pp.se 9710153Sandreas@sandberg.pp.se source = PySourceFile(package, source) 9810153Sandreas@sandberg.pp.se py_sources.append(source) 9910153Sandreas@sandberg.pp.se 10010153Sandreas@sandberg.pp.sesim_objects_fixed = False 10110153Sandreas@sandberg.pp.sesim_object_modfiles = set() 10210153Sandreas@sandberg.pp.sedef SimObject(source): 10310361SAndreas.Sandberg@ARM.com '''Add a SimObject python file as a python source object and add 1049983Sstever@gmail.com it to a list of sim object modules''' 1059983Sstever@gmail.com 1069983Sstever@gmail.com if sim_objects_fixed: 1079983Sstever@gmail.com raise AttributeError, "Too late to call SimObject now." 1089983Sstever@gmail.com 1099983Sstever@gmail.com if not isinstance(source, SCons.Node.FS.File): 1109983Sstever@gmail.com source = File(source) 1119983Sstever@gmail.com 11210361SAndreas.Sandberg@ARM.com PySource('m5.objects', source) 1139983Sstever@gmail.com modfile = basename(str(source)) 1149983Sstever@gmail.com assert modfile.endswith('.py') 1159983Sstever@gmail.com modname = modfile[:-3] 1169983Sstever@gmail.com sim_object_modfiles.add(modname) 1179983Sstever@gmail.com 1189983Sstever@gmail.comswig_sources = [] 1199983Sstever@gmail.comdef SwigSource(package, source): 1209983Sstever@gmail.com '''Add a swig file to build''' 1219983Sstever@gmail.com if not isinstance(source, SCons.Node.FS.File): 1229983Sstever@gmail.com source = File(source) 1239983Sstever@gmail.com val = source,package 1249983Sstever@gmail.com swig_sources.append(val) 1259983Sstever@gmail.com 1269983Sstever@gmail.com# Children should have access 1279983Sstever@gmail.comExport('Source') 1289983Sstever@gmail.comExport('PySource') 1299983Sstever@gmail.comExport('SimObject') 1309983Sstever@gmail.comExport('SwigSource') 1319983Sstever@gmail.com 1329983Sstever@gmail.com######################################################################## 1339983Sstever@gmail.com# 1349983Sstever@gmail.com# Trace Flags 1359983Sstever@gmail.com# 1369983Sstever@gmail.comall_flags = {} 1379983Sstever@gmail.comtrace_flags = [] 1389983Sstever@gmail.comdef TraceFlag(name, desc=''): 1399983Sstever@gmail.com if name in all_flags: 1409983Sstever@gmail.com raise AttributeError, "Flag %s already specified" % name 1419983Sstever@gmail.com flag = (name, (), desc) 1429983Sstever@gmail.com trace_flags.append(flag) 1439983Sstever@gmail.com all_flags[name] = () 1449983Sstever@gmail.com 1459983Sstever@gmail.comdef CompoundFlag(name, flags, desc=''): 1469983Sstever@gmail.com if name in all_flags: 1479983Sstever@gmail.com raise AttributeError, "Flag %s already specified" % name 1489983Sstever@gmail.com 1499983Sstever@gmail.com compound = tuple(flags) 1509983Sstever@gmail.com for flag in compound: 1519983Sstever@gmail.com if flag not in all_flags: 1529983Sstever@gmail.com raise AttributeError, "Trace flag %s not found" % flag 1539983Sstever@gmail.com if all_flags[flag]: 1549983Sstever@gmail.com raise AttributeError, \ 1559983Sstever@gmail.com "Compound flag can't point to another compound flag" 1569983Sstever@gmail.com 1579983Sstever@gmail.com flag = (name, compound, desc) 1589983Sstever@gmail.com trace_flags.append(flag) 1599983Sstever@gmail.com all_flags[name] = compound 1609983Sstever@gmail.com 1619983Sstever@gmail.comExport('TraceFlag') 1629983Sstever@gmail.comExport('CompoundFlag') 1639983Sstever@gmail.com 1649983Sstever@gmail.com######################################################################## 1659983Sstever@gmail.com# 1669983Sstever@gmail.com# Set some compiler variables 1679983Sstever@gmail.com# 1689983Sstever@gmail.com 1699983Sstever@gmail.com# Include file paths are rooted in this directory. SCons will 1709983Sstever@gmail.com# automatically expand '.' to refer to both the source directory and 1719983Sstever@gmail.com# the corresponding build directory to pick up generated include 1729983Sstever@gmail.com# files. 1739983Sstever@gmail.comenv.Append(CPPPATH=Dir('.')) 1749983Sstever@gmail.com 1759983Sstever@gmail.com# Add a flag defining what THE_ISA should be for all compilation 1769983Sstever@gmail.comenv.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) 1779983Sstever@gmail.com 1789983Sstever@gmail.com######################################################################## 1799983Sstever@gmail.com# 1809983Sstever@gmail.com# Walk the tree and execute all SConscripts in subdirectories 1819983Sstever@gmail.com# 1829983Sstever@gmail.com 1839983Sstever@gmail.comfor base_dir in base_dir_list: 1849983Sstever@gmail.com here = Dir('.').srcnode().abspath 1859983Sstever@gmail.com for root, dirs, files in os.walk(base_dir, topdown=True): 1869983Sstever@gmail.com if root == here: 1879983Sstever@gmail.com # we don't want to recurse back into this SConscript 1889983Sstever@gmail.com continue 1899983Sstever@gmail.com 1909983Sstever@gmail.com if 'SConscript' in files: 1919983Sstever@gmail.com build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) 1929983Sstever@gmail.com SConscript(joinpath(root, 'SConscript'), build_dir=build_dir) 1939983Sstever@gmail.com 1949983Sstever@gmail.comfor opt in env.ExportOptions: 1959983Sstever@gmail.com env.ConfigFile(opt) 1969983Sstever@gmail.com 1979983Sstever@gmail.com######################################################################## 1989983Sstever@gmail.com# 1999983Sstever@gmail.com# Prevent any SimObjects from being added after this point, they 2009983Sstever@gmail.com# should all have been added in the SConscripts above 2019983Sstever@gmail.com# 2029983Sstever@gmail.comsim_objects_fixed = True 2039983Sstever@gmail.com 2049983Sstever@gmail.com######################################################################## 2059983Sstever@gmail.com# 2069983Sstever@gmail.com# Manually turn python/generate.py into a python module and import it 2079983Sstever@gmail.com# 2089983Sstever@gmail.comgenerate_file = File('python/generate.py') 2099983Sstever@gmail.comgenerate_module = imp.new_module('generate') 2109983Sstever@gmail.comsys.modules['generate'] = generate_module 2119983Sstever@gmail.comexec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__ 2129983Sstever@gmail.com 2139983Sstever@gmail.com######################################################################## 2149983Sstever@gmail.com# 2159983Sstever@gmail.com# build a generate 2169983Sstever@gmail.com# 2179983Sstever@gmail.comfrom generate import Generate 2189983Sstever@gmail.comoptionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) 2199983Sstever@gmail.comgenerate = Generate(py_sources, sim_object_modfiles, optionDict) 2209983Sstever@gmail.comm5 = generate.m5 2219983Sstever@gmail.com 22211290Sgabor.dozsa@arm.com######################################################################## 2239983Sstever@gmail.com# 2249983Sstever@gmail.com# calculate extra dependencies 2259983Sstever@gmail.com# 2269983Sstever@gmail.commodule_depends = ["m5", "m5.SimObject", "m5.params"] 2279983Sstever@gmail.commodule_depends = [ File(generate.py_modules[dep]) for dep in module_depends ] 2289983Sstever@gmail.comfile_depends = [ generate_file ] 2299983Sstever@gmail.comdepends = module_depends + file_depends 2309983Sstever@gmail.com 2319983Sstever@gmail.com######################################################################## 2329983Sstever@gmail.com# 2339983Sstever@gmail.com# Commands for the basic automatically generated python files 2349983Sstever@gmail.com# 2359983Sstever@gmail.com 2369983Sstever@gmail.com# Generate a file with all of the compile options in it 2379983Sstever@gmail.comenv.Command('python/m5/defines.py', Value(optionDict), 2389983Sstever@gmail.com generate.makeDefinesPyFile) 2399983Sstever@gmail.comPySource('m5', 'python/m5/defines.py') 240 241# Generate a file that wraps the basic top level files 242env.Command('python/m5/info.py', 243 [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], 244 generate.makeInfoPyFile) 245PySource('m5', 'python/m5/info.py') 246 247# Generate an __init__.py file for the objects package 248env.Command('python/m5/objects/__init__.py', 249 [ Value(o) for o in sort_list(sim_object_modfiles) ], 250 generate.makeObjectsInitFile) 251PySource('m5.objects', 'python/m5/objects/__init__.py') 252 253######################################################################## 254# 255# Create all of the SimObject param headers and enum headers 256# 257 258# Generate all of the SimObject param struct header files 259params_hh_files = [] 260for name,simobj in generate.sim_objects.iteritems(): 261 extra_deps = [ File(generate.py_modules[simobj.__module__]) ] 262 263 hh_file = File('params/%s.hh' % name) 264 params_hh_files.append(hh_file) 265 env.Command(hh_file, Value(name), generate.createSimObjectParam) 266 env.Depends(hh_file, depends + extra_deps) 267 268# Generate any parameter header files needed 269for name,param in generate.params.iteritems(): 270 if isinstance(param, m5.params.VectorParamDesc): 271 ext = 'vptype' 272 else: 273 ext = 'ptype' 274 275 i_file = File('params/%s_%s.i' % (name, ext)) 276 env.Command(i_file, Value(name), generate.createSwigParam) 277 env.Depends(i_file, depends) 278 279# Generate all enum header files 280for name,enum in generate.enums.iteritems(): 281 extra_deps = [ File(generate.py_modules[enum.__module__]) ] 282 283 cc_file = File('enums/%s.cc' % name) 284 env.Command(cc_file, Value(name), generate.createEnumStrings) 285 env.Depends(cc_file, depends + extra_deps) 286 Source(cc_file) 287 288 hh_file = File('enums/%s.hh' % name) 289 env.Command(hh_file, Value(name), generate.createEnumParam) 290 env.Depends(hh_file, depends + extra_deps) 291 292# Build the big monolithic swigged params module (wraps all SimObject 293# param structs and enum structs) 294params_file = File('params/params.i') 295names = sort_list(generate.sim_objects.keys()) 296env.Command(params_file, [ Value(v) for v in names ], 297 generate.buildParams) 298env.Depends(params_file, params_hh_files + depends) 299SwigSource('m5.objects', params_file) 300 301# Build all swig modules 302swig_modules = [] 303for source,package in swig_sources: 304 filename = str(source) 305 assert filename.endswith('.i') 306 307 base = '.'.join(filename.split('.')[:-1]) 308 module = basename(base) 309 cc_file = base + '_wrap.cc' 310 py_file = base + '.py' 311 312 env.Command([cc_file, py_file], source, 313 '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' 314 '-o ${TARGETS[0]} $SOURCES') 315 env.Depends(py_file, source) 316 env.Depends(cc_file, source) 317 318 swig_modules.append(Value(module)) 319 Source(cc_file) 320 PySource(package, py_file) 321 322# Generate the main swig init file 323env.Command('swig/init.cc', swig_modules, generate.makeSwigInit) 324Source('swig/init.cc') 325 326# Generate traceflags.py 327flags = [ Value(f) for f in trace_flags ] 328env.Command('base/traceflags.py', flags, generate.traceFlagsPy) 329PySource('m5', 'base/traceflags.py') 330 331env.Command('base/traceflags.hh', flags, generate.traceFlagsHH) 332env.Command('base/traceflags.cc', flags, generate.traceFlagsCC) 333Source('base/traceflags.cc') 334 335# Generate program_info.cc 336env.Command('base/program_info.cc', 337 Value(str(SCons.Node.FS.default_fs.SConstruct_dir)), generate.programInfo) 338 339# Build the zip file 340py_compiled = [] 341py_zip_depends = [] 342for source in py_sources: 343 env.Command(source.compiled, source.source, generate.compilePyFile) 344 py_compiled.append(source.compiled) 345 346 # make the zipfile depend on the archive name so that the archive 347 # is rebuilt if the name changes 348 py_zip_depends.append(Value(source.arcname)) 349 350# Add the zip file target to the environment. 351m5zip = File('m5py.zip') 352env.Command(m5zip, py_compiled, generate.buildPyZip) 353env.Depends(m5zip, py_zip_depends) 354 355######################################################################## 356# 357# Define binaries. Each different build type (debug, opt, etc.) gets 358# a slightly different build environment. 359# 360 361# List of constructed environments to pass back to SConstruct 362envList = [] 363 364# This function adds the specified sources to the given build 365# environment, and returns a list of all the corresponding SCons 366# Object nodes (including an extra one for date.cc). We explicitly 367# add the Object nodes so we can set up special dependencies for 368# date.cc. 369def make_objs(sources, env): 370 objs = [env.Object(s) for s in sources] 371 372 # make date.cc depend on all other objects so it always gets 373 # recompiled whenever anything else does 374 date_obj = env.Object('base/date.cc') 375 376 # Make the generation of program_info.cc dependend on all 377 # the other cc files and the compiling of program_info.cc 378 # dependent on all the objects but program_info.o 379 pinfo_obj = env.Object('base/program_info.cc') 380 env.Depends('base/program_info.cc', sources) 381 env.Depends(date_obj, objs) 382 env.Depends(pinfo_obj, objs) 383 objs.extend([date_obj,pinfo_obj]) 384 return objs 385 386# Function to create a new build environment as clone of current 387# environment 'env' with modified object suffix and optional stripped 388# binary. Additional keyword arguments are appended to corresponding 389# build environment vars. 390def makeEnv(label, objsfx, strip = False, **kwargs): 391 newEnv = env.Copy(OBJSUFFIX=objsfx) 392 newEnv.Label = label 393 newEnv.Append(**kwargs) 394 exe = 'm5.' + label # final executable 395 bin = exe + '.bin' # executable w/o appended Python zip archive 396 newEnv.Program(bin, make_objs(cc_sources, newEnv)) 397 if strip: 398 stripped_bin = bin + '.stripped' 399 if sys.platform == 'sunos5': 400 cmd = 'cp $SOURCE $TARGET; strip $TARGET' 401 else: 402 cmd = 'strip $SOURCE -o $TARGET' 403 newEnv.Command(stripped_bin, bin, cmd) 404 bin = stripped_bin 405 targets = newEnv.Concat(exe, [bin, 'm5py.zip']) 406 newEnv.M5Binary = targets[0] 407 envList.append(newEnv) 408 409# Debug binary 410ccflags = {} 411if env['GCC']: 412 if sys.platform == 'sunos5': 413 ccflags['debug'] = '-gstabs+' 414 else: 415 ccflags['debug'] = '-ggdb3' 416 ccflags['opt'] = '-g -O3' 417 ccflags['fast'] = '-O3' 418 ccflags['prof'] = '-O3 -g -pg' 419elif env['SUNCC']: 420 ccflags['debug'] = '-g0' 421 ccflags['opt'] = '-g -O' 422 ccflags['fast'] = '-fast' 423 ccflags['prof'] = '-fast -g -pg' 424elif env['ICC']: 425 ccflags['debug'] = '-g -O0' 426 ccflags['opt'] = '-g -O' 427 ccflags['fast'] = '-fast' 428 ccflags['prof'] = '-fast -g -pg' 429else: 430 print 'Unknown compiler, please fix compiler options' 431 Exit(1) 432 433makeEnv('debug', '.do', 434 CCFLAGS = Split(ccflags['debug']), 435 CPPDEFINES = ['DEBUG', 'TRACING_ON=1']) 436 437# Optimized binary 438makeEnv('opt', '.o', 439 CCFLAGS = Split(ccflags['opt']), 440 CPPDEFINES = ['TRACING_ON=1']) 441 442# "Fast" binary 443makeEnv('fast', '.fo', strip = True, 444 CCFLAGS = Split(ccflags['fast']), 445 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0']) 446 447# Profiled binary 448makeEnv('prof', '.po', 449 CCFLAGS = Split(ccflags['prof']), 450 CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], 451 LINKFLAGS = '-pg') 452 453Return('envList') 454