1# Copyright (c) 2013, 2015-2017 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder.  You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Copyright (c) 2011 Advanced Micro Devices, Inc.
14# Copyright (c) 2009 The Hewlett-Packard Development Company
15# Copyright (c) 2004-2005 The Regents of The University of Michigan
16# All rights reserved.
17#
18# Redistribution and use in source and binary forms, with or without
19# modification, are permitted provided that the following conditions are
20# met: redistributions of source code must retain the above copyright
21# notice, this list of conditions and the following disclaimer;
22# redistributions in binary form must reproduce the above copyright
23# notice, this list of conditions and the following disclaimer in the
24# documentation and/or other materials provided with the distribution;
25# neither the name of the copyright holders nor the names of its
26# contributors may be used to endorse or promote products derived from
27# this software without specific prior written permission.
28#
29# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
41import os
42
43from gem5_scons.util import get_termcap
44
45termcap = get_termcap()
46
47def strip_build_path(path, env):
48    path = str(path)
49    build_base = 'build/'
50    variant_base = env['BUILDROOT'] + os.path.sep
51    if path.startswith(variant_base):
52        path = path[len(variant_base):]
53    elif path.startswith(build_base):
54        path = path[len(build_base):]
55    return path
56
57# Generate a string of the form:
58#   common/path/prefix/src1, src2 -> tgt1, tgt2
59# to print while building.
60class Transform(object):
61    # all specific color settings should be here and nowhere else
62    tool_color = termcap.Normal
63    pfx_color = termcap.Yellow
64    srcs_color = termcap.Yellow + termcap.Bold
65    arrow_color = termcap.Blue + termcap.Bold
66    tgts_color = termcap.Yellow + termcap.Bold
67
68    def __init__(self, tool, max_sources=99):
69        self.format = self.tool_color + (" [%8s] " % tool) \
70                      + self.pfx_color + "%s" \
71                      + self.srcs_color + "%s" \
72                      + self.arrow_color + " -> " \
73                      + self.tgts_color + "%s" \
74                      + termcap.Normal
75        self.max_sources = max_sources
76
77    def __call__(self, target, source, env, for_signature=None):
78        # truncate source list according to max_sources param
79        source = source[0:self.max_sources]
80        def strip(f):
81            return strip_build_path(str(f), env)
82        if len(source) > 0:
83            srcs = map(strip, source)
84        else:
85            srcs = ['']
86        tgts = map(strip, target)
87        # surprisingly, os.path.commonprefix is a dumb char-by-char string
88        # operation that has nothing to do with paths.
89        com_pfx = os.path.commonprefix(srcs + tgts)
90        com_pfx_len = len(com_pfx)
91        if com_pfx:
92            # do some cleanup and sanity checking on common prefix
93            if com_pfx[-1] == ".":
94                # prefix matches all but file extension: ok
95                # back up one to change 'foo.cc -> o' to 'foo.cc -> .o'
96                com_pfx = com_pfx[0:-1]
97            elif com_pfx[-1] == "/":
98                # common prefix is directory path: OK
99                pass
100            else:
101                src0_len = len(srcs[0])
102                tgt0_len = len(tgts[0])
103                if src0_len == com_pfx_len:
104                    # source is a substring of target, OK
105                    pass
106                elif tgt0_len == com_pfx_len:
107                    # target is a substring of source, need to back up to
108                    # avoid empty string on RHS of arrow
109                    sep_idx = com_pfx.rfind(".")
110                    if sep_idx != -1:
111                        com_pfx = com_pfx[0:sep_idx]
112                    else:
113                        com_pfx = ''
114                elif src0_len > com_pfx_len and srcs[0][com_pfx_len] == ".":
115                    # still splitting at file extension: ok
116                    pass
117                else:
118                    # probably a fluke; ignore it
119                    com_pfx = ''
120        # recalculate length in case com_pfx was modified
121        com_pfx_len = len(com_pfx)
122        def fmt(files):
123            f = map(lambda s: s[com_pfx_len:], files)
124            return ', '.join(f)
125        return self.format % (com_pfx, fmt(srcs), fmt(tgts))
126
127__all__ = ['Transform']
128