By having them in gem5_scons.sources, they can be used by mechanisms outside of src/SConscript, like separated out builders. Change-Id: Ic3769723c8413e7db48aef536572ad3f2f948658 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/48376 Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Hoa Nguyen <hoanguyen@ucdavis.edu>
240 lines
8.4 KiB
Python
240 lines
8.4 KiB
Python
# -*- mode:python -*-
|
|
|
|
# Copyright (c) 2018, 2020 ARM Limited
|
|
#
|
|
# The license below extends only to copyright in the software and shall
|
|
# not be construed as granting a license to any other intellectual
|
|
# property including but not limited to intellectual property relating
|
|
# to a hardware implementation of the functionality of the software
|
|
# licensed hereunder. You may use the software subject to the license
|
|
# terms below provided that you ensure that this notice is replicated
|
|
# unmodified and in its entirety in all distributions of the software,
|
|
# modified or unmodified, in source code or in binary form.
|
|
#
|
|
# Copyright (c) 2004-2005 The Regents of The University of Michigan
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are
|
|
# met: redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer;
|
|
# redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution;
|
|
# neither the name of the copyright holders nor the names of its
|
|
# contributors may be used to endorse or promote products derived from
|
|
# this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import functools
|
|
|
|
import SCons.Script
|
|
|
|
########################################################################
|
|
# Code for adding source files of various types
|
|
#
|
|
# When specifying a source file of some type, a set of tags can be
|
|
# specified for that file.
|
|
|
|
def tag_implies(env, tag, tag_list):
|
|
'''
|
|
Associates a tag X to a list of tags which are implied by X.
|
|
|
|
For example, assume:
|
|
- Each file <X>.cc is tagged with the tag "Tag <X>".
|
|
- B.cc refers to symbols from A.cc
|
|
- C.cc refers to symbols from B.cc
|
|
- D.cc refers to symbols from A.cc and C.cc
|
|
|
|
Then:
|
|
- "Tag A" is implied by "Tag B"
|
|
- "Tag B" is implied by "Tag C"
|
|
- "Tag A" is transitively implied by "Tag C" (from "Tag B")
|
|
- "Tag A" and "Tag C" are implied by "Tag D"
|
|
- "Tag B" is transitively implied by "Tag D" (from "Tag C")
|
|
- "Tag A" is transitively implied by "Tag D" (from transitive "Tag B")
|
|
|
|
All of these implications are simply declared as:
|
|
env.TagImplies("Tag B", "Tag A")
|
|
env.TagImplies("Tag C", "Tag B")
|
|
env.TagImplies("Tag D", ["Tag A", "Tag C"])
|
|
|
|
So that any use of a tag will automatically include its transitive tags
|
|
after being resolved.
|
|
'''
|
|
|
|
env.SetDefault(_tag_implies={})
|
|
implications = env['_tag_implies']
|
|
|
|
if isinstance(tag_list, str):
|
|
tag_list = frozenset([tag_list])
|
|
if not isinstance(tag_list, frozenset):
|
|
tag_list = frozenset(tag_list)
|
|
if tag in implications:
|
|
implications[tag] |= tag_list
|
|
else:
|
|
implications[tag] = tag_list
|
|
|
|
# Check if any of the tags on which the new tag depends on already
|
|
# has a list of implications. If so, add the list to the new tag's
|
|
# implications
|
|
for t in tag_list:
|
|
if t in implications:
|
|
implications[tag] |= implications[t]
|
|
|
|
# Check if another tag depends on this tag. If so, add this tag's
|
|
# implications to that tag.
|
|
for t,implied in implications.items():
|
|
if tag in implied:
|
|
implications[t] |= implications[tag]
|
|
|
|
def TagImpliesTool(env):
|
|
env.AddMethod(tag_implies, 'TagImplies')
|
|
|
|
def resolve_tags(env, tags):
|
|
'''
|
|
Returns the complete set of tags implied (dependencies) by the
|
|
supplied tags.
|
|
'''
|
|
|
|
implications = env.SetDefault(_tag_implies={})
|
|
implications = env['_tag_implies']
|
|
|
|
if isinstance(tags, str):
|
|
tags = frozenset([tags])
|
|
if not isinstance(tags, frozenset):
|
|
tags = frozenset(tags)
|
|
|
|
tags = tags.copy()
|
|
for tag in tags:
|
|
if tag in implications:
|
|
tags |= implications[tag]
|
|
return tags
|
|
|
|
class SourceFilter(object):
|
|
factories = {}
|
|
def __init__(self, predicate):
|
|
self.predicate = predicate
|
|
|
|
def __or__(self, other):
|
|
return SourceFilter(lambda env, tags: self.predicate(env, tags) or
|
|
other.predicate(env, tags))
|
|
|
|
def __and__(self, other):
|
|
return SourceFilter(lambda env, tags: self.predicate(env, tags) and
|
|
other.predicate(env, tags))
|
|
|
|
def with_any_tags(*tags):
|
|
'''Return a list of sources with any of the supplied tags.'''
|
|
return SourceFilter(lambda env, stags: \
|
|
len(resolve_tags(env, tags) & stags) > 0)
|
|
|
|
def with_all_tags(*tags):
|
|
'''Return a list of sources with all of the supplied tags.'''
|
|
return SourceFilter(lambda env, stags: resolve_tags(env, tags) <= stags)
|
|
|
|
def with_tag(tag):
|
|
'''Return a list of sources with the supplied tag.'''
|
|
return with_any_tags(*[tag])
|
|
|
|
def without_tags(*tags):
|
|
'''Return a list of sources without any of the supplied tags.'''
|
|
return SourceFilter(lambda env, stags: \
|
|
len(resolve_tags(env, tags) & stags) == 0)
|
|
|
|
def without_tag(tag):
|
|
'''Return a list of sources without the supplied tag.'''
|
|
return without_tags(*[tag])
|
|
|
|
SourceFilter.factories.update({
|
|
'with_any_tags': with_any_tags,
|
|
'with_all_tags': with_all_tags,
|
|
'with_tag': with_tag,
|
|
'without_tags': without_tags,
|
|
'without_tag': without_tag,
|
|
})
|
|
|
|
class SourceList(list):
|
|
def apply_filter(self, env, f):
|
|
def match(source):
|
|
return f.predicate(env, source.tags)
|
|
return SourceList(filter(match, self))
|
|
|
|
def __getattr__(self, name):
|
|
func = SourceFilter.factories.get(name, None)
|
|
if not func:
|
|
raise AttributeError
|
|
|
|
@functools.wraps(func)
|
|
def wrapper(env, *args, **kwargs):
|
|
return self.apply_filter(env, func(*args, **kwargs))
|
|
return wrapper
|
|
|
|
class SourceMeta(type):
|
|
'''Meta class for source files that keeps track of all files of a
|
|
particular type.'''
|
|
def __init__(cls, name, bases, dict):
|
|
super(SourceMeta, cls).__init__(name, bases, dict)
|
|
cls.all = SourceList()
|
|
|
|
class SourceFile(object, metaclass=SourceMeta):
|
|
'''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 tags which
|
|
describing arbitrary properties of the source file.'''
|
|
|
|
def __init__(self, source, tags=None, add_tags=None, append=None):
|
|
if tags is None:
|
|
tags='gem5 lib'
|
|
if isinstance(tags, str):
|
|
tags = { tags }
|
|
if not isinstance(tags, set):
|
|
tags = set(tags)
|
|
self.tags = tags
|
|
|
|
if add_tags:
|
|
if isinstance(add_tags, str):
|
|
add_tags = { add_tags }
|
|
if not isinstance(add_tags, set):
|
|
add_tags = set(add_tags)
|
|
self.tags |= add_tags
|
|
|
|
self.append = append
|
|
|
|
tnode = SCons.Script.File(source)
|
|
|
|
self.tnode = tnode
|
|
self.filename = str(self.tnode)
|
|
self.snode = tnode.srcnode()
|
|
|
|
for base in type(self).__mro__:
|
|
if issubclass(base, SourceFile):
|
|
base.all.append(self)
|
|
|
|
def static(self, env):
|
|
if self.append:
|
|
env = env.Clone()
|
|
env.Append(**self.append)
|
|
return env.StaticObject(self.tnode)
|
|
|
|
def shared(self, env):
|
|
if self.append:
|
|
env = env.Clone()
|
|
env.Append(**self.append)
|
|
return env.SharedObject(self.tnode)
|
|
|
|
__all__ = ['TagImpliesTool', 'SourceFilter', 'SourceList', 'SourceFile',
|
|
'with_any_tags', 'with_all_tags', 'with_tag', 'without_tags',
|
|
'without_tag']
|