X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2FSConscript;h=fd67533200ba8e3d4331ce0789fb54e6775607b7;hb=aa598b3ad1d91e974378f18837f2fbcca909e805;hp=8c407f4c72ce956a7dc1a1b38a6d3e08efbd233d;hpb=d1f3a3b91a2370c5e8fae2951a3ee6231158d4f4;p=gem5.git diff --git a/src/SConscript b/src/SConscript index 8c407f4c7..fd6753320 100755 --- a/src/SConscript +++ b/src/SConscript @@ -34,6 +34,7 @@ import imp import marshal import os import re +import subprocess import sys import zlib @@ -63,12 +64,25 @@ from m5.util import code_formatter, compareVersions # false). Current filters are: # main -- specifies the gem5 main() function # skip_lib -- do not put this file into the gem5 library +# skip_no_python -- do not put this file into a no_python library +# as it embeds compiled Python # -- unit tests use filters based on the unit test name # # A parent can now be specified for a source file and default filter # values will be retrieved recursively from parents (children override # parents). # +def guarded_source_iterator(sources, **guards): + '''Iterate over a set of sources, gated by a set of guards.''' + for src in sources: + for flag,value in guards.iteritems(): + # if the flag is found and has a different value, skip + # this file + if src.all_guards.get(flag, False) != value: + break + else: + yield src + class SourceMeta(type): '''Meta class for source files that keeps track of all files of a particular type and has a get function for finding all functions @@ -76,18 +90,12 @@ class SourceMeta(type): def __init__(cls, name, bases, dict): super(SourceMeta, cls).__init__(name, bases, dict) cls.all = [] - + def get(cls, **guards): '''Find all files that match the specified guards. If a source file does not specify a flag, the default is False''' - for src in cls.all: - for flag,value in guards.iteritems(): - # if the flag is found and has a different value, skip - # this file - if src.all_guards.get(flag, False) != value: - break - else: - yield src + for s in guarded_source_iterator(cls.all, **guards): + yield s class SourceFile(object): '''Base object that encapsulates the notion of a source file. @@ -148,15 +156,33 @@ class SourceFile(object): def __ge__(self, other): return self.filename >= other.filename def __eq__(self, other): return self.filename == other.filename def __ne__(self, other): return self.filename != other.filename - + + @staticmethod + def done(): + def disabled(cls, name, *ignored): + raise RuntimeError("Additional SourceFile '%s'" % name,\ + "declared, but targets deps are already fixed.") + SourceFile.__init__ = disabled + + class Source(SourceFile): + current_group = None + source_groups = { None : [] } + + @classmethod + def set_group(cls, group): + if not group in Source.source_groups: + Source.source_groups[group] = [] + Source.current_group = group + '''Add a c/c++ source file to the build''' - def __init__(self, source, Werror=True, swig=False, **guards): + def __init__(self, source, Werror=True, **guards): '''specify the source file, and any guards''' super(Source, self).__init__(source, **guards) self.Werror = Werror - self.swig = swig + + Source.source_groups[Source.current_group].append(self) class PySource(SourceFile): '''Add a python source file to the named package''' @@ -164,7 +190,7 @@ class PySource(SourceFile): modules = {} tnodes = {} symnames = {} - + def __init__(self, package, source, **guards): '''specify the python package, the source file, and any guards''' super(PySource, self).__init__(source, **guards) @@ -216,22 +242,21 @@ class SimObject(PySource): bisect.insort_right(SimObject.modnames, self.modname) -class SwigSource(SourceFile): - '''Add a swig file to build''' +class ProtoBuf(SourceFile): + '''Add a Protocol Buffer to build''' - def __init__(self, package, source, **guards): - '''Specify the python package, the source file, and any guards''' - super(SwigSource, self).__init__(source, **guards) + def __init__(self, source, **guards): + '''Specify the source file, and any guards''' + super(ProtoBuf, self).__init__(source, **guards) + # Get the file name and the extension modname,ext = self.extname - assert ext == 'i' - - self.module = modname - cc_file = joinpath(self.dirname, modname + '_wrap.cc') - py_file = joinpath(self.dirname, modname + '.py') + assert ext == 'proto' - self.cc_source = Source(cc_file, swig=True, parent=self) - self.py_source = PySource(package, py_file, parent=self) + # Currently, we stick to generating the C++ headers, so we + # only need to track the source and header. + self.cc_file = File(modname + '.pb.cc') + self.hh_file = File(modname + '.pb.h') class UnitTest(object): '''Create a UnitTest''' @@ -259,7 +284,7 @@ class UnitTest(object): Export('Source') Export('PySource') Export('SimObject') -Export('SwigSource') +Export('ProtoBuf') Export('UnitTest') ######################################################################## @@ -314,10 +339,16 @@ for root, dirs, files in os.walk(base_dir, topdown=True): if 'SConscript' in files: build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) + Source.set_group(build_dir) SConscript(joinpath(root, 'SConscript'), variant_dir=build_dir) for extra_dir in extras_dir_list: prefix_len = len(dirname(extra_dir)) + 1 + + # Also add the corresponding build directory to pick up generated + # include files. + env.Append(CPPPATH=Dir(joinpath(env['BUILDDIR'], extra_dir[prefix_len:]))) + for root, dirs, files in os.walk(extra_dir, topdown=True): # if build lives in the extras directory, don't walk down it if 'build' in dirs: @@ -335,9 +366,9 @@ def makeTheISA(source, target, env): target_isa = env['TARGET_ISA'] def define(isa): return isa.upper() + '_ISA' - + def namespace(isa): - return isa[0].upper() + isa[1:].lower() + 'ISA' + return isa[0].upper() + isa[1:].lower() + 'ISA' code = code_formatter() @@ -347,8 +378,20 @@ def makeTheISA(source, target, env): ''') + # create defines for the preprocessing and compile-time determination for i,isa in enumerate(isas): code('#define $0 $1', define(isa), i + 1) + code() + + # create an enum for any run-time determination of the ISA, we + # reuse the same name as the namespaces + code('enum class Arch {') + for i,isa in enumerate(isas): + if i + 1 == len(isas): + code(' $0 = $1', namespace(isa), define(isa)) + else: + code(' $0 = $1,', namespace(isa), define(isa)) + code('};') code(''' @@ -363,6 +406,51 @@ def makeTheISA(source, target, env): env.Command('config/the_isa.hh', map(Value, all_isa_list), MakeAction(makeTheISA, Transform("CFG ISA", 0))) +def makeTheGPUISA(source, target, env): + isas = [ src.get_contents() for src in source ] + target_gpu_isa = env['TARGET_GPU_ISA'] + def define(isa): + return isa.upper() + '_ISA' + + def namespace(isa): + return isa[0].upper() + isa[1:].lower() + 'ISA' + + + code = code_formatter() + code('''\ +#ifndef __CONFIG_THE_GPU_ISA_HH__ +#define __CONFIG_THE_GPU_ISA_HH__ + +''') + + # create defines for the preprocessing and compile-time determination + for i,isa in enumerate(isas): + code('#define $0 $1', define(isa), i + 1) + code() + + # create an enum for any run-time determination of the ISA, we + # reuse the same name as the namespaces + code('enum class GPUArch {') + for i,isa in enumerate(isas): + if i + 1 == len(isas): + code(' $0 = $1', namespace(isa), define(isa)) + else: + code(' $0 = $1,', namespace(isa), define(isa)) + code('};') + + code(''' + +#define THE_GPU_ISA ${{define(target_gpu_isa)}} +#define TheGpuISA ${{namespace(target_gpu_isa)}} +#define THE_GPU_ISA_STR "${{target_gpu_isa}}" + +#endif // __CONFIG_THE_GPU_ISA_HH__''') + + code.write(str(target[0])) + +env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list), + MakeAction(makeTheGPUISA, Transform("CFG ISA", 0))) + ######################################################################## # # Prevent any SimObjects from being added after this point, they @@ -393,7 +481,7 @@ class DictImporter(object): if fullname == 'm5.objects': return self - if fullname.startswith('m5.internal'): + if fullname.startswith('_m5'): return None source = self.modules.get(fullname, None) @@ -451,13 +539,6 @@ sys.meta_path.remove(importer) sim_objects = m5.SimObject.allClasses all_enums = m5.params.allEnums -# Find param types that need to be explicitly wrapped with swig. -# These will be recognized because the ParamDesc will have a -# swig_decl() method. Most param types are based on types that don't -# need this, either because they're based on native types (like Int) -# or because they're SimObjects (which get swigged independently). -# For now the only things handled here are VectorParam types. -params_to_swig = {} for name,obj in sorted(sim_objects.iteritems()): for param in obj._params.local.values(): # load the ptype attribute now because it depends on the @@ -466,18 +547,13 @@ for name,obj in sorted(sim_objects.iteritems()): # SimObject.allClasses will have been loaded param.ptype - if not hasattr(param, 'swig_decl'): - continue - pname = param.ptype_str - if pname not in params_to_swig: - params_to_swig[pname] = param - ######################################################################## # # calculate extra dependencies # module_depends = ["m5", "m5.SimObject", "m5.params"] depends = [ PySource.modules[dep].snode for dep in module_depends ] +depends.sort(key = lambda x: x.name) ######################################################################## # @@ -491,14 +567,14 @@ def makeDefinesPyFile(target, source, env): code = code_formatter() code(""" -import m5.internal +import _m5.core import m5.util buildEnv = m5.util.SmartDict($build_env) -compileDate = m5.internal.core.compileDate +compileDate = _m5.core.compileDate _globals = globals() -for key,val in m5.internal.core.__dict__.iteritems(): +for key,val in _m5.core.__dict__.iteritems(): if key.startswith('flag_'): flag = key[5:] _globals[flag] = val @@ -541,15 +617,17 @@ def createSimObjectParamStruct(target, source, env): obj.cxx_param_decl(code) code.write(target[0].abspath) -def createParamSwigWrapper(target, source, env): - assert len(target) == 1 and len(source) == 1 +def createSimObjectCxxConfig(is_header): + def body(target, source, env): + assert len(target) == 1 and len(source) == 1 - name = str(source[0].get_contents()) - param = params_to_swig[name] + name = str(source[0].get_contents()) + obj = sim_objects[name] - code = code_formatter() - param.swig_decl(code) - code.write(target[0].abspath) + code = code_formatter() + obj.cxx_config_param_file(code, is_header) + code.write(target[0].abspath) + return body def createEnumStrings(target, source, env): assert len(target) == 1 and len(source) == 1 @@ -559,6 +637,8 @@ def createEnumStrings(target, source, env): code = code_formatter() obj.cxx_def(code) + if env['USE_PYTHON']: + obj.pybind_def(code) code.write(target[0].abspath) def createEnumDecls(target, source, env): @@ -571,22 +651,12 @@ def createEnumDecls(target, source, env): obj.cxx_decl(code) code.write(target[0].abspath) -def createEnumSwigWrapper(target, source, env): - assert len(target) == 1 and len(source) == 1 - - name = str(source[0].get_contents()) - obj = all_enums[name] - - code = code_formatter() - obj.swig_decl(code) - code.write(target[0].abspath) - -def createSimObjectSwigWrapper(target, source, env): +def createSimObjectPyBindWrapper(target, source, env): name = source[0].get_contents() obj = sim_objects[name] code = code_formatter() - obj.swig_decl(code) + obj.pybind_decl(code) code.write(target[0].abspath) # Generate all of the SimObject param C++ struct header files @@ -601,15 +671,60 @@ for name,simobj in sorted(sim_objects.iteritems()): MakeAction(createSimObjectParamStruct, Transform("SO PARAM"))) env.Depends(hh_file, depends + extra_deps) -# Generate any needed param SWIG wrapper files -params_i_files = [] -for name,param in params_to_swig.iteritems(): - i_file = File('python/m5/internal/%s.i' % (param.swig_module_name())) - params_i_files.append(i_file) - env.Command(i_file, Value(name), - MakeAction(createParamSwigWrapper, Transform("SW PARAM"))) - env.Depends(i_file, depends) - SwigSource('m5.internal', i_file) +# C++ parameter description files +if GetOption('with_cxx_config'): + for name,simobj in sorted(sim_objects.iteritems()): + py_source = PySource.modules[simobj.__module__] + extra_deps = [ py_source.tnode ] + + cxx_config_hh_file = File('cxx_config/%s.hh' % name) + cxx_config_cc_file = File('cxx_config/%s.cc' % name) + env.Command(cxx_config_hh_file, Value(name), + MakeAction(createSimObjectCxxConfig(True), + Transform("CXXCPRHH"))) + env.Command(cxx_config_cc_file, Value(name), + MakeAction(createSimObjectCxxConfig(False), + Transform("CXXCPRCC"))) + env.Depends(cxx_config_hh_file, depends + extra_deps + + [File('params/%s.hh' % name), File('sim/cxx_config.hh')]) + env.Depends(cxx_config_cc_file, depends + extra_deps + + [cxx_config_hh_file]) + Source(cxx_config_cc_file) + + cxx_config_init_cc_file = File('cxx_config/init.cc') + + def createCxxConfigInitCC(target, source, env): + assert len(target) == 1 and len(source) == 1 + + code = code_formatter() + + for name,simobj in sorted(sim_objects.iteritems()): + if not hasattr(simobj, 'abstract') or not simobj.abstract: + code('#include "cxx_config/${name}.hh"') + code() + code('void cxxConfigInit()') + code('{') + code.indent() + for name,simobj in sorted(sim_objects.iteritems()): + not_abstract = not hasattr(simobj, 'abstract') or \ + not simobj.abstract + if not_abstract and 'type' in simobj.__dict__: + code('cxx_config_directory["${name}"] = ' + '${name}CxxConfigParams::makeDirectoryEntry();') + code.dedent() + code('}') + code.write(target[0].abspath) + + py_source = PySource.modules[simobj.__module__] + extra_deps = [ py_source.tnode ] + env.Command(cxx_config_init_cc_file, Value(name), + MakeAction(createCxxConfigInitCC, Transform("CXXCINIT"))) + cxx_param_hh_files = ["cxx_config/%s.hh" % simobj + for name,simobj in sorted(sim_objects.iteritems()) + if not hasattr(simobj, 'abstract') or not simobj.abstract] + Depends(cxx_config_init_cc_file, cxx_param_hh_files + + [File('sim/cxx_config.hh')]) + Source(cxx_config_init_cc_file) # Generate all enum header files for name,enum in sorted(all_enums.iteritems()): @@ -627,45 +742,35 @@ for name,enum in sorted(all_enums.iteritems()): MakeAction(createEnumDecls, Transform("ENUMDECL"))) env.Depends(hh_file, depends + extra_deps) - i_file = File('python/m5/internal/enum_%s.i' % name) - env.Command(i_file, Value(name), - MakeAction(createEnumSwigWrapper, Transform("ENUMSWIG"))) - env.Depends(i_file, depends + extra_deps) - SwigSource('m5.internal', i_file) - -# Generate SimObject SWIG wrapper files -for name in sim_objects.iterkeys(): - i_file = File('python/m5/internal/param_%s.i' % name) - env.Command(i_file, Value(name), - MakeAction(createSimObjectSwigWrapper, Transform("SO SWIG"))) - env.Depends(i_file, depends) - SwigSource('m5.internal', i_file) - -# Generate the main swig init file -def makeEmbeddedSwigInit(target, source, env): - code = code_formatter() - module = source[0].get_contents() - code('''\ -#include "sim/init.hh" - -extern "C" { - void init_${module}(); -} - -EmbeddedSwig embed_swig_${module}(init_${module}); -''') - code.write(str(target[0])) - -# Build all swig modules -for swig in SwigSource.all: - env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode, - MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' - '-o ${TARGETS[0]} $SOURCES', Transform("SWIG"))) - cc_file = str(swig.tnode) - init_file = '%s/%s_init.cc' % (dirname(cc_file), basename(cc_file)) - env.Command(init_file, Value(swig.module), - MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW"))) - Source(init_file, **swig.guards) +# Generate SimObject Python bindings wrapper files +if env['USE_PYTHON']: + for name,simobj in sorted(sim_objects.iteritems()): + py_source = PySource.modules[simobj.__module__] + extra_deps = [ py_source.tnode ] + cc_file = File('python/_m5/param_%s.cc' % name) + env.Command(cc_file, Value(name), + MakeAction(createSimObjectPyBindWrapper, + Transform("SO PyBind"))) + env.Depends(cc_file, depends + extra_deps) + Source(cc_file) + +# Build all protocol buffers if we have got protoc and protobuf available +if env['HAVE_PROTOBUF']: + for proto in ProtoBuf.all: + # Use both the source and header as the target, and the .proto + # file as the source. When executing the protoc compiler, also + # specify the proto_path to avoid having the generated files + # include the path. + env.Command([proto.cc_file, proto.hh_file], proto.tnode, + MakeAction('$PROTOC --cpp_out ${TARGET.dir} ' + '--proto_path ${SOURCE.dir} $SOURCE', + Transform("PROTOC"))) + + # Add the C++ source file + Source(proto.cc_file, **proto.guards) +elif ProtoBuf.all: + print 'Got protobuf to build, but lacks support!' + Exit(1) # # Handle debug flags @@ -673,40 +778,42 @@ for swig in SwigSource.all: def makeDebugFlagCC(target, source, env): assert(len(target) == 1 and len(source) == 1) - val = eval(source[0].get_contents()) - name, compound, desc = val - compound = list(sorted(compound)) - code = code_formatter() + # delay definition of CompoundFlags until after all the definition + # of all constituent SimpleFlags + comp_code = code_formatter() + # file header code(''' /* - * DO NOT EDIT THIS FILE! Automatically generated + * DO NOT EDIT THIS FILE! Automatically generated by SCons. */ #include "base/debug.hh" -''') - for flag in compound: - code('#include "debug/$flag.hh"') - code() - code('namespace Debug {') - code() +namespace Debug { - if not compound: - code('SimpleFlag $name("$name", "$desc");') - else: - code('CompoundFlag $name("$name", "$desc",') - code.indent() - last = len(compound) - 1 - for i,flag in enumerate(compound): - if i != last: - code('$flag,') - else: - code('$flag);') - code.dedent() +''') + for name, flag in sorted(source[0].read().iteritems()): + n, compound, desc = flag + assert n == name + + if not compound: + code('SimpleFlag $name("$name", "$desc");') + else: + comp_code('CompoundFlag $name("$name", "$desc",') + comp_code.indent() + last = len(compound) - 1 + for i,flag in enumerate(compound): + if i != last: + comp_code('&$flag,') + else: + comp_code('&$flag);') + comp_code.dedent() + + code.append(comp_code) code() code('} // namespace Debug') @@ -723,9 +830,7 @@ def makeDebugFlagHH(target, source, env): # file header boilerplate code('''\ /* - * DO NOT EDIT THIS FILE! - * - * Automatically generated by SCons + * DO NOT EDIT THIS FILE! Automatically generated by SCons. */ #ifndef __DEBUG_${name}_HH__ @@ -757,11 +862,20 @@ for name,flag in sorted(debug_flags.iteritems()): n, compound, desc = flag assert n == name - env.Command('debug/%s.hh' % name, Value(flag), + hh_file = 'debug/%s.hh' % name + env.Command(hh_file, Value(flag), MakeAction(makeDebugFlagHH, Transform("TRACING", 0))) - env.Command('debug/%s.cc' % name, Value(flag), - MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) - Source('debug/%s.cc' % name) + +env.Command('debug/flags.cc', Value(debug_flags), + MakeAction(makeDebugFlagCC, Transform("TRACING", 0))) +Source('debug/flags.cc') + +# version tags +tags = \ +env.Command('sim/tags.cc', None, + MakeAction('util/cpt_upgrader.py --get-cc-file > $TARGET', + Transform("VER TAGS"))) +env.AlwaysBuild(tags) # Embed python files. All .py files that have been indicated by a # PySource() call in a SConscript need to be embedded into the M5 @@ -801,7 +915,7 @@ const uint8_t data_${sym}[] = { x = array.array('B', data[i:i+step]) code(''.join('%d,' % d for d in x)) code.dedent() - + code('''}; EmbeddedPython embedded_${sym}( @@ -817,9 +931,9 @@ EmbeddedPython embedded_${sym}( code.write(str(target[0])) for source in PySource.all: - env.Command(source.cpp, source.tnode, + env.Command(source.cpp, source.tnode, MakeAction(embedPyFile, Transform("EMBED PY"))) - Source(source.cpp) + Source(source.cpp, skip_no_python=True) ######################################################################## # @@ -828,47 +942,83 @@ for source in PySource.all: # # List of constructed environments to pass back to SConstruct -envList = [] - date_source = Source('base/date.cc', skip_lib=True) +# Capture this directory for the closure makeEnv, otherwise when it is +# called, it won't know what directory it should use. +variant_dir = Dir('.').path +def variant(*path): + return os.path.join(variant_dir, *path) +def variantd(*path): + return variant(*path)+'/' + # Function to create a new build environment as clone of current # environment 'env' with modified object suffix and optional stripped # binary. Additional keyword arguments are appended to corresponding # build environment vars. -def makeEnv(label, objsfx, strip = False, **kwargs): +def makeEnv(env, label, objsfx, strip = False, **kwargs): # SCons doesn't know to append a library suffix when there is a '.' in the # name. Use '_' instead. - libname = 'gem5_' + label - exename = 'gem5.' + label - secondary_exename = 'm5.' + label + libname = variant('gem5_' + label) + exename = variant('gem5.' + label) + secondary_exename = variant('m5.' + label) new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') new_env.Label = label new_env.Append(**kwargs) - swig_env = new_env.Clone() - swig_env.Append(CCFLAGS='-Werror') if env['GCC']: - swig_env.Append(CCFLAGS=['-Wno-uninitialized', '-Wno-sign-compare', - '-Wno-parentheses', '-Wno-unused-label', - '-Wno-unused-value']) - if compareVersions(env['GCC_VERSION'], '4.6') >= 0: - swig_env.Append(CCFLAGS='-Wno-unused-but-set-variable') + # The address sanitizer is available for gcc >= 4.8 + if GetOption('with_asan'): + if GetOption('with_ubsan') and \ + compareVersions(env['GCC_VERSION'], '4.9') >= 0: + new_env.Append(CCFLAGS=['-fsanitize=address,undefined', + '-fno-omit-frame-pointer']) + new_env.Append(LINKFLAGS='-fsanitize=address,undefined') + else: + new_env.Append(CCFLAGS=['-fsanitize=address', + '-fno-omit-frame-pointer']) + new_env.Append(LINKFLAGS='-fsanitize=address') + # Only gcc >= 4.9 supports UBSan, so check both the version + # and the command-line option before adding the compiler and + # linker flags. + elif GetOption('with_ubsan') and \ + compareVersions(env['GCC_VERSION'], '4.9') >= 0: + new_env.Append(CCFLAGS='-fsanitize=undefined') + new_env.Append(LINKFLAGS='-fsanitize=undefined') + + if env['CLANG']: - swig_env.Append(CCFLAGS=['-Wno-unused-label', '-Wno-unused-value']) + # We require clang >= 3.1, so there is no need to check any + # versions here. + if GetOption('with_ubsan'): + if GetOption('with_asan'): + new_env.Append(CCFLAGS=['-fsanitize=address,undefined', + '-fno-omit-frame-pointer']) + new_env.Append(LINKFLAGS='-fsanitize=address,undefined') + else: + new_env.Append(CCFLAGS='-fsanitize=undefined') + new_env.Append(LINKFLAGS='-fsanitize=undefined') + + elif GetOption('with_asan'): + new_env.Append(CCFLAGS=['-fsanitize=address', + '-fno-omit-frame-pointer']) + new_env.Append(LINKFLAGS='-fsanitize=address') werror_env = new_env.Clone() - werror_env.Append(CCFLAGS='-Werror') + # Treat warnings as errors but white list some warnings that we + # want to allow (e.g., deprecation warnings). + werror_env.Append(CCFLAGS=['-Werror', + '-Wno-error=deprecated-declarations', + '-Wno-error=deprecated', + ]) def make_obj(source, static, extra_deps = None): '''This function adds the specified source to the correct build environment, and returns the corresponding SCons Object nodes''' - if source.swig: - env = swig_env - elif source.Werror: + if source.Werror: env = werror_env else: env = new_env @@ -883,14 +1033,48 @@ def makeEnv(label, objsfx, strip = False, **kwargs): return obj - static_objs = \ - [ make_obj(s, True) for s in Source.get(main=False, skip_lib=False) ] - shared_objs = \ - [ make_obj(s, False) for s in Source.get(main=False, skip_lib=False) ] + lib_guards = {'main': False, 'skip_lib': False} + + # Without Python, leave out all Python content from the library + # builds. The option doesn't affect gem5 built as a program + if GetOption('without_python'): + lib_guards['skip_no_python'] = False + + static_objs = [] + shared_objs = [] + for s in guarded_source_iterator(Source.source_groups[None], **lib_guards): + static_objs.append(make_obj(s, True)) + shared_objs.append(make_obj(s, False)) + + partial_objs = [] + for group, all_srcs in Source.source_groups.iteritems(): + # If these are the ungrouped source files, skip them. + if not group: + continue + + # Get a list of the source files compatible with the current guards. + srcs = [ s for s in guarded_source_iterator(all_srcs, **lib_guards) ] + # If there aren't any left, skip this group. + if not srcs: + continue + + # Set up the static partially linked objects. + source_objs = [ make_obj(s, True) for s in srcs ] + file_name = new_env.subst("${OBJPREFIX}lib${OBJSUFFIX}.partial") + target = File(joinpath(group, file_name)) + partial = env.PartialStatic(target=target, source=source_objs) + static_objs.append(partial) + + # Set up the shared partially linked objects. + source_objs = [ make_obj(s, False) for s in srcs ] + file_name = new_env.subst("${SHOBJPREFIX}lib${SHOBJSUFFIX}.partial") + target = File(joinpath(group, file_name)) + partial = env.PartialShared(target=target, source=source_objs) + shared_objs.append(partial) static_date = make_obj(date_source, static=True, extra_deps=static_objs) static_objs.append(static_date) - + shared_date = make_obj(date_source, static=False, extra_deps=shared_objs) shared_objs.append(shared_date) @@ -908,8 +1092,8 @@ def makeEnv(label, objsfx, strip = False, **kwargs): test_objs = [ make_obj(s, static=True) for s in test_sources ] if test.main: test_objs += main_objs - testname = "unittest/%s.%s" % (test.target, label) - new_env.Program(testname, test_objs + static_objs) + path = variant('unittest/%s.%s' % (test.target, label)) + new_env.Program(path, test_objs + static_objs) progname = exename if strip: @@ -929,7 +1113,11 @@ def makeEnv(label, objsfx, strip = False, **kwargs): MakeAction('ln $SOURCE $TARGET', Transform("HARDLINK"))) new_env.M5Binary = targets[0] - envList.append(new_env) + + # Set up regression tests. + SConscript(os.path.join(env.root.abspath, 'tests', 'SConscript'), + variant_dir=variantd('tests', new_env.Label), + exports={ 'env' : new_env }, duplicate=False) # Start out with the compiler flags common to all compilers, # i.e. they all use -g for opt and -g -pg for prof @@ -962,17 +1150,6 @@ if env['GCC']: ccflags['fast'] += env['LTO_CCFLAGS'] ldflags['fast'] += env['LTO_LDFLAGS'] - -elif env['SUNCC']: - ccflags['debug'] += ['-g0'] - ccflags['opt'] += ['-O'] - for target in ['fast', 'prof', 'perf']: - ccflags[target] += ['-fast'] -elif env['ICC']: - ccflags['debug'] += ['-g', '-O0'] - ccflags['opt'] += ['-O'] - for target in ['fast', 'prof', 'perf']: - ccflags[target] += ['-fast'] elif env['CLANG']: ccflags['debug'] += ['-g', '-O0'] # opt, fast, prof and perf all share the same cc flags @@ -1006,39 +1183,63 @@ needed_envs = [identifyTarget(target) for target in BUILD_TARGETS] if 'all' in needed_envs: needed_envs += target_types -# Debug binary -if 'debug' in needed_envs: - makeEnv('debug', '.do', - CCFLAGS = Split(ccflags['debug']), - CPPDEFINES = ['DEBUG', 'TRACING_ON=1'], - LINKFLAGS = Split(ldflags['debug'])) - -# Optimized binary -if 'opt' in needed_envs: - makeEnv('opt', '.o', - CCFLAGS = Split(ccflags['opt']), - CPPDEFINES = ['TRACING_ON=1'], - LINKFLAGS = Split(ldflags['opt'])) - -# "Fast" binary -if 'fast' in needed_envs: - makeEnv('fast', '.fo', strip = True, - CCFLAGS = Split(ccflags['fast']), - CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], - LINKFLAGS = Split(ldflags['fast'])) - -# Profiled binary using gprof -if 'prof' in needed_envs: - makeEnv('prof', '.po', - CCFLAGS = Split(ccflags['prof']), - CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], - LINKFLAGS = Split(ldflags['prof'])) - -# Profiled binary using google-pprof -if 'perf' in needed_envs: - makeEnv('perf', '.gpo', - CCFLAGS = Split(ccflags['perf']), - CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], - LINKFLAGS = Split(ldflags['perf'])) - -Return('envList') +def makeEnvirons(target, source, env): + # cause any later Source() calls to be fatal, as a diagnostic. + Source.done() + + # Debug binary + if 'debug' in needed_envs: + makeEnv(env, 'debug', '.do', + CCFLAGS = Split(ccflags['debug']), + CPPDEFINES = ['DEBUG', 'TRACING_ON=1'], + LINKFLAGS = Split(ldflags['debug'])) + + # Optimized binary + if 'opt' in needed_envs: + makeEnv(env, 'opt', '.o', + CCFLAGS = Split(ccflags['opt']), + CPPDEFINES = ['TRACING_ON=1'], + LINKFLAGS = Split(ldflags['opt'])) + + # "Fast" binary + if 'fast' in needed_envs: + makeEnv(env, 'fast', '.fo', strip = True, + CCFLAGS = Split(ccflags['fast']), + CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], + LINKFLAGS = Split(ldflags['fast'])) + + # Profiled binary using gprof + if 'prof' in needed_envs: + makeEnv(env, 'prof', '.po', + CCFLAGS = Split(ccflags['prof']), + CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], + LINKFLAGS = Split(ldflags['prof'])) + + # Profiled binary using google-pprof + if 'perf' in needed_envs: + makeEnv(env, 'perf', '.gpo', + CCFLAGS = Split(ccflags['perf']), + CPPDEFINES = ['NDEBUG', 'TRACING_ON=0'], + LINKFLAGS = Split(ldflags['perf'])) + +# The MakeEnvirons Builder defers the full dependency collection until +# after processing the ISA definition (due to dynamically generated +# source files). Add this dependency to all targets so they will wait +# until the environments are completely set up. Otherwise, a second +# process (e.g. -j2 or higher) will try to compile the requested target, +# not know how, and fail. +env.Append(BUILDERS = {'MakeEnvirons' : + Builder(action=MakeAction(makeEnvirons, + Transform("ENVIRONS", 1)))}) + +isa_target = env['PHONY_BASE'] + '-deps' +environs = env['PHONY_BASE'] + '-environs' +env.Depends('#all-deps', isa_target) +env.Depends('#all-environs', environs) +env.ScanISA(isa_target, File('arch/%s/generated/inc.d' % env['TARGET_ISA'])) +envSetup = env.MakeEnvirons(environs, isa_target) + +# make sure no -deps targets occur before all ISAs are complete +env.Depends(isa_target, '#all-isas') +# likewise for -environs targets and all the -deps targets +env.Depends(environs, '#all-deps')