+from m5.util import code_formatter, compareVersions
+
+########################################################################
+# Code for adding source files of various types
+#
+# When specifying a source file of some type, a set of guards can be
+# specified for that file. When get() is used to find the files, if
+# get specifies a set of filters, only files that match those filters
+# will be accepted (unspecified filters on files are assumed to be
+# false). Current filters are:
+# main -- specifies the gem5 main() function
+# skip_lib -- do not put this file into the gem5 library
+# <unittest> -- 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).
+#
+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
+ of a certain type that match a set of guards'''
+ 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
+
+class SourceFile(object):
+ '''Base object that encapsulates the notion of a source file.
+ This includes, the source node, target node, various manipulations
+ of those. A source file also specifies a set of guards which
+ describing which builds the source file applies to. A parent can
+ also be specified to get default guards from'''
+ __metaclass__ = SourceMeta
+ def __init__(self, source, parent=None, **guards):
+ self.guards = guards
+ self.parent = parent
+
+ tnode = source
+ if not isinstance(source, SCons.Node.FS.File):
+ tnode = File(source)
+
+ self.tnode = tnode
+ self.snode = tnode.srcnode()
+
+ for base in type(self).__mro__:
+ if issubclass(base, SourceFile):
+ base.all.append(self)
+
+ @property
+ def filename(self):
+ return str(self.tnode)
+
+ @property
+ def dirname(self):
+ return dirname(self.filename)
+
+ @property
+ def basename(self):
+ return basename(self.filename)
+
+ @property
+ def extname(self):
+ index = self.basename.rfind('.')
+ if index <= 0:
+ # dot files aren't extensions
+ return self.basename, None
+
+ return self.basename[:index], self.basename[index+1:]
+
+ @property
+ def all_guards(self):
+ '''find all guards for this object getting default values
+ recursively from its parents'''
+ guards = {}
+ if self.parent:
+ guards.update(self.parent.guards)
+ guards.update(self.guards)
+ return guards
+
+ def __lt__(self, other): return self.filename < other.filename
+ def __le__(self, other): return self.filename <= other.filename
+ def __gt__(self, other): return self.filename > other.filename
+ 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
+
+class Source(SourceFile):
+ '''Add a c/c++ source file to the build'''
+ def __init__(self, source, Werror=True, swig=False, **guards):
+ '''specify the source file, and any guards'''
+ super(Source, self).__init__(source, **guards)
+
+ self.Werror = Werror
+ self.swig = swig