scons: Move Transform and termcap functionality into their own files.

Change-Id: Ica08e93f3873a7eafd02fe7d44c3bdbf0ce7f6b7
Reviewed-on: https://gem5-review.googlesource.com/5565
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
diff --git a/SConstruct b/SConstruct
index 9816c86..095b58b 100755
--- a/SConstruct
+++ b/SConstruct
@@ -96,7 +96,6 @@
 import SCons.Node
 
 from m5.util import compareVersions, readCommand
-from m5.util.terminal import get_termcap
 
 help_texts = {
     "options" : "",
@@ -168,8 +167,6 @@
     print '--no-lto and --force-lto are mutually exclusive'
     Exit(1)
 
-termcap = get_termcap(GetOption('use_colors'))
-
 ########################################################################
 #
 # Set up the main build environment.
@@ -178,6 +175,10 @@
 
 main = Environment()
 
+from gem5_scons import Transform
+from gem5_scons.util import get_termcap
+termcap = get_termcap()
+
 main_dict_keys = main.Dictionary().keys()
 
 # Check that we have a C/C++ compiler
@@ -301,90 +302,6 @@
 # Add shared top-level headers
 main.Prepend(CPPPATH=Dir('include'))
 
-def strip_build_path(path, env):
-    path = str(path)
-    variant_base = env['BUILDROOT'] + os.path.sep
-    if path.startswith(variant_base):
-        path = path[len(variant_base):]
-    elif path.startswith('build/'):
-        path = path[6:]
-    return path
-
-# Generate a string of the form:
-#   common/path/prefix/src1, src2 -> tgt1, tgt2
-# to print while building.
-class Transform(object):
-    # all specific color settings should be here and nowhere else
-    tool_color = termcap.Normal
-    pfx_color = termcap.Yellow
-    srcs_color = termcap.Yellow + termcap.Bold
-    arrow_color = termcap.Blue + termcap.Bold
-    tgts_color = termcap.Yellow + termcap.Bold
-
-    def __init__(self, tool, max_sources=99):
-        self.format = self.tool_color + (" [%8s] " % tool) \
-                      + self.pfx_color + "%s" \
-                      + self.srcs_color + "%s" \
-                      + self.arrow_color + " -> " \
-                      + self.tgts_color + "%s" \
-                      + termcap.Normal
-        self.max_sources = max_sources
-
-    def __call__(self, target, source, env, for_signature=None):
-        # truncate source list according to max_sources param
-        source = source[0:self.max_sources]
-        def strip(f):
-            return strip_build_path(str(f), env)
-        if len(source) > 0:
-            srcs = map(strip, source)
-        else:
-            srcs = ['']
-        tgts = map(strip, target)
-        # surprisingly, os.path.commonprefix is a dumb char-by-char string
-        # operation that has nothing to do with paths.
-        com_pfx = os.path.commonprefix(srcs + tgts)
-        com_pfx_len = len(com_pfx)
-        if com_pfx:
-            # do some cleanup and sanity checking on common prefix
-            if com_pfx[-1] == ".":
-                # prefix matches all but file extension: ok
-                # back up one to change 'foo.cc -> o' to 'foo.cc -> .o'
-                com_pfx = com_pfx[0:-1]
-            elif com_pfx[-1] == "/":
-                # common prefix is directory path: OK
-                pass
-            else:
-                src0_len = len(srcs[0])
-                tgt0_len = len(tgts[0])
-                if src0_len == com_pfx_len:
-                    # source is a substring of target, OK
-                    pass
-                elif tgt0_len == com_pfx_len:
-                    # target is a substring of source, need to back up to
-                    # avoid empty string on RHS of arrow
-                    sep_idx = com_pfx.rfind(".")
-                    if sep_idx != -1:
-                        com_pfx = com_pfx[0:sep_idx]
-                    else:
-                        com_pfx = ''
-                elif src0_len > com_pfx_len and srcs[0][com_pfx_len] == ".":
-                    # still splitting at file extension: ok
-                    pass
-                else:
-                    # probably a fluke; ignore it
-                    com_pfx = ''
-        # recalculate length in case com_pfx was modified
-        com_pfx_len = len(com_pfx)
-        def fmt(files):
-            f = map(lambda s: s[com_pfx_len:], files)
-            return ', '.join(f)
-        return self.format % (com_pfx, fmt(srcs), fmt(tgts))
-
-Export('Transform')
-
-# enable the regression script to use the termcap
-main['TERMCAP'] = termcap
-
 if GetOption('verbose'):
     def MakeAction(action, string, *args, **kwargs):
         return Action(action, *args, **kwargs)
diff --git a/site_scons/gem5_scons/__init__.py b/site_scons/gem5_scons/__init__.py
index e69de29..0521862 100644
--- a/site_scons/gem5_scons/__init__.py
+++ b/site_scons/gem5_scons/__init__.py
@@ -0,0 +1,127 @@
+# Copyright (c) 2013, 2015-2017 ARM Limited
+# All rights reserved.
+#
+# 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) 2011 Advanced Micro Devices, Inc.
+# Copyright (c) 2009 The Hewlett-Packard Development Company
+# 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 os
+
+from gem5_scons.util import get_termcap
+
+termcap = get_termcap()
+
+def strip_build_path(path, env):
+    path = str(path)
+    build_base = 'build/'
+    variant_base = env['BUILDROOT'] + os.path.sep
+    if path.startswith(variant_base):
+        path = path[len(variant_base):]
+    elif path.startswith(build_base):
+        path = path[len(build_base):]
+    return path
+
+# Generate a string of the form:
+#   common/path/prefix/src1, src2 -> tgt1, tgt2
+# to print while building.
+class Transform(object):
+    # all specific color settings should be here and nowhere else
+    tool_color = termcap.Normal
+    pfx_color = termcap.Yellow
+    srcs_color = termcap.Yellow + termcap.Bold
+    arrow_color = termcap.Blue + termcap.Bold
+    tgts_color = termcap.Yellow + termcap.Bold
+
+    def __init__(self, tool, max_sources=99):
+        self.format = self.tool_color + (" [%8s] " % tool) \
+                      + self.pfx_color + "%s" \
+                      + self.srcs_color + "%s" \
+                      + self.arrow_color + " -> " \
+                      + self.tgts_color + "%s" \
+                      + termcap.Normal
+        self.max_sources = max_sources
+
+    def __call__(self, target, source, env, for_signature=None):
+        # truncate source list according to max_sources param
+        source = source[0:self.max_sources]
+        def strip(f):
+            return strip_build_path(str(f), env)
+        if len(source) > 0:
+            srcs = map(strip, source)
+        else:
+            srcs = ['']
+        tgts = map(strip, target)
+        # surprisingly, os.path.commonprefix is a dumb char-by-char string
+        # operation that has nothing to do with paths.
+        com_pfx = os.path.commonprefix(srcs + tgts)
+        com_pfx_len = len(com_pfx)
+        if com_pfx:
+            # do some cleanup and sanity checking on common prefix
+            if com_pfx[-1] == ".":
+                # prefix matches all but file extension: ok
+                # back up one to change 'foo.cc -> o' to 'foo.cc -> .o'
+                com_pfx = com_pfx[0:-1]
+            elif com_pfx[-1] == "/":
+                # common prefix is directory path: OK
+                pass
+            else:
+                src0_len = len(srcs[0])
+                tgt0_len = len(tgts[0])
+                if src0_len == com_pfx_len:
+                    # source is a substring of target, OK
+                    pass
+                elif tgt0_len == com_pfx_len:
+                    # target is a substring of source, need to back up to
+                    # avoid empty string on RHS of arrow
+                    sep_idx = com_pfx.rfind(".")
+                    if sep_idx != -1:
+                        com_pfx = com_pfx[0:sep_idx]
+                    else:
+                        com_pfx = ''
+                elif src0_len > com_pfx_len and srcs[0][com_pfx_len] == ".":
+                    # still splitting at file extension: ok
+                    pass
+                else:
+                    # probably a fluke; ignore it
+                    com_pfx = ''
+        # recalculate length in case com_pfx was modified
+        com_pfx_len = len(com_pfx)
+        def fmt(files):
+            f = map(lambda s: s[com_pfx_len:], files)
+            return ', '.join(f)
+        return self.format % (com_pfx, fmt(srcs), fmt(tgts))
+
+__all__ = ['Transform']
diff --git a/site_scons/gem5_scons/util.py b/site_scons/gem5_scons/util.py
index 4781cc5..1a196c2 100644
--- a/site_scons/gem5_scons/util.py
+++ b/site_scons/gem5_scons/util.py
@@ -42,6 +42,11 @@
 
 import SCons.Script
 
+import m5.util.terminal
+
 def ignore_style():
     """Determine whether we should ignore style checks"""
     return SCons.Script.GetOption('ignore_style') or not sys.stdin.isatty()
+
+def get_termcap():
+    return m5.util.terminal.get_termcap(SCons.Script.GetOption('use_colors'))
diff --git a/src/SConscript b/src/SConscript
index 76bf8d1..6c3f220 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -42,6 +42,8 @@
 
 import SCons
 
+from gem5_scons import Transform
+
 # This file defines how to build a particular configuration of gem5
 # based on variable settings in the 'env' build environment.
 
diff --git a/src/arch/SConscript b/src/arch/SConscript
index 1030be7..728377d 100644
--- a/src/arch/SConscript
+++ b/src/arch/SConscript
@@ -44,6 +44,8 @@
 import os
 import re
 
+from gem5_scons import Transform
+
 Import('*')
 
 #################################################################
diff --git a/src/mem/protocol/SConscript b/src/mem/protocol/SConscript
index 0eccdf3..e66c6b3 100644
--- a/src/mem/protocol/SConscript
+++ b/src/mem/protocol/SConscript
@@ -36,6 +36,8 @@
 
 from SCons.Scanner import Classic
 
+from gem5_scons import Transform
+
 Import('*')
 
 if env['PROTOCOL'] == 'None':
diff --git a/src/mem/ruby/SConscript b/src/mem/ruby/SConscript
index 88edb44..5cae880 100644
--- a/src/mem/ruby/SConscript
+++ b/src/mem/ruby/SConscript
@@ -35,6 +35,8 @@
 
 import SCons
 
+from gem5_scons import Transform
+
 Import('*')
 
 DebugFlag('ProtocolTrace')
diff --git a/tests/SConscript b/tests/SConscript
index d1fee7a..3ed3e24 100644
--- a/tests/SConscript
+++ b/tests/SConscript
@@ -50,11 +50,12 @@
 sys.path.insert(0, Dir(".").srcnode().abspath)
 import testing.tests as tests
 import testing.results as results
+from gem5_scons.util import get_termcap
 
 Import('env')
 
 # get the termcap from the environment
-termcap = env['TERMCAP']
+termcap = get_termcap()
 
 # Dict that accumulates lists of tests by category (quick, medium, long)
 env.Tests = {}