scons: Move the source related helper classes out of src/SConscript.
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>
This commit is contained in:
@@ -130,6 +130,7 @@ from gem5_scons import error, warning, summarize_warnings, parse_build_path
|
||||
from gem5_scons import TempFileSpawn, EnvDefaults, MakeAction, MakeActionTool
|
||||
import gem5_scons
|
||||
from gem5_scons.builders import ConfigFile, AddLocalRPATH, SwitchingHeaders
|
||||
from gem5_scons.sources import TagImpliesTool
|
||||
from gem5_scons.util import compareVersions, readCommand
|
||||
|
||||
# Disable warnings when targets can be built with multiple environments but
|
||||
@@ -149,7 +150,7 @@ Export('MakeAction')
|
||||
|
||||
main = Environment(tools=[
|
||||
'default', 'git', TempFileSpawn, EnvDefaults, MakeActionTool,
|
||||
ConfigFile, AddLocalRPATH, SwitchingHeaders
|
||||
ConfigFile, AddLocalRPATH, SwitchingHeaders, TagImpliesTool
|
||||
])
|
||||
|
||||
main.Tool(SCons.Tool.FindTool(['gcc', 'clang'], main))
|
||||
|
||||
239
site_scons/gem5_scons/sources.py
Normal file
239
site_scons/gem5_scons/sources.py
Normal file
@@ -0,0 +1,239 @@
|
||||
# -*- 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']
|
||||
198
src/SConscript
198
src/SConscript
@@ -41,7 +41,6 @@ import array
|
||||
import bisect
|
||||
import distutils.spawn
|
||||
import functools
|
||||
import imp
|
||||
import importlib
|
||||
import importlib.abc
|
||||
import importlib.machinery
|
||||
@@ -55,6 +54,9 @@ import zlib
|
||||
import SCons
|
||||
|
||||
from gem5_scons import Transform, warning, error, ToValue, FromValue
|
||||
from gem5_scons.sources import *
|
||||
|
||||
Export(SourceFilter.factories)
|
||||
|
||||
# This file defines how to build a particular configuration of gem5
|
||||
# based on variable settings in the 'env' build environment.
|
||||
@@ -68,200 +70,6 @@ build_env = [(opt, env[opt]) for opt in export_vars]
|
||||
|
||||
from m5.util import code_formatter
|
||||
|
||||
########################################################################
|
||||
# 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]
|
||||
|
||||
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,
|
||||
})
|
||||
|
||||
Export(SourceFilter.factories)
|
||||
|
||||
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 = 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)
|
||||
|
||||
def bytesToCppArray(code, symbol, data):
|
||||
'''
|
||||
Output an array of bytes to a code formatter as a c++ array declaration.
|
||||
|
||||
Reference in New Issue
Block a user